From b29912f7f72462243169fcc1c985d0bf96f049ff Mon Sep 17 00:00:00 2001 From: Volodymyr Kozieiev Date: Mon, 19 Apr 2021 15:12:53 +0300 Subject: [PATCH] community links unfurling Signed-off-by: Volodymyr Kozieiev --- src/status_im/chat/models/link_preview.cljs | 30 +++-- src/status_im/constants.cljs | 1 + src/status_im/ethereum/json_rpc.cljs | 1 + src/status_im/router/core.cljs | 6 +- src/status_im/signals/core.cljs | 2 + .../ui/screens/chat/message/link_preview.cljs | 72 ++++++++++-- .../ui/screens/chat/message/styles.cljs | 3 + .../ui/screens/communities/community.cljs | 107 ++++++++++-------- src/status_im/utils/universal_links/core.cljs | 6 + status-go-version.json | 6 +- translations/en.json | 4 + 11 files changed, 166 insertions(+), 72 deletions(-) diff --git a/src/status_im/chat/models/link_preview.cljs b/src/status_im/chat/models/link_preview.cljs index 5a60a7fbbd..fe6f36397f 100644 --- a/src/status_im/chat/models/link_preview.cljs +++ b/src/status_im/chat/models/link_preview.cljs @@ -27,16 +27,23 @@ #{}) {}))) +(fx/defn resolve-community-info + {:events [::resolve-community-info]} + [cofx community-id] + {::json-rpc/call [{:method (json-rpc/call-ext-method "requestCommunityInfoFromMailserver") + :params [community-id] + :on-success #() + :on-error #(log/error "Failed to request community info from mailserver")}]}) + (fx/defn load-link-preview-data {:events [::load-link-preview-data]} [cofx link] - (fx/merge cofx - {::json-rpc/call [{:method (json-rpc/call-ext-method "getLinkPreviewData") - :params [link] - :on-success #(re-frame/dispatch [::cache-link-preview-data link %]) - :on-error #(re-frame/dispatch [::cache-link-preview-data - link - {:error (str "Can't get preview data for " link)}])}]})) + {::json-rpc/call [{:method (json-rpc/call-ext-method "getLinkPreviewData") + :params [link] + :on-success #(re-frame/dispatch [::cache-link-preview-data link %]) + :on-error #(re-frame/dispatch [::cache-link-preview-data + link + {:error (str "Can't get preview data for " link)}])}]}) (fx/defn cache-link-preview-data {:events [::cache-link-preview-data]} @@ -46,6 +53,15 @@ :link-previews-cache (assoc (get multiaccount :link-previews-cache {}) site data))) +(defn community-link [id] + (str "https://join.status.im/c/" id)) + +(defn cache-community-preview-data + [{:keys [id] :as community}] + (re-frame/dispatch [::cache-link-preview-data + (community-link id) + community])) + (fx/defn should-suggest-link-preview {:events [::should-suggest-link-preview]} [{:keys [db] :as cofx} enabled?] diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 81145a3ce8..0c070dca02 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -115,6 +115,7 @@ (def regx-italic #"~[^~]+~") (def regx-backquote #"`[^`]+`") (def regx-universal-link #"((^https?://join.status.im/)|(^status-im://))[\x00-\x7F]+$") +(def regx-community-universal-link #"((^https?://join.status.im/)|(^status-im://))c/([\x00-\x7F]+)$") (def regx-deep-link #"((^ethereum:.*)|(^status-im://[\x00-\x7F]+$))") (def ^:const dapp-permission-contact-code "contact-code") diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index c2fad67798..a8d5b05c73 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -84,6 +84,7 @@ "wakuext_emojiReactionsByChatID" {} "wakuext_getLinkPreviewWhitelist" {} "wakuext_getLinkPreviewData" {} + "wakuext_requestCommunityInfoFromMailserver" {} ;;TODO not used anywhere? "wakuext_deleteChat" {} "wakuext_saveContact" {} diff --git a/src/status_im/router/core.cljs b/src/status_im/router/core.cljs index 9e8aab1ae6..8eefd2fb22 100644 --- a/src/status_im/router/core.cljs +++ b/src/status_im/router/core.cljs @@ -43,7 +43,8 @@ "b/" browser-extractor "browser/" browser-extractor ["p/" :chat-id] :private-chat - ["cr/" :community-id] :community-requests + ["cr/" :community-id] :community-requests + ["c/" :community-id] :community "g/" group-chat-extractor ["wallet/" :account] :wallet-account ["u/" :user-id] :user @@ -205,6 +206,9 @@ (= handler :community-requests) (cb {:type handler :community-id (:community-id route-params)}) + (= handler :community) + (cb {:type handler :community-id (:community-id route-params)}) + (= handler :referrals) (cb (match-referral route-params)) diff --git a/src/status_im/signals/core.cljs b/src/status_im/signals/core.cljs index 9e55553306..c3f852ae88 100644 --- a/src/status_im/signals/core.cljs +++ b/src/status_im/signals/core.cljs @@ -8,6 +8,7 @@ [status-im.transport.message.core :as transport.message] [status-im.notifications.local :as local-notifications] [status-im.chat.models.message :as models.message] + [status-im.chat.models.link-preview :as link.preview] [status-im.utils.fx :as fx] [taoensso.timbre :as log])) @@ -69,4 +70,5 @@ "messages.new" (transport.message/sanitize-messages-and-process-response cofx event-js true) "wallet" (ethereum.subscriptions/new-wallet-event cofx (js->clj event-js :keywordize-keys true)) "local-notifications" (local-notifications/process cofx (js->clj event-js :keywordize-keys true)) + "community.found" (link.preview/cache-community-preview-data (js->clj event-js :keywordize-keys true)) (log/debug "Event " type " not handled")))) diff --git a/src/status_im/ui/screens/chat/message/link_preview.cljs b/src/status_im/ui/screens/chat/message/link_preview.cljs index 05068316e7..488698bd4d 100644 --- a/src/status_im/ui/screens/chat/message/link_preview.cljs +++ b/src/status_im/ui/screens/chat/message/link_preview.cljs @@ -7,7 +7,9 @@ [status-im.i18n.i18n :as i18n] [status-im.ui.screens.chat.message.styles :as styles] [status-im.react-native.resources :as resources] - [status-im.chat.models.link-preview :as link-preview]) + [status-im.chat.models.link-preview :as link-preview] + [status-im.ui.screens.communities.icon :as communities.icon] + [status-im.constants :as constants]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) (defn link-belongs-to-domain [link domain] @@ -16,16 +18,25 @@ (string/starts-with? link (str "https://www." domain)) true :else false)) +(defn community-id-from-link [link] + (nth (re-find constants/regx-community-universal-link link) 4)) + (defn domain-info-if-whitelisted [link whitelist] (first (filter #(link-belongs-to-domain link (:address %)) whitelist))) (defn link-extended-info [link whitelist enabled-list] - (let [domain-info (domain-info-if-whitelisted link whitelist)] - {:whitelisted (not (nil? domain-info)) - :enabled (contains? enabled-list (:title domain-info)) - :link link})) + (let [domain-info (domain-info-if-whitelisted link whitelist) + community-id (community-id-from-link link)] + (if-not community-id + {:whitelisted (not (nil? domain-info)) + :enabled (contains? enabled-list (:title domain-info)) + :link link} + {:whitelisted true + :enabled true + :link link + :community true}))) (defn previewable-link [links whitelist enabled-list] (->> links @@ -88,6 +99,45 @@ :style styles/link-preview-site} site]])]]))))) +(defview community-preview [community outgoing timeline] + (let [{:keys [name members description verified]} community + members-count (count members)] + [react/view (styles/link-preview-wrapper outgoing timeline) + (if verified [quo/text {:size :small + :color :link + :style styles/community-preview-header} + (i18n/label :t/verified-community)] + [quo/text {:size :small + :color :secondary + :style styles/community-preview-header} + (i18n/label :t/community)]) + [quo/separator] + [react/view {:flex-direction :row :align-self :flex-start :margin 12} + [communities.icon/community-icon community] + [react/view {:flex 1 :flex-direction :column :margin-left 12} + [quo/text {:weight :bold :size :large} name] + [quo/text description] + [quo/text {:size :small + :color :secondary} + (i18n/label-pluralize members-count :t/community-members {:count members-count})]]] + [quo/separator] + [quo/button {:on-press #(re-frame/dispatch [:navigate-to + :community + {:community-id (:id community)}]) + :type :secondary} + (i18n/label :t/view)]])) + +(defview community-preview-loader [community-link outgoing timeline] + (letsubs [cache [:link-preview/cache]] + {:component-did-mount (fn [] + (let [community (get cache community-link) + community-id (community-id-from-link community-link)] + (when-not community + (re-frame/dispatch + [::link-preview/resolve-community-info community-id]))))} + (when-let [community (get cache community-link)] + [community-preview community outgoing timeline]))) + (defview link-preview-wrapper [links outgoing timeline] (letsubs [ask-user? [:link-preview/link-preview-request-enabled] @@ -95,9 +145,9 @@ enabled-sites [:link-preview/enabled-sites]] (when links (let [link-info (previewable-link links whitelist enabled-sites) - {:keys [link whitelisted enabled]} link-info] - (when (and link whitelisted) - (if enabled - [link-preview-loader link outgoing timeline] - (when ask-user? - [link-preview-enable-request]))))))) + {:keys [link whitelisted enabled community]} link-info + link-whitelisted (and link whitelisted)] + (cond + community [community-preview-loader link outgoing timeline] + (and link-whitelisted enabled) [link-preview-loader link outgoing timeline] + (and link-whitelisted ask-user?) [link-preview-enable-request]))))) diff --git a/src/status_im/ui/screens/chat/message/styles.cljs b/src/status_im/ui/screens/chat/message/styles.cljs index 1b27d226e6..4e07241f11 100644 --- a/src/status_im/ui/screens/chat/message/styles.cljs +++ b/src/status_im/ui/screens/chat/message/styles.cljs @@ -103,6 +103,9 @@ :height 94 :align-self :center}) +(def community-preview-header + {:margin 8 :margin-left 12}) + (defn link-preview-wrapper [outgoing timeline] {:overflow :hidden :border-top-left-radius 16 diff --git a/src/status_im/ui/screens/communities/community.cljs b/src/status_im/ui/screens/communities/community.cljs index f28332f9cd..4da2229941 100644 --- a/src/status_im/ui/screens/communities/community.cljs +++ b/src/status_im/ui/screens/communities/community.cljs @@ -117,11 +117,11 @@ :icon :main-icons/objects :on-press #(hide-sheet-and-dispatch [::communities/export-pressed id])}])])) -(defn welcome-blank-page [] +(defn blank-page [text] [rn/view {:style {:padding 16 :flex 1 :flex-direction :row :align-items :center :justify-content :center}} [quo/text {:align :center :color :secondary} - (i18n/label :t/welcome-community-blank-message)]]) + text]]) (defn community-chat-item [{:keys [chat-id] :as home-item}] [inner-item/home-list-item @@ -136,7 +136,7 @@ (defn community-chat-list [chats] (if (empty? chats) - [welcome-blank-page] + [blank-page (i18n/label :t/welcome-community-blank-message)] [list/flat-list {:key-fn :chat-id :content-container-style {:padding-vertical 8} @@ -188,59 +188,66 @@ :data chats :render-fn channel-preview-item}])) +(defn unknown-community [] + [rn/view {:style {:flex 1}} + [topbar/topbar {:title (i18n/label :t/not-found)}] + [blank-page (i18n/label :t/community-info-not-found)]]) + (defn community [route] (let [{:keys [community-id]} (get-in route [:route :params]) {:keys [id chats name images members permissions color joined can-request-access? can-join? requested-to-join-at admin] :as community} (evt [:bottom-sheet/show-sheet + (if community + [rn/view {:style {:flex 1}} + [topbar/topbar + {:content + [toolbar-content + id + name + color + images + (not= (:access permissions) constants/community-no-membership-access) + (count members)] + :right-accessories + (when (or admin joined) + [{:icon :main-icons/more + :accessibility-label :community-menu-button + :on-press #(>evt [:bottom-sheet/show-sheet + {:content (fn [] + [community-actions community])}])}])}] + (if joined + [community-channel-list id] + [community-channel-preview-list id chats]) + (when admin + [components.plus-button/plus-button + {:on-press #(>evt [:bottom-sheet/show-sheet {:content (fn [] - [community-actions community])}])}])}] - (if joined - [community-channel-list id] - [community-channel-preview-list id chats]) - (when admin - [components.plus-button/plus-button - {:on-press #(>evt [:bottom-sheet/show-sheet - {:content (fn [] - [community-plus-actions community])}]) - :accessibility-label :new-chat-button}]) - (when-not joined - (cond - can-join? - [toolbar/toolbar - {:show-border? true - :center [quo/button {:on-press #(>evt [::communities/join id]) - :type :secondary} - (i18n/label :t/join)]}] - can-request-access? - (if (and (pos? requested-to-join-at) - (not (can-request-access-again? requested-to-join-at))) + [community-plus-actions community])}]) + :accessibility-label :new-chat-button}]) + (when-not joined + (cond + can-join? [toolbar/toolbar {:show-border? true - :left [quo/text {:color :secondary} (i18n/label :t/membership-request-pending)]}] - [toolbar/toolbar - {:show-border? true - :center [quo/button {:on-press #(>evt [::communities/request-to-join id]) + :center [quo/button {:on-press #(>evt [::communities/join id]) :type :secondary} - (i18n/label :t/request-access)]}]) - :else - [toolbar/toolbar - {:show-border? true - :center [quo/button {:on-press #(>evt [::communities/join id]) - :type :secondary} - (i18n/label :t/follow)]}]))])) + (i18n/label :t/join)]}] + can-request-access? + (if (and (pos? requested-to-join-at) + (not (can-request-access-again? requested-to-join-at))) + [toolbar/toolbar + {:show-border? true + :left [quo/text {:color :secondary} (i18n/label :t/membership-request-pending)]}] + [toolbar/toolbar + {:show-border? true + :center [quo/button {:on-press #(>evt [::communities/request-to-join id]) + :type :secondary} + (i18n/label :t/request-access)]}]) + :else + [toolbar/toolbar + {:show-border? true + :center [quo/button {:on-press #(>evt [::communities/join id]) + :type :secondary} + (i18n/label :t/follow)]}]))] + [unknown-community]))) diff --git a/src/status_im/utils/universal_links/core.cljs b/src/status_im/utils/universal_links/core.cljs index c652209b1a..c696a67cd4 100644 --- a/src/status_im/utils/universal_links/core.cljs +++ b/src/status_im/utils/universal_links/core.cljs @@ -27,6 +27,7 @@ (def links {:public-chat "%s/%s" :private-chat "%s/p/%s" :community-requests "%s/cr/%s" + :community "%s/c/%s" :group-chat "%s/g/%s" :user "%s/u/%s" :browse "%s/b/%s"}) @@ -64,6 +65,10 @@ (log/info "universal-links: handling community request " community-id) (navigation/navigate-to-cofx cofx :community-requests-to-join {:community-id community-id})) +(fx/defn handle-community [cofx {:keys [community-id]}] + (log/info "universal-links: handling community" community-id) + (navigation/navigate-to-cofx cofx :community {:community-id community-id})) + (fx/defn handle-public-chat [cofx {:keys [topic]}] (log/info "universal-links: handling public chat" topic) (when (seq topic) @@ -122,6 +127,7 @@ :public-chat (handle-public-chat cofx data) :private-chat (handle-private-chat cofx data) :community-requests (handle-community-requests cofx data) + :community (handle-community cofx data) :contact (handle-view-profile cofx data) :browser (handle-browse cofx data) :eip681 (handle-eip681 cofx data) diff --git a/status-go-version.json b/status-go-version.json index ec992a2196..7afb0bb718 100644 --- a/status-go-version.json +++ b/status-go-version.json @@ -2,7 +2,7 @@ "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh ' instead", "owner": "status-im", "repo": "status-go", - "version": "v0.76.0", - "commit-sha1": "c739f73f497b2cc1f22be0a176683193766d5193", - "src-sha256": "1db355sqsaj9g2hdzs9db29azrf8s1mzp0x62a6sny9gyiwwl5vd" + "version": "v0.76.3", + "commit-sha1": "0e048081b0cb9f8324f4b64b1b042185a6798141", + "src-sha256": "1p0y8af3pzyab3f0qphyy1sm0x5m8c7kg05n0qrfpxsydy7sh1v4" } diff --git a/translations/en.json b/translations/en.json index ab95c161af..2b92695315 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1509,6 +1509,10 @@ "rpc-usage-copy": "Copy", "community-message-preview": "Invitation to join {{community-name}}", "non-contacts": "Non contacts", + "community": "Community", + "verified-community": "✓ Verified community", + "community-info-not-found": "Community information not found", + "not-found": "Not found", "activity": "Activity", "reject-and-delete": "Reject and delete", "accept-and-add": "Accept and add"