diff --git a/src/quo2/components/notifications/activity_log/style.cljs b/src/quo2/components/notifications/activity_log/style.cljs index 292eed955d..4d184d8ced 100644 --- a/src/quo2/components/notifications/activity_log/style.cljs +++ b/src/quo2/components/notifications/activity_log/style.cljs @@ -33,25 +33,16 @@ :padding-vertical 8 :background-color colors/white-opa-5}) -(def buttons-container +(def footer-container {:margin-top 12 - :flex-direction :row - :align-items :flex-start}) - -(def status - {:margin-top 12 - :align-items :flex-start - :flex 1}) + :flex-direction :row}) (defn title - [replying?] - {:color colors/white - :flex-shrink 1 - :max-width (when-not replying? "60%")}) + [] + {:color colors/white}) (def timestamp {:text-transform :none - :flex-grow 1 :margin-left 8 :color colors/neutral-40}) @@ -75,3 +66,8 @@ (def top-section-container {:align-items :center :flex-direction :row}) + +(def title-container + {:flex 1 + :flex-direction :row + :align-items :center}) diff --git a/src/quo2/components/notifications/activity_log/view.cljs b/src/quo2/components/notifications/activity_log/view.cljs index 5fd585e0a0..249f2276d7 100644 --- a/src/quo2/components/notifications/activity_log/view.cljs +++ b/src/quo2/components/notifications/activity_log/view.cljs @@ -11,15 +11,8 @@ [reagent.core :as reagent] [utils.i18n :as i18n])) -(def ^:private max-reply-length - 280) - -(defn- valid-reply? - [reply] - (<= (count reply) max-reply-length)) - (defn- activity-reply-text-input - [reply-input on-update-reply] + [{:keys [on-update-reply max-reply-length valid-reply?]} reply-input] [rn/view [rn/view {:style {:margin-top 16 @@ -99,44 +92,12 @@ body] body)]) -(defn- activity-buttons - [button-1 button-2 replying? reply-input] - (let [size (if replying? 40 24) - common-style (when replying? - {:padding-vertical 9 - :flex-grow 1 - :flex-basis 0})] - [rn/view style/buttons-container - (when button-1 - [button/button - (-> button-1 - (assoc :size size) - (update :style merge common-style {:margin-right 8})) - (:label button-1)]) - (when button-2 - [button/button - (-> button-2 - (assoc :size size) - (assoc :disabled (and replying? (not (valid-reply? @reply-input)))) - (update :style merge common-style)) - (:label button-2)])])) - -(defn- activity-status - [status] - [rn/view - {:style style/status - :accessibility-label :activity-status} - [status-tags/status-tag - {:size :small - :label (:label status) - :status status}]]) - (defn- activity-title [title replying?] [text/text {:weight :semi-bold :accessibility-label :activity-title - :style (style/title replying?) + :style (style/title) :size (if replying? :heading-2 :paragraph-1)} title]) @@ -155,18 +116,42 @@ :style style/unread-dot-container} [rn/view {:style style/unread-dot}]]) +(defmulti footer-item-view (fn [item _ _] (:type item))) + +(defmethod footer-item-view :button + [{:keys [label subtype disable-when] :as button} replying? reply-input] + (let [size (if replying? 40 24) + common-style (when replying? + {:padding-vertical 9 + :flex-grow 1 + :flex-basis 0})] + [button/button + (-> button + (assoc :size size) + (assoc :type subtype) + (assoc :disabled (and replying? (disable-when @reply-input))) + (update :style merge common-style {:margin-right 8})) + label])) + +(defmethod footer-item-view :status + [{:keys [label subtype]} _ _] + [status-tags/status-tag + {:size :small + :label label + :status {:type subtype}}]) + (defn- footer - [_] + [_ _] (let [reply-input (reagent/atom "")] - (fn [{:keys [replying? on-update-reply status button-1 button-2]}] + (fn [{:keys [replying? items] :as props}] [:<> (when replying? - [activity-reply-text-input reply-input on-update-reply]) - (cond (some? status) - [activity-status status] - - (or button-1 button-2) - [activity-buttons button-1 button-2 replying? reply-input])]))) + [activity-reply-text-input props reply-input]) + (when items + [rn/view style/footer-container + (for [{:keys [key] :as item} items] + ^{:key key} + [footer-item-view item replying? reply-input])])]))) (defn view [{:keys [icon @@ -187,9 +172,10 @@ :flex 1}} [rn/view [rn/view {:style style/top-section-container} - [activity-title title replying?] - (when-not replying? - [activity-timestamp timestamp]) + [rn/view {:style style/title-container} + [activity-title title replying?] + (when-not replying? + [activity-timestamp timestamp])] (when (and unread? (not replying?)) [activity-unread-dot])] (when context diff --git a/src/quo2/components/notifications/toast.cljs b/src/quo2/components/notifications/toast.cljs index 9c94f96084..43266def85 100644 --- a/src/quo2/components/notifications/toast.cljs +++ b/src/quo2/components/notifications/toast.cljs @@ -10,6 +10,8 @@ (def ^:private themes {:container {:dark {:background-color colors/white-opa-70} :light {:background-color colors/neutral-80-opa-90}} + :title {:dark {:color colors/neutral-100} + :light {:color colors/white}} :text {:dark {:color colors/neutral-100} :light {:color colors/white}} :icon {:dark {:color colors/neutral-100} @@ -51,7 +53,7 @@ [i18n/label :t/undo]]]) (defn- toast-container - [{:keys [left middle right container-style override-theme]}] + [{:keys [left title text right container-style override-theme]}] [rn/view {:style (merge {:padding-left 12 :padding-right 12} container-style)} [rn/view {:style (merge-theme-style :container @@ -66,16 +68,25 @@ override-theme)} [rn/view {:style {:padding 2}} left] [rn/view {:style {:padding 4 :flex 1}} - [text/text - {:size :paragraph-2 - :weight :medium - :style (merge-theme-style :text {} override-theme) - :accessibility-label :toast-content} - middle]] + (when title + [text/text + {:size :paragraph-1 + :weight :semi-bold + :style (merge-theme-style :title {} override-theme) + :accessibility-label :toast-title} + title]) + (when text + [text/text + {:size :paragraph-2 + :weight :medium + :style (merge-theme-style :text {} override-theme) + :accessibility-label :toast-content} + text])] (when right right)]]) (defn toast - [{:keys [icon icon-color text action undo-duration undo-on-press container-style override-theme]}] + [{:keys [icon icon-color title text action undo-duration undo-on-press container-style + override-theme]}] [toast-container {:left (when icon [icon/icon icon @@ -84,7 +95,8 @@ (get-in themes [:icon (or override-theme (theme/get-theme)) :color]))}]) - :middle text + :title title + :text text :right (if undo-duration [toast-undo-action undo-duration undo-on-press override-theme] action) diff --git a/src/quo2/components/tags/status_tags.cljs b/src/quo2/components/tags/status_tags.cljs index e2a7b67b87..2d9f525a5e 100644 --- a/src/quo2/components/tags/status_tags.cljs +++ b/src/quo2/components/tags/status_tags.cljs @@ -12,7 +12,7 @@ (def small-container-style (merge default-container-style {:padding-horizontal 8 - :padding-vertical 3})) + :padding-vertical 1})) (def large-container-style (merge default-container-style @@ -56,8 +56,8 @@ [size theme label] [base-tag {:size size - :background-color colors/success-50-opa-10 :icon :verified + :background-color colors/success-50-opa-10 :border-color colors/success-50-opa-20 :label label :text-color (if (= theme :light) @@ -77,18 +77,14 @@ colors/danger-60)}]) (defn- pending - [size theme label] + [size _ label] [base-tag {:size size :icon :pending :label label - :background-color (if (= theme :light) - colors/neutral-10 - colors/neutral-80) - :border-color (if (= theme :light) - colors/neutral-20 - colors/neutral-70) - :text-color colors/neutral-50}]) + :background-color colors/white-opa-5 + :border-color colors/white-opa-5 + :text-color colors/white-opa-70}]) (defn status-tag [{:keys [status size override-theme label]}] diff --git a/src/status_im/contact/core.cljs b/src/status_im/contact/core.cljs index 573b5d34b9..97e76e19aa 100644 --- a/src/status_im/contact/core.cljs +++ b/src/status_im/contact/core.cljs @@ -8,19 +8,6 @@ [status-im2.navigation.events :as navigation] [taoensso.timbre :as log])) -(rf/defn load-contacts - {:events [::contacts-loaded]} - [{:keys [db] :as cofx} all-contacts] - (let [contacts-list (map #(vector (:public-key %) - (if (empty? (:address %)) - (dissoc % :address) - %)) - all-contacts) - contacts (into {} contacts-list)] - {:db (cond-> (-> db - (update :contacts/contacts #(merge contacts %)) - (assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts))))})) - (defn build-contact [{{:keys [multiaccount] :contacts/keys [contacts]} @@ -66,7 +53,7 @@ (rf/defn add-contact "Add a contact and set pending to false" - {:events [:contact.ui/add-to-contact-pressed]} + {:events [:contact.ui/add-contact-pressed]} [{:keys [db] :as cofx} public-key nickname ens-name] (when (not= (get-in db [:multiaccount :public-key]) public-key) (contacts-store/add @@ -87,26 +74,10 @@ (assoc-in [:contacts/contacts public-key :contact-request-state] constants/contact-request-state-none)) :json-rpc/call [{:method "wakuext_retractContactRequest" - :params [{:contactId public-key}] + :params [{:id public-key}] :on-success #(log/debug "contact removed successfully")}] :dispatch [:chat/offload-messages constants/timeline-chat-id]}) -(rf/defn accept-contact-request - {:events [:contact-requests.ui/accept-request]} - [{:keys [db]} id] - {:json-rpc/call [{:method "wakuext_acceptContactRequest" - :params [{:id id}] - :js-response true - :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}) - -(rf/defn decline-contact-request - {:events [:contact-requests.ui/decline-request]} - [{:keys [db]} id] - {:json-rpc/call [{:method "wakuext_dismissContactRequest" - :params [{:id id}] - :js-response true - :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}) - (rf/defn initialize-contacts [cofx] (contacts-store/fetch-contacts-rpc cofx #(re-frame/dispatch [::contacts-loaded %]))) diff --git a/src/status_im/multiaccounts/login/core.cljs b/src/status_im/multiaccounts/login/core.cljs index 668f3b43a5..7254095535 100644 --- a/src/status_im/multiaccounts/login/core.cljs +++ b/src/status_im/multiaccounts/login/core.cljs @@ -4,7 +4,6 @@ [re-frame.core :as re-frame] [status-im.async-storage.core :as async-storage] [status-im.communities.core :as communities] - [status-im.contact.core :as contact] [status-im.data-store.chats :as data-store.chats] [status-im.data-store.invitations :as data-store.invitations] [status-im.data-store.settings :as data-store.settings] @@ -41,6 +40,7 @@ [status-im2.common.json-rpc.events :as json-rpc] [status-im2.contexts.activity-center.events :as activity-center] [status-im2.contexts.chat.messages.link-preview.events :as link-preview] + [status-im2.contexts.contacts.events :as contacts] [status-im2.navigation.events :as navigation] [status-im2.common.log :as logging] [taoensso.timbre :as log] @@ -468,7 +468,7 @@ (transport/start-messenger) (initialize-transactions-management-enabled) (check-network-version network-id) - (contact/initialize-contacts) + (contacts/initialize-contacts) (initialize-browser) (mobile-network/on-network-status-change) (get-group-chat-invitations) diff --git a/src/status_im/transport/message/core.cljs b/src/status_im/transport/message/core.cljs index 4bb266c497..f6d0a2e8a4 100644 --- a/src/status_im/transport/message/core.cljs +++ b/src/status_im/transport/message/core.cljs @@ -67,13 +67,13 @@ (models.message/receive-many cofx response-js) (seq activity-notifications) - (do + (let [notifications (->> activity-notifications + types/js->clj + (map data-store.activities/<-rpc))] (js-delete response-js "activityCenterNotifications") (rf/merge cofx - (->> activity-notifications - types/js->clj - (map data-store.activities/<-rpc) - activity-center/notifications-reconcile) + (activity-center/notifications-reconcile notifications) + (activity-center/show-toasts notifications) (process-next response-js sync-handler))) (seq installations) diff --git a/src/status_im/ui/screens/profile/contact/views.cljs b/src/status_im/ui/screens/profile/contact/views.cljs index 1ee5977cb0..232907f173 100644 --- a/src/status_im/ui/screens/profile/contact/views.cljs +++ b/src/status_im/ui/screens/profile/contact/views.cljs @@ -35,7 +35,7 @@ :disabled blocked? :accessibility-label :add-to-contacts-button :action (when-not blocked? - #(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key + #(re-frame/dispatch [:contact.ui/add-contact-pressed public-key nil ens-name]))}]) [{:label (i18n/label (if (or muted? blocked?) :t/unmute :t/mute)) :icon :main-icons/notification diff --git a/src/status_im2/contexts/activity_center/events.cljs b/src/status_im2/contexts/activity_center/events.cljs index 134626eb60..cc8f11e366 100644 --- a/src/status_im2/contexts/activity_center/events.cljs +++ b/src/status_im2/contexts/activity_center/events.cljs @@ -3,8 +3,12 @@ [status-im.data-store.chats :as data-store.chats] [status-im2.contexts.activity-center.notification-types :as types] [status-im2.contexts.chat.events :as chat.events] + [status-im2.common.toasts.events :as toasts] + status-im2.contexts.activity-center.notification.contact-requests.events [taoensso.timbre :as log] [utils.re-frame :as rf] + [utils.i18n :as i18n] + [quo2.foundations.colors :as colors] [status-im2.constants :as constants])) (def defaults @@ -93,6 +97,38 @@ new-notifications) :dispatch [:activity-center.notifications/fetch-unread-count]})) +(rf/defn show-toasts + {:events [:activity-center.notifications/show-toasts]} + [{:keys [db]} new-notifications] + (let [my-public-key (get-in db [:multiaccount :public-key])] + (reduce (fn [cofx {:keys [author type accepted dismissed message name] :as x}] + (cond + (and (not= author my-public-key) + (= type types/contact-request) + (not accepted) + (not dismissed)) + (toasts/upsert cofx + {:icon :placeholder + :icon-color colors/primary-50-opa-40 + :title (i18n/label :t/contact-request-sent-toast + {:name name}) + :text (get-in message [:content :text])}) + + (and (= author my-public-key) ;; we show it for user who sent the request + (= type types/contact-request) + accepted + (not dismissed)) + (toasts/upsert cofx + {:icon :placeholder + :icon-color colors/primary-50-opa-40 + :title (i18n/label :t/contact-request-accepted-toast + {:name (:alias message)})}) + + :else + cofx)) + {:db db} + new-notifications))) + (rf/defn notifications-reconcile-from-response {:events [:activity-center/reconcile-notifications-from-response]} [cofx response] diff --git a/src/status_im2/contexts/activity_center/notification/admin/view.cljs b/src/status_im2/contexts/activity_center/notification/admin/view.cljs index 92551e328d..d935b15aa3 100644 --- a/src/status_im2/contexts/activity_center/notification/admin/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/admin/view.cljs @@ -14,38 +14,48 @@ community-name (:name community) community-image (get-in community [:images :thumbnail :uri])] [quo/activity-log - (merge - {:title (i18n/label :t/join-request) - :icon :i/add-user - :timestamp (datetime/timestamp->relative timestamp) - :unread? (not read) - :context [[common/user-avatar-tag author] - (i18n/label :t/wants-to-join) - [quo/context-tag - {:size :small - :override-theme :dark - :color colors/primary-50 - :style style/user-avatar-tag - :text-style style/user-avatar-tag-text} - {:uri community-image} community-name]] - :status (case membership-status - constants/activity-center-membership-status-accepted - {:type :positive :label (i18n/label :t/accepted)} - constants/activity-center-membership-status-declined - {:type :negative :label (i18n/label :t/declined)} - nil)} - (case membership-status - constants/activity-center-membership-status-pending - {:button-1 {:label (i18n/label :t/decline) - :accessibility-label :decline-join-request - :type :danger - :on-press (fn [] - (rf/dispatch [:communities.ui/decline-request-to-join-pressed - community-id id]))} - :button-2 {:label (i18n/label :t/accept) - :accessibility-label :accept-join-request - :type :positive - :on-press (fn [] - (rf/dispatch [:communities.ui/accept-request-to-join-pressed - community-id id]))}} - nil))])) + {:title (i18n/label :t/join-request) + :icon :i/add-user + :timestamp (datetime/timestamp->relative timestamp) + :unread? (not read) + :context [[common/user-avatar-tag author] + (i18n/label :t/wants-to-join) + [quo/context-tag + {:size :small + :override-theme :dark + :color colors/primary-50 + :style style/user-avatar-tag + :text-style style/user-avatar-tag-text} + {:uri community-image} community-name]] + :items (case membership-status + constants/activity-center-membership-status-accepted + [{:type :status + :subtype :positive + :key :status-accepted + :label (i18n/label :t/accepted)}] + + constants/activity-center-membership-status-declined + [{:type :status + :subtype :negative + :key :status-declined + :label (i18n/label :t/declined)}] + + constants/activity-center-membership-status-pending + [{:type :button + :subtype :danger + :key :button-decline + :label (i18n/label :t/decline) + :accessibility-label :decline-join-request + :on-press (fn [] + (rf/dispatch [:communities.ui/decline-request-to-join-pressed + community-id id]))} + {:type :button + :subtype :positive + :key :button-accept + :label (i18n/label :t/accept) + :accessibility-label :accept-join-request + :on-press (fn [] + (rf/dispatch [:communities.ui/accept-request-to-join-pressed + community-id id]))}] + + nil)}])) diff --git a/src/status_im2/contexts/activity_center/notification/common/view.cljs b/src/status_im2/contexts/activity_center/notification/common/view.cljs index 4a5373a8c4..09041390c2 100644 --- a/src/status_im2/contexts/activity_center/notification/common/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/common/view.cljs @@ -6,8 +6,8 @@ [utils.re-frame :as rf])) (defn user-avatar-tag - [user] - (let [contact (rf/sub [:contacts/contact-by-identity user])] + [user-id] + (let [contact (rf/sub [:contacts/contact-by-identity user-id])] [quo/user-avatar-tag {:color :purple :override-theme :dark diff --git a/src/status_im2/contexts/activity_center/notification/contact_request/view.cljs b/src/status_im2/contexts/activity_center/notification/contact_request/view.cljs deleted file mode 100644 index 2466906839..0000000000 --- a/src/status_im2/contexts/activity_center/notification/contact_request/view.cljs +++ /dev/null @@ -1,59 +0,0 @@ -(ns status-im2.contexts.activity-center.notification.contact-request.view - (:require [quo2.core :as quo] - [react-native.core :as rn] - [status-im2.constants :as constants] - [status-im2.contexts.activity-center.notification.common.view :as common] - [utils.datetime :as datetime] - [utils.i18n :as i18n] - [utils.re-frame :as rf])) - -(defn view - [{:keys [id author message last-message] :as notification}] - (let [message (or message last-message) - pressable (case (:contact-request-state message) - constants/contact-request-message-state-accepted - ;; NOTE(2022-09-21): We need to dispatch to - ;; `:chat.ui/start-chat` instead of - ;; `:chat/navigate-to-chat`, otherwise the chat screen - ;; looks completely broken if it has never been opened - ;; before for the accepted contact. - [rn/touchable-opacity - {:on-press (fn [] - (rf/dispatch [:hide-popover]) - (rf/dispatch [:chat.ui/start-chat author]))}] - [:<>])] - (conj - pressable - [rn/view - [quo/activity-log - (merge - {:title (i18n/label :t/contact-request) - :icon :main-icons2/add-user - :timestamp (datetime/timestamp->relative (:timestamp notification)) - :unread? (not (:read notification)) - :context [[common/user-avatar-tag author] - (i18n/label :t/contact-request-sent)] - :message {:body (get-in message [:content :text])} - :status (case (:contact-request-state message) - constants/contact-request-message-state-accepted - {:type :positive :label (i18n/label :t/accepted)} - constants/contact-request-message-state-declined - {:type :negative :label (i18n/label :t/declined)} - nil)} - (case (:contact-request-state message) - constants/contact-request-message-state-pending - {:button-1 {:label (i18n/label :t/decline) - :accessibility-label :decline-contact-request - :type :danger - :on-press (fn [] - (rf/dispatch [:contact-requests.ui/decline-request id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))} - :button-2 {:label (i18n/label :t/accept) - :accessibility-label :accept-contact-request - :type :positive - :on-press (fn [] - (rf/dispatch [:contact-requests.ui/accept-request id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))}} - nil))]]))) diff --git a/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs b/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs new file mode 100644 index 0000000000..4bf9554bad --- /dev/null +++ b/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs @@ -0,0 +1,26 @@ +(ns status-im2.contexts.activity-center.notification.contact-requests.events + (:require [utils.re-frame :as rf])) + +(rf/defn accept-contact-request + {:events [:activity-center.contact-requests/accept-request]} + [{:keys [db]} id] + {:json-rpc/call [{:method "wakuext_acceptContactRequest" + :params [{:id id}] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}) + +(rf/defn decline-contact-request + {:events [:activity-center.contact-requests/decline-request]} + [{:keys [db]} id] + {:json-rpc/call [{:method "wakuext_declineContactRequest" + :params [{:id id}] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}) + +(rf/defn cancel-outgoing-contact-request + {:events [:activity-center.contact-requests/cancel-outgoing-request]} + [{:keys [db]} id] + {:json-rpc/call [{:method "wakuext_cancelOutgoingContactRequest" + :params [{:id id}] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}) diff --git a/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs b/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs new file mode 100644 index 0000000000..1a6198a1e9 --- /dev/null +++ b/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs @@ -0,0 +1,119 @@ +(ns status-im2.contexts.activity-center.notification.contact-requests.view + (:require [quo2.core :as quo] + [react-native.core :as rn] + [status-im2.constants :as constants] + [status-im2.contexts.activity-center.notification.common.view :as common] + [utils.datetime :as datetime] + [utils.i18n :as i18n] + [utils.re-frame :as rf])) + +(defn outgoing-contact-request-view + [{:keys [id chat-id message last-message] :as notification}] + (let [{:keys [contact-request-state] :as message} (or message last-message)] + (if (= contact-request-state constants/contact-request-message-state-accepted) + [quo/activity-log + {:title (i18n/label :t/contact-request-was-accepted) + :icon :i/add-user + :timestamp (datetime/timestamp->relative (:timestamp notification)) + :unread? (not (:read notification)) + :context [[common/user-avatar-tag chat-id] + (i18n/label :t/contact-request-is-now-a-contact)]} + :message {:body (get-in message [:content :text])} + :items []] + [quo/activity-log + {:title (i18n/label :t/contact-request) + :icon :i/add-user + :timestamp (datetime/timestamp->relative (:timestamp notification)) + :unread? (not (:read notification)) + :context [(i18n/label :t/contact-request-outgoing) + [common/user-avatar-tag chat-id]] + :message {:body (get-in message [:content :text])} + :items (case contact-request-state + constants/contact-request-state-mutual + [{:type :button + :subtype :danger + :key :button-cancel + :label (i18n/label :t/cancel) + :accessibility-label :cancel-contact-request + :on-press (fn [] + (rf/dispatch + [:activity-center.contact-requests/cancel-outgoing-request + (:from message)]) + (rf/dispatch [:activity-center.notifications/mark-as-read + id]))} + {:type :status + :subtype :pending + :key :status-pending + :label (i18n/label :t/pending)}] + + constants/contact-request-message-state-declined + [{:type :status + :subtype :pending + :key :status-pending + :label (i18n/label :t/pending)}] + + nil)}]))) + +(defn incoming-contact-request-view + [{:keys [id author message last-message] :as notification}] + (let [message (or message last-message)] + [quo/activity-log + {:title (i18n/label :t/contact-request) + :icon :i/add-user + :timestamp (datetime/timestamp->relative (:timestamp notification)) + :unread? (not (:read notification)) + :context [[common/user-avatar-tag author] + (i18n/label :t/contact-request-sent)] + :message {:body (get-in message [:content :text])} + :items + (case (:contact-request-state message) + constants/contact-request-message-state-accepted + [{:type :status + :subtype :positive + :key :status-accepted + :label (i18n/label :t/accepted)}] + + constants/contact-request-message-state-declined + [{:type :status + :subtype :negative + :key :status-declined + :label (i18n/label :t/declined)}] + + constants/contact-request-state-mutual + [{:type :button + :subtype :danger + :key :button-decline + :label (i18n/label :t/decline) + :accessibility-label :decline-contact-request + :on-press (fn [] + (rf/dispatch [:activity-center.contact-requests/decline-request id]) + (rf/dispatch [:activity-center.notifications/mark-as-read + id]))} + {:type :button + :subtype :positive + :key :button-accept + :label (i18n/label :t/accept) + :accessibility-label :accept-contact-request + :on-press (fn [] + (rf/dispatch [:activity-center.contact-requests/accept-request id]) + (rf/dispatch [:activity-center.notifications/mark-as-read + id]))}] + nil)}])) + +(defn view + [{:keys [author message last-message] :as notification}] + (let [{:keys [public-key]} (rf/sub [:multiaccount/contact]) + {:keys [contact-request-state]} (or message last-message)] + (cond + (= public-key author) + [outgoing-contact-request-view notification] + + (= contact-request-state constants/contact-request-message-state-accepted) + [rn/touchable-opacity + {:on-press (fn [] + (rf/dispatch [:hide-popover]) + (rf/dispatch [:chat.ui/start-chat {:public-key author}]))} + [incoming-contact-request-view notification]] + + :else + [incoming-contact-request-view notification]))) diff --git a/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs b/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs index 4ab78b4f84..825c1f36c6 100644 --- a/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs @@ -50,6 +50,13 @@ (= contact-verification-status constants/contact-verification-status-declined) {:type :negative :label (i18n/label :t/declined)}))) +(def ^:private max-reply-length + 280) + +(defn- valid-reply? + [reply] + (<= (count reply) max-reply-length)) + (defn view [_ _] (let [reply (atom "")] @@ -62,57 +69,72 @@ (= contact-verification-status constants/contact-verification-status-declined)) [quo/activity-log (merge - {:title (i18n/label :t/identity-verification-request) - :icon :i/friend - :timestamp (datetime/timestamp->relative (:timestamp notification)) - :unread? (not (:read notification)) + {:title (i18n/label :t/identity-verification-request) + :icon :i/friend + :timestamp (datetime/timestamp->relative (:timestamp notification)) + :unread? (not (:read notification)) :on-update-reply #(reset! reply %) - :replying? replying? - :context (context-tags challenger? notification) - :message (activity-message challenger? notification) - :status (activity-status challenger? contact-verification-status)} - (if challenger? - (when (= contact-verification-status constants/contact-verification-status-accepted) - {:button-1 {:label (i18n/label :t/untrustworthy) - :accessibility-label :mark-contact-verification-as-untrustworthy - :type :danger - :on-press (fn [] - (rf/dispatch - [:activity-center.contact-verification/mark-as-untrustworthy - id]) - (rf/dispatch [:activity-center.notifications/mark-as-read id]))} - :button-2 {:label (i18n/label :t/accept) - :accessibility-label :mark-contact-verification-as-trusted - :type :positive - :on-press (fn [] - (rf/dispatch - [:activity-center.contact-verification/mark-as-trusted id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))}}) - (when (= contact-verification-status constants/contact-verification-status-pending) - {:button-1 {:label (i18n/label :t/decline) - :accessibility-label :decline-contact-verification - :type :danger - :on-press (fn [] - (hide-bottom-sheet-and-dispatch - [:activity-center.contact-verification/decline id]) - (rf/dispatch - [:activity-center.notifications/mark-as-read id]))} - :button-2 (if replying? - {:label (i18n/label :t/send-reply) - :accessibility-label :reply-to-contact-verification - :type :primary - :on-press (fn [] - (hide-bottom-sheet-and-dispatch - [:activity-center.contact-verification/reply id - @reply]) - (rf/dispatch - [:activity-center.notifications/mark-as-read id]))} - {:label (i18n/label :t/message-reply) - :accessibility-label :send-reply-to-contact-verification - :type :primary - :on-press (fn [] - (rf/dispatch [:bottom-sheet/show-sheet - {:content view} - {:notification notification - :replying? true}]))})})))]))))) + :replying? replying? + :max-reply-length max-reply-length + :valid-reply? valid-reply? + :context (context-tags challenger? notification) + :message (activity-message challenger? notification) + :status (activity-status challenger? contact-verification-status) + :items + (if challenger? + (when (= contact-verification-status constants/contact-verification-status-accepted) + [{:type :button + :subtype :danger + :key :button-mark-as-untrustworthy + :label (i18n/label :t/untrustworthy) + :accessibility-label :mark-contact-verification-as-untrustworthy + :on-press (fn [] + (rf/dispatch + [:activity-center.contact-verification/mark-as-untrustworthy + id]) + (rf/dispatch [:activity-center.notifications/mark-as-read + id]))} + {:type :button + :subtype :positive + :key :button-accept + :label (i18n/label :t/accept) + :accessibility-label :mark-contact-verification-as-trusted + :on-press (fn [] + (rf/dispatch + [:activity-center.contact-verification/mark-as-trusted id]) + (rf/dispatch [:activity-center.notifications/mark-as-read + id]))}]) + (when (= contact-verification-status constants/contact-verification-status-pending) + [{:type :button + :subtype :danger + :key :button-decline + :label (i18n/label :t/decline) + :accessibility-label :decline-contact-verification + :on-press (fn [] + (hide-bottom-sheet-and-dispatch + [:activity-center.contact-verification/decline id]) + (rf/dispatch + [:activity-center.notifications/mark-as-read id]))} + (if replying? + {:type :button + :subtype :primary + :key :button-reply + :label (i18n/label :t/send-reply) + :accessibility-label :reply-to-contact-verification + :disable-when #(not (valid-reply? %)) + :on-press (fn [] + (hide-bottom-sheet-and-dispatch + [:activity-center.contact-verification/reply id + @reply]) + (rf/dispatch + [:activity-center.notifications/mark-as-read id]))} + {:type :button + :subtype :primary + :key :button-send-reply + :label (i18n/label :t/message-reply) + :accessibility-label :send-reply-to-contact-verification + :on-press (fn [] + (rf/dispatch [:bottom-sheet/show-sheet + {:content view} + {:notification notification + :replying? true}]))})]))})]))))) diff --git a/src/status_im2/contexts/activity_center/notification/membership/view.cljs b/src/status_im2/contexts/activity_center/notification/membership/view.cljs index b8d735ed6a..4100b4411b 100644 --- a/src/status_im2/contexts/activity_center/notification/membership/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/membership/view.cljs @@ -20,22 +20,26 @@ [{:keys [id accepted author read timestamp chat-name chat-id]}] [pressable {:accepted accepted :chat-id chat-id} [quo/activity-log - (merge - {:title (i18n/label :t/added-to-group-chat) - :icon :i/add-user - :timestamp (datetime/timestamp->relative timestamp) - :unread? (not read) - :context [[common/user-avatar-tag author] - (i18n/label :t/added-you-to) - [quo/group-avatar-tag chat-name - {:size :small - :color :purple}]]} - (when-not accepted - {:button-2 {:label (i18n/label :t/accept) - :accessibility-label :accept-group-chat-invitation - :type :positive - :on-press #(rf/dispatch [:activity-center.notifications/accept id])} - :button-1 {:label (i18n/label :t/decline) - :accessibility-label :decline-group-chat-invitation - :type :danger - :on-press #(rf/dispatch [:activity-center.notifications/dismiss id])}}))]]) + {:title (i18n/label :t/added-to-group-chat) + :icon :i/add-user + :timestamp (datetime/timestamp->relative timestamp) + :unread? (not read) + :context [[common/user-avatar-tag author] + (i18n/label :t/added-you-to) + [quo/group-avatar-tag chat-name + {:size :small + :color :purple}]] + :items (when-not accepted + [{:type :button + :subtype :positive + :key :button-accept + :label (i18n/label :t/accept) + :accessibility-label :accept-group-chat-invitation + :on-press #(rf/dispatch [:activity-center.notifications/accept id])} + {:type :button + :subtype :danger + :key :button-decline + :label (i18n/label :t/decline) + :accessibility-label :decline-group-chat-invitation + :on-press #(rf/dispatch [:activity-center.notifications/dismiss + id])}])}]]) diff --git a/src/status_im2/contexts/activity_center/view.cljs b/src/status_im2/contexts/activity_center/view.cljs index 5380bbec09..f1080c025f 100644 --- a/src/status_im2/contexts/activity_center/view.cljs +++ b/src/status_im2/contexts/activity_center/view.cljs @@ -6,7 +6,7 @@ [react-native.safe-area :as safe-area] [status-im2.contexts.activity-center.notification-types :as types] [status-im2.contexts.activity-center.notification.admin.view :as admin] - [status-im2.contexts.activity-center.notification.contact-request.view :as contact-request] + [status-im2.contexts.activity-center.notification.contact-requests.view :as contact-requests] [status-im2.contexts.activity-center.notification.contact-verification.view :as contact-verification] [status-im2.contexts.activity-center.notification.membership.view :as membership] @@ -173,15 +173,15 @@ (= type types/contact-verification) [contact-verification/view notification {}] - (= type types/contact-request) - [contact-request/view notification] - (= type types/mention) [mentions/view notification] (= type types/reply) [reply/view notification] + (= type types/contact-request) + [contact-requests/view notification] + (= type types/admin) [admin/view notification] diff --git a/src/status_im2/contexts/contacts/events.cljs b/src/status_im2/contexts/contacts/events.cljs new file mode 100644 index 0000000000..0da55f0358 --- /dev/null +++ b/src/status_im2/contexts/contacts/events.cljs @@ -0,0 +1,22 @@ +(ns status-im2.contexts.contacts.events + (:require + [utils.re-frame :as rf] + [status-im.contact.db :as contact.db] + [status-im.data-store.contacts :as contacts-store])) + +(rf/defn load-contacts + {:events [:contacts/contacts-loaded]} + [{:keys [db] :as cofx} all-contacts] + (let [contacts-list (map #(vector (:public-key %) + (if (empty? (:address %)) + (dissoc % :address) + %)) + all-contacts) + contacts (into {} contacts-list)] + {:db (cond-> (-> db + (update :contacts/contacts #(merge contacts %)) + (assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts))))})) + +(rf/defn initialize-contacts + [cofx] + (contacts-store/fetch-contacts-rpc cofx #(rf/dispatch [:contacts/contacts-loaded %]))) diff --git a/status-go-version.json b/status-go-version.json index 2718dc81cc..ec59123ab6 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -1,9 +1,9 @@ { - "_comment": "THIS SHOULD NOT BE EDITED BY HAND.", - "_comment": "Instead use: scripts/update-status-go.sh ", - "owner": "status-im", - "repo": "status-go", - "version": "v0.131.10", - "commit-sha1": "8ff91ba0024f5ecf05d29904288537b236329f51", - "src-sha256": "1m3an4fhzhh0vq8bb24xfjwdysfdd9qrz08a3gfz3ddahkh41jad" + "_comment": "THIS SHOULD NOT BE EDITED BY HAND.", + "_comment": "Instead use: scripts/update-status-go.sh ", + "owner": "status-im", + "repo": "status-go", + "version": "v0.131.11", + "commit-sha1": "27730057d0914b0c53c3e87e1442def7edc76998", + "src-sha256": "1c3q6nbki2fcs23jarkk673kr65frdfqbb3hsxp05mh8ybv1wgjw" } diff --git a/translations/en.json b/translations/en.json index 955d34614f..8a3865f4c6 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1825,12 +1825,17 @@ "new-ui": "New UI", "send-contact-request-message": "To start a chat you need to become contacts", "contact-request": "Contact request", + "contact-request-was-accepted": "Contact request accepted", + "contact-request-is-now-a-contact": "is now a contact", "contact-requests": "Contact requests", "say-hi": "Say hi", "opened": "Opened", "accepted": "Accepted", "declined": "Declined", "contact-request-sent": "sent contact request", + "contact-request-sent-toast": "{{name}} sent you a contact request", + "contact-request-accepted-toast": "{{name}} accepted your contact request", + "contact-request-outgoing": "You’re trying to connect with", "contact-request-header": "👋 Contact requests", "contact-request-declined": "Declined ⓧ", "contact-request-accepted": "Accepted ✓",