community links unfurling

Signed-off-by: Volodymyr Kozieiev <vkjr.sp@gmail.com>
This commit is contained in:
Volodymyr Kozieiev 2021-04-19 15:12:53 +03:00
parent fab241f6ac
commit b29912f7f7
No known key found for this signature in database
GPG Key ID: 82B04968DF4C0535
11 changed files with 166 additions and 72 deletions

View File

@ -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 (fx/defn load-link-preview-data
{:events [::load-link-preview-data]} {:events [::load-link-preview-data]}
[cofx link] [cofx link]
(fx/merge cofx {::json-rpc/call [{:method (json-rpc/call-ext-method "getLinkPreviewData")
{::json-rpc/call [{:method (json-rpc/call-ext-method "getLinkPreviewData") :params [link]
:params [link] :on-success #(re-frame/dispatch [::cache-link-preview-data link %])
:on-success #(re-frame/dispatch [::cache-link-preview-data link %]) :on-error #(re-frame/dispatch [::cache-link-preview-data
:on-error #(re-frame/dispatch [::cache-link-preview-data link
link {:error (str "Can't get preview data for " link)}])}]})
{:error (str "Can't get preview data for " link)}])}]}))
(fx/defn cache-link-preview-data (fx/defn cache-link-preview-data
{:events [::cache-link-preview-data]} {:events [::cache-link-preview-data]}
@ -46,6 +53,15 @@
:link-previews-cache :link-previews-cache
(assoc (get multiaccount :link-previews-cache {}) site data))) (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 (fx/defn should-suggest-link-preview
{:events [::should-suggest-link-preview]} {:events [::should-suggest-link-preview]}
[{:keys [db] :as cofx} enabled?] [{:keys [db] :as cofx} enabled?]

View File

@ -115,6 +115,7 @@
(def regx-italic #"~[^~]+~") (def regx-italic #"~[^~]+~")
(def regx-backquote #"`[^`]+`") (def regx-backquote #"`[^`]+`")
(def regx-universal-link #"((^https?://join.status.im/)|(^status-im://))[\x00-\x7F]+$") (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 regx-deep-link #"((^ethereum:.*)|(^status-im://[\x00-\x7F]+$))")
(def ^:const dapp-permission-contact-code "contact-code") (def ^:const dapp-permission-contact-code "contact-code")

View File

@ -84,6 +84,7 @@
"wakuext_emojiReactionsByChatID" {} "wakuext_emojiReactionsByChatID" {}
"wakuext_getLinkPreviewWhitelist" {} "wakuext_getLinkPreviewWhitelist" {}
"wakuext_getLinkPreviewData" {} "wakuext_getLinkPreviewData" {}
"wakuext_requestCommunityInfoFromMailserver" {}
;;TODO not used anywhere? ;;TODO not used anywhere?
"wakuext_deleteChat" {} "wakuext_deleteChat" {}
"wakuext_saveContact" {} "wakuext_saveContact" {}

View File

@ -43,7 +43,8 @@
"b/" browser-extractor "b/" browser-extractor
"browser/" browser-extractor "browser/" browser-extractor
["p/" :chat-id] :private-chat ["p/" :chat-id] :private-chat
["cr/" :community-id] :community-requests ["cr/" :community-id] :community-requests
["c/" :community-id] :community
"g/" group-chat-extractor "g/" group-chat-extractor
["wallet/" :account] :wallet-account ["wallet/" :account] :wallet-account
["u/" :user-id] :user ["u/" :user-id] :user
@ -205,6 +206,9 @@
(= handler :community-requests) (= handler :community-requests)
(cb {:type handler :community-id (:community-id route-params)}) (cb {:type handler :community-id (:community-id route-params)})
(= handler :community)
(cb {:type handler :community-id (:community-id route-params)})
(= handler :referrals) (= handler :referrals)
(cb (match-referral route-params)) (cb (match-referral route-params))

View File

@ -8,6 +8,7 @@
[status-im.transport.message.core :as transport.message] [status-im.transport.message.core :as transport.message]
[status-im.notifications.local :as local-notifications] [status-im.notifications.local :as local-notifications]
[status-im.chat.models.message :as models.message] [status-im.chat.models.message :as models.message]
[status-im.chat.models.link-preview :as link.preview]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[taoensso.timbre :as log])) [taoensso.timbre :as log]))
@ -69,4 +70,5 @@
"messages.new" (transport.message/sanitize-messages-and-process-response cofx event-js true) "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)) "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)) "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")))) (log/debug "Event " type " not handled"))))

View File

@ -7,7 +7,9 @@
[status-im.i18n.i18n :as i18n] [status-im.i18n.i18n :as i18n]
[status-im.ui.screens.chat.message.styles :as styles] [status-im.ui.screens.chat.message.styles :as styles]
[status-im.react-native.resources :as resources] [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]])) (:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn link-belongs-to-domain [link domain] (defn link-belongs-to-domain [link domain]
@ -16,16 +18,25 @@
(string/starts-with? link (str "https://www." domain)) true (string/starts-with? link (str "https://www." domain)) true
:else false)) :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] (defn domain-info-if-whitelisted [link whitelist]
(first (filter (first (filter
#(link-belongs-to-domain link (:address %)) #(link-belongs-to-domain link (:address %))
whitelist))) whitelist)))
(defn link-extended-info [link whitelist enabled-list] (defn link-extended-info [link whitelist enabled-list]
(let [domain-info (domain-info-if-whitelisted link whitelist)] (let [domain-info (domain-info-if-whitelisted link whitelist)
{:whitelisted (not (nil? domain-info)) community-id (community-id-from-link link)]
:enabled (contains? enabled-list (:title domain-info)) (if-not community-id
:link link})) {: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] (defn previewable-link [links whitelist enabled-list]
(->> links (->> links
@ -88,6 +99,45 @@
:style styles/link-preview-site} :style styles/link-preview-site}
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] (defview link-preview-wrapper [links outgoing timeline]
(letsubs (letsubs
[ask-user? [:link-preview/link-preview-request-enabled] [ask-user? [:link-preview/link-preview-request-enabled]
@ -95,9 +145,9 @@
enabled-sites [:link-preview/enabled-sites]] enabled-sites [:link-preview/enabled-sites]]
(when links (when links
(let [link-info (previewable-link links whitelist enabled-sites) (let [link-info (previewable-link links whitelist enabled-sites)
{:keys [link whitelisted enabled]} link-info] {:keys [link whitelisted enabled community]} link-info
(when (and link whitelisted) link-whitelisted (and link whitelisted)]
(if enabled (cond
[link-preview-loader link outgoing timeline] community [community-preview-loader link outgoing timeline]
(when ask-user? (and link-whitelisted enabled) [link-preview-loader link outgoing timeline]
[link-preview-enable-request]))))))) (and link-whitelisted ask-user?) [link-preview-enable-request])))))

View File

@ -103,6 +103,9 @@
:height 94 :height 94
:align-self :center}) :align-self :center})
(def community-preview-header
{:margin 8 :margin-left 12})
(defn link-preview-wrapper [outgoing timeline] (defn link-preview-wrapper [outgoing timeline]
{:overflow :hidden {:overflow :hidden
:border-top-left-radius 16 :border-top-left-radius 16

View File

@ -117,11 +117,11 @@
:icon :main-icons/objects :icon :main-icons/objects
:on-press #(hide-sheet-and-dispatch [::communities/export-pressed id])}])])) :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}} [rn/view {:style {:padding 16 :flex 1 :flex-direction :row :align-items :center :justify-content :center}}
[quo/text {:align :center [quo/text {:align :center
:color :secondary} :color :secondary}
(i18n/label :t/welcome-community-blank-message)]]) text]])
(defn community-chat-item [{:keys [chat-id] :as home-item}] (defn community-chat-item [{:keys [chat-id] :as home-item}]
[inner-item/home-list-item [inner-item/home-list-item
@ -136,7 +136,7 @@
(defn community-chat-list [chats] (defn community-chat-list [chats]
(if (empty? chats) (if (empty? chats)
[welcome-blank-page] [blank-page (i18n/label :t/welcome-community-blank-message)]
[list/flat-list [list/flat-list
{:key-fn :chat-id {:key-fn :chat-id
:content-container-style {:padding-vertical 8} :content-container-style {:padding-vertical 8}
@ -188,59 +188,66 @@
:data chats :data chats
:render-fn channel-preview-item}])) :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] (defn community [route]
(let [{:keys [community-id]} (get-in route [:route :params]) (let [{:keys [community-id]} (get-in route [:route :params])
{:keys [id chats name images members permissions color joined can-request-access? {:keys [id chats name images members permissions color joined can-request-access?
can-join? requested-to-join-at admin] can-join? requested-to-join-at admin]
:as community} (<sub [:communities/community community-id])] :as community} (<sub [:communities/community community-id])]
[rn/view {:style {:flex 1}} (if community
[topbar/topbar [rn/view {:style {:flex 1}}
{:content [topbar/topbar
[toolbar-content {:content
id [toolbar-content
name id
color name
images color
(not= (:access permissions) constants/community-no-membership-access) images
(count members)] (not= (:access permissions) constants/community-no-membership-access)
:right-accessories (count members)]
(when (or admin joined) :right-accessories
[{:icon :main-icons/more (when (or admin joined)
:accessibility-label :community-menu-button [{:icon :main-icons/more
:on-press #(>evt [:bottom-sheet/show-sheet :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 [] {:content (fn []
[community-actions community])}])}])}] [community-plus-actions community])}])
(if joined :accessibility-label :new-chat-button}])
[community-channel-list id] (when-not joined
[community-channel-preview-list id chats]) (cond
(when admin can-join?
[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)))
[toolbar/toolbar [toolbar/toolbar
{:show-border? true {:show-border? true
:left [quo/text {:color :secondary} (i18n/label :t/membership-request-pending)]}] :center [quo/button {:on-press #(>evt [::communities/join id])
[toolbar/toolbar
{:show-border? true
:center [quo/button {:on-press #(>evt [::communities/request-to-join id])
:type :secondary} :type :secondary}
(i18n/label :t/request-access)]}]) (i18n/label :t/join)]}]
:else can-request-access?
[toolbar/toolbar (if (and (pos? requested-to-join-at)
{:show-border? true (not (can-request-access-again? requested-to-join-at)))
:center [quo/button {:on-press #(>evt [::communities/join id]) [toolbar/toolbar
:type :secondary} {:show-border? true
(i18n/label :t/follow)]}]))])) :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])))

View File

@ -27,6 +27,7 @@
(def links {:public-chat "%s/%s" (def links {:public-chat "%s/%s"
:private-chat "%s/p/%s" :private-chat "%s/p/%s"
:community-requests "%s/cr/%s" :community-requests "%s/cr/%s"
:community "%s/c/%s"
:group-chat "%s/g/%s" :group-chat "%s/g/%s"
:user "%s/u/%s" :user "%s/u/%s"
:browse "%s/b/%s"}) :browse "%s/b/%s"})
@ -64,6 +65,10 @@
(log/info "universal-links: handling community request " community-id) (log/info "universal-links: handling community request " community-id)
(navigation/navigate-to-cofx cofx :community-requests-to-join {:community-id 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]}] (fx/defn handle-public-chat [cofx {:keys [topic]}]
(log/info "universal-links: handling public chat" topic) (log/info "universal-links: handling public chat" topic)
(when (seq topic) (when (seq topic)
@ -122,6 +127,7 @@
:public-chat (handle-public-chat cofx data) :public-chat (handle-public-chat cofx data)
:private-chat (handle-private-chat cofx data) :private-chat (handle-private-chat cofx data)
:community-requests (handle-community-requests cofx data) :community-requests (handle-community-requests cofx data)
:community (handle-community cofx data)
:contact (handle-view-profile cofx data) :contact (handle-view-profile cofx data)
:browser (handle-browse cofx data) :browser (handle-browse cofx data)
:eip681 (handle-eip681 cofx data) :eip681 (handle-eip681 cofx data)

View File

@ -2,7 +2,7 @@
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead", "_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
"owner": "status-im", "owner": "status-im",
"repo": "status-go", "repo": "status-go",
"version": "v0.76.0", "version": "v0.76.3",
"commit-sha1": "c739f73f497b2cc1f22be0a176683193766d5193", "commit-sha1": "0e048081b0cb9f8324f4b64b1b042185a6798141",
"src-sha256": "1db355sqsaj9g2hdzs9db29azrf8s1mzp0x62a6sny9gyiwwl5vd" "src-sha256": "1p0y8af3pzyab3f0qphyy1sm0x5m8c7kg05n0qrfpxsydy7sh1v4"
} }

View File

@ -1509,6 +1509,10 @@
"rpc-usage-copy": "Copy", "rpc-usage-copy": "Copy",
"community-message-preview": "Invitation to join {{community-name}}", "community-message-preview": "Invitation to join {{community-name}}",
"non-contacts": "Non contacts", "non-contacts": "Non contacts",
"community": "Community",
"verified-community": "✓ Verified community",
"community-info-not-found": "Community information not found",
"not-found": "Not found",
"activity": "Activity", "activity": "Activity",
"reject-and-delete": "Reject and delete", "reject-and-delete": "Reject and delete",
"accept-and-add": "Accept and add" "accept-and-add": "Accept and add"