Merge pull request #460 from status-im/bug/discovery

Discovery fixes (#432, #434, #462, #463)
This commit is contained in:
Roman Volosovskyi 2016-11-17 20:17:07 +02:00 committed by GitHub
commit 5c1c0f78eb
40 changed files with 630 additions and 442 deletions

View File

@ -14,6 +14,7 @@
"awesome-phonenumber": "^1.0.13",
"babel-plugin-transform-es2015-block-scoping": "6.15.0",
"browserify-zlib": "^0.1.4",
"buffer": "^3.6.0",
"chance": "1.0.4",
"console-browserify": "^1.1.0",
"constants-browserify": "0.0.1",

View File

@ -65,7 +65,7 @@
[{:keys [current-account-id current-public-key web3 accounts]} _]
(let [{:keys [name photo-path status]} (get accounts current-account-id)
{:keys [updates-public-key updates-private-key]} (accounts current-account-id)]
(protocol/broadcats-profile!
(protocol/broadcast-profile!
{:web3 web3
:message {:from current-public-key
:message-id (random/id)

View File

@ -15,7 +15,6 @@
[status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]]
[status-im.qr-scanner.screen :refer [qr-scanner]]
[status-im.discovery.tag :refer [discovery-tag]]
[status-im.discovery.search-results :refer [discovery-search-results]]
[status-im.chat.screen :refer [chat]]
[status-im.accounts.login.screen :refer [login]]
@ -89,7 +88,6 @@
(let [current-view (validate-current-view @view-id @signed-up?)]
(let [component (case current-view
:discovery main-tabs
:discovery-tag discovery-tag
:discovery-search-results discovery-search-results
:add-participants new-participants
:remove-participants remove-participants

View File

@ -18,6 +18,22 @@
:additional-height 0}
:chat {:new-message {:border-top-color styles/color-transparent
:border-top-width 0.5}}
:discovery {:subtitle {:color styles/color-gray2
:font-size 14}
:popular {:border-radius 1
:margin-top 2
:margin-bottom 4
:margin-right 2
:elevation 3}
:tag {:flex-direction "column"
:background-color "#7099e619"
:border-radius 5
:padding 4}
:item {:status-text {:color styles/color-black
:line-height 22
:font-size 14}}}
:contacts {:subtitle {:color styles/color-gray2
:font-size 14}}
:bottom-gradient {:height 3}
:input-label {:left 4}
:input-error-text {:margin-left 4}
@ -58,4 +74,7 @@
:chats {:action-button? true
:new-chat-in-toolbar? false}
:contacts {:action-button? true
:new-contact-in-toolbar? false}})
:new-contact-in-toolbar? false
:uppercase-subtitles? false
:group-block-shadows? true}
:discovery {:uppercase-subtitles? false}})

View File

@ -393,10 +393,12 @@
(register-handler :start-chat
(u/side-effect!
(fn [{:keys [chats]} [_ contact-id options navigation-type]]
(if (chats contact-id)
(dispatch [(or navigation-type :navigate-to) :chat contact-id])
(dispatch [::start-chat! contact-id options navigation-type])))))
(fn [{:keys [chats current-public-key]}
[_ contact-id options navigation-type]]
(when-not (= current-public-key contact-id)
(if (chats contact-id)
(dispatch [(or navigation-type :navigate-to) :chat contact-id])
(dispatch [::start-chat! contact-id options navigation-type]))))))
(register-handler :add-chat
(u/side-effect!

View File

@ -39,6 +39,12 @@
:font :default}
name]])
(defn clean-text [s]
(-> s
(str/replace #"\n" " ")
(str/replace #"\r" "")
(str/trim)))
(defn drawer-menu []
(let
[account (subscribe [:get-current-account])
@ -65,7 +71,7 @@
:value name
:on-change-text #(dispatch [:set-in [:profile-edit :name] %])
:on-end-editing #(when (and new-name (not (str/blank? new-name)))
(dispatch [:account-update {:name new-name}]))}]]
(dispatch [:account-update {:name (clean-text new-name)}]))}]]
[view st/status-container
[text-input {:style st/status-input
:editable true
@ -77,8 +83,8 @@
:on-change-text #(dispatch [:set-in [:profile-edit :status] %])
:on-blur (fn []
(when (and new-status (not (str/blank? new-status)))
(dispatch [:check-status-change new-status])
(dispatch [:account-update {:status new-status}])))
(dispatch [:check-status-change (clean-text new-status)])
(dispatch [:account-update {:status (clean-text new-status)}])))
:default-value status}]]
[view st/menu-items-container
[menu-item {:name (label :t/profile)

View File

@ -54,16 +54,18 @@
(defn text
([t]
(r/as-element [text-class t]))
([{:keys [style font] :as opts
:or {font :default}} t & other]
([{:keys [style font uppercase?] :as opts
:or {font :default}} t & ts]
(r/as-element
(let [font (get-in platform-specific [:fonts font])]
(let [font (get-in platform-specific [:fonts font])
ts (cond->> (conj ts t)
uppercase? (map clojure.string/upper-case))]
(vec (concat
[text-class
(-> opts
(dissoc :font)
(assoc :style (merge style font)))]
(conj other t)))))))
ts))))))
(defn text-input [props text]
[text-input-class (merge

View File

@ -5,6 +5,7 @@
[reagent.core :as r]
[status-im.components.selectable-field.styles :as st]
[status-im.i18n :refer [label]]
[status-im.utils.platform :as p]
[taoensso.timbre :as log]))
(defn- on-press
@ -41,7 +42,7 @@
[text-input {:style (st/sized-text full-height)
:multiline true
:selectTextOnFocus true
:editable editable?
:editable (if p/android? true editable?)
:auto-focus true
:on-selection-change #(on-selection-change % component)
:on-focus #(log/debug "Focused" %)

View File

@ -8,6 +8,7 @@
(def color-gray "#838c93de")
(def color-gray2 "#8f838c93")
(def color-gray3 "#00000040")
(def color-steel "#838b91")
(def color-white "white")
(def color-light-blue-transparent "#bbc4cb32")
(def color-light-gray "#EEF2F5")

View File

@ -22,7 +22,7 @@
:height toolbar-height})
(defn toolbar-nav-actions-container [actions]
{:width (if (and actions (> (count actions) 0))
{:width (when (and actions (> (count actions) 0))
(-> (+ toolbar-icon-width toolbar-icon-spacing)
(* (count actions))
(+ toolbar-icon-spacing)))
@ -45,9 +45,12 @@
:color text1-color
:font-size 16})
(def toolbar-actions-container
{:flex-direction "row"
:margin-left 8})
(defn toolbar-actions-container [actions-count custom]
(merge {:flex-direction "row"
:margin-left toolbar-icon-spacing}
(when (and (= actions-count 0)
(not custom))
{:width (+ toolbar-icon-width toolbar-icon-spacing)})))
(def toolbar-action
{:width toolbar-icon-width

View File

@ -11,14 +11,14 @@
[status-im.components.toolbar.styles :as st]
[status-im.utils.platform :refer [platform-specific]]))
(defn toolbar [{title :title
nav-action :nav-action
hide-nav? :hide-nav?
actions :actions
custom-action :custom-action
background-color :background-color
custom-content :custom-content
style :style}]
(defn toolbar [{title :title
nav-action :nav-action
hide-nav? :hide-nav?
actions :actions
custom-action :custom-action
background-color :background-color
custom-content :custom-content
style :style}]
(let [style (merge (st/toolbar-wrapper background-color) style)]
[view {:style style}
[view st/toolbar
@ -38,7 +38,7 @@
[text {:style st/toolbar-title-text
:font :toolbar-title}
title]])
[view st/toolbar-actions-container
[view (st/toolbar-actions-container (count actions) (or custom-content custom-action))
(if actions
(for [{action-image :image
action-handler :handler} actions]

View File

@ -205,7 +205,8 @@
(dispatch [:update-chat! {:chat-id chat-id
:contact-info nil
:pending-contact? false}])
(dispatch [:watch-contact contact])))))
(dispatch [:watch-contact contact])
(dispatch [:discoveries-send-portions chat-id])))))
(defn set-contact-identity-from-qr
[db [_ _ contact-identity]]
@ -215,21 +216,21 @@
(register-handler :contact-update-received
(u/side-effect!
(fn [{:keys [chats] :as db} [_ {:keys [from payload]}]]
(let [{:keys [content timestamp]} payload
{:keys [status name profile-image]} (:profile content)
prev-last-updated (get-in db [:contacts from :last-updated])]
(if (<= prev-last-updated timestamp)
(let [contact {:whisper-identity from
:name name
:photo-path profile-image
:status status
:last-updated timestamp}]
(dispatch [:check-status! contact payload])
(dispatch [:update-contact! contact])
(when (chats from)
(dispatch [:update-chat! {:chat-id from
:name name}]))))))))
(fn [{:keys [chats current-public-key] :as db} [_ {:keys [from payload]}]]
(when (not= current-public-key from)
(let [{:keys [content timestamp]} payload
{:keys [status name profile-image]} (:profile content)
prev-last-updated (get-in db [:contacts from :last-updated])]
(if (<= prev-last-updated timestamp)
(let [contact {:whisper-identity from
:name name
:photo-path profile-image
:status status
:last-updated timestamp}]
(dispatch [:update-contact! contact])
(when (chats from)
(dispatch [:update-chat! {:chat-id from
:name name}])))))))))
(register-handler :contact-online-received
(u/side-effect!

View File

@ -27,7 +27,9 @@
[status-im.i18n :refer [label]]
[status-im.utils.platform :refer [platform-specific]]))
(defn contact-list-toolbar []
(def contacts-limit 50)
(defn toolbar-view []
(let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])
actions (cond->> [{:image {:source {:uri :icon_search}
:style icon-search}
@ -44,35 +46,57 @@
:style {:elevation 0}
:actions actions}]))
(def contacts-limit 10)
(defn subtitle-view [subtitle contacts-count]
[view st/contact-group-header-inner
[text {:style (merge st/contact-group-subtitle
(get-in platform-specific [:component-styles :contacts :subtitle]))
:uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?])
:font :medium}
subtitle]
[text {:style (merge st/contact-group-count
(get-in platform-specific [:component-styles :contacts :subtitle]))
:uppercase? (get-in platform-specific [:contacts :uppercase-subtitles?])
:font :medium}
(str contacts-count)]])
(defn contact-group [contacts contacts-count title group top? click-handler]
[view st/contact-group
[view st/contact-group-header
(when-not top?
[linear-gradient {:style st/contact-group-header-gradient-top
:colors st/contact-group-header-gradient-top-colors}])
[view st/contact-group-header-inner
[text {:style st/contact-group-text} title]
[text {:style st/contact-group-size-text} (str contacts-count)]]
[linear-gradient {:style st/contact-group-header-gradient-bottom
:colors st/contact-group-header-gradient-bottom-colors}]]
;; todo what if there is no contacts, should we show some information
;; about this?
[view {:flexDirection :column}
(doall
;; TODO not imlemented: contact more button handler
(map (fn [contact]
(let [whisper-identity (:whisper-identity contact)
click-handler (or click-handler on-press)]
^{:key contact}
[contact-extended-view contact nil (click-handler whisper-identity) nil]))
contacts))]
(when (<= contacts-limit (count contacts))
[view st/show-all
[touchable-highlight {:on-press #(dispatch [:navigate-to :group-contacts group])}
[view
[text {:style st/show-all-text} (label :t/show-all)]]]])])
(defn group-top-view []
[linear-gradient {:style st/contact-group-header-gradient-bottom
:colors st/contact-group-header-gradient-bottom-colors}])
(defn group-bottom-view []
[linear-gradient {:style st/contact-group-header-gradient-top
:colors st/contact-group-header-gradient-top-colors}])
(defn line-view []
[view {:style {:background-color "#D7D7D7"
:height 1}}])
(defn contact-group-view [contacts contacts-count subtitle group click-handler]
(let [shadows? (get-in platform-specific [:contacts :group-block-shadows?])]
[view st/contact-group
[view st/contact-group-header
[subtitle-view subtitle contacts-count]]
(if shadows?
[group-top-view]
[line-view])
[view
(doall
(map (fn [contact]
(let [whisper-identity (:whisper-identity contact)
click-handler (or click-handler on-press)]
^{:key contact}
[contact-extended-view contact nil (click-handler whisper-identity) nil]))
contacts))]
(when (<= contacts-limit (count contacts))
[view st/show-all
[touchable-highlight {:on-press #(dispatch [:navigate-to :group-contacts group])}
[view
[text {:style st/show-all-text
:font :medium}
(label :t/show-all)]]]])
(if shadows?
[group-bottom-view]
[line-view])]))
(defn contacts-action-button []
[view st/buttons-container
@ -97,7 +121,7 @@
show-toolbar-shadow? (r/atom false)]
(fn []
[view st/contacts-list-container
[contact-list-toolbar]
[toolbar-view]
[view {:style st/toolbar-shadow}
(when @show-toolbar-shadow?
[linear-gradient {:style st/contact-group-header-gradient-bottom
@ -108,18 +132,18 @@
(let [offset (.. e -nativeEvent -contentOffset -y)]
(reset! show-toolbar-shadow? (<= st/contact-group-header-height offset))))}
(when (pos? @dapps-count)
[contact-group
[contact-group-view
@dapps
@dapps-count
(label :t/contacts-group-dapps)
:dapps true
:dapps
@click-handler])
(when (pos? @people-count)
[contact-group
[contact-group-view
@peoples
@people-count
(label :t/contacts-group-people)
:people false
:people
@click-handler])]
[view st/empty-contact-groups
[react/icon :group_big st/empty-contacts-icon]

View File

@ -18,13 +18,13 @@
:backgroundColor toolbar-background2})
(def contact-groups
{:flex 1
:backgroundColor toolbar-background2})
{:flex 1
:background-color toolbar-background2})
(def empty-contact-groups
(merge contact-groups
{:align-items :center
:padding-top 150}))
{:align-items :center
:justify-content :center}))
(def empty-contacts-icon
{:height 62
@ -39,11 +39,11 @@
{:backgroundColor color-white})
(def contact-group
{:flexDirection :column})
{:flex-direction :column})
(def contact-group-header
{:flexDirection :column
:backgroundColor toolbar-background2})
{:flex-direction :column
:background-color toolbar-background2})
(def contact-group-header-inner
{:flexDirection :row
@ -51,16 +51,12 @@
:height 48
:backgroundColor toolbar-background2})
(def contact-group-text
(def contact-group-subtitle
{:flex 1
:marginLeft 16
:fontSize 14
:color text5-color})
:margin-left 16})
(def contact-group-size-text
{:marginRight 14
:fontSize 12
:color text2-color})
(def contact-group-count
{:margin-right 14})
(def contact-group-header-gradient-top
{:flexDirection :row

View File

@ -1,7 +1,8 @@
(ns status-im.contacts.subs
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub subscribe]]
[status-im.utils.identicon :refer [identicon]]))
[status-im.utils.identicon :refer [identicon]]
[taoensso.timbre :as log]))
(register-sub :get-contacts
(fn [db _]
@ -19,7 +20,7 @@
(register-sub :all-added-contacts
(fn [db _]
(let [contacts (reaction (:contacts @db))]
(->> (remove :pending @contacts)
(->> (remove #(true? (:pending (second %))) @contacts)
(sort-contacts)
(reaction)))))

View File

@ -16,7 +16,12 @@
(let [{pending-db :pending
:as contact-db} (data-store/get-by-id whisper-identity)
contact (assoc contact :pending (boolean (if contact-db
(and pending-db pending)
;; TODO:
;; this is temporary fix for pending users
;; we need to change this (if ...) to (and pending-db pending)
(if (nil? pending)
pending-db
(and pending-db pending))
pending)))]
(data-store/save contact (if contact-db true false))))

View File

@ -2,14 +2,18 @@
(:require [status-im.data-store.realm.discovery :as data-store]))
(defn get-all
[]
(->> (data-store/get-all-as-list)
[ordering]
(->> (data-store/get-all-as-list ordering)
(mapv #(update % :tags vals))))
(defn save
[discovery]
(data-store/save discovery))
(defn exists?
[message-id]
(data-store/exists? message-id))
(defn save-all
[discoveries]
(data-store/save-all discoveries))

View File

@ -1,15 +1,16 @@
(ns status-im.data-store.realm.discovery
(:require [status-im.data-store.realm.core :as realm]
[taoensso.timbre :as log]))
[taoensso.timbre :as log])
(:refer-clojure :exclude [exists?]))
(defn get-all
[]
[ordering]
(-> (realm/get-all @realm/account-realm :discovery)
(realm/sorted :priority :desc)))
(realm/sorted :created-at ordering)))
(defn get-all-as-list
[]
(-> (get-all)
[ordering]
(-> (get-all ordering)
realm/realm-collection->list))
(defn get-tag-by-name [tag]
@ -38,11 +39,15 @@
(defn- upsert-discovery [{:keys [message-id tags] :as discovery}]
(log/debug "Creating/updating discovery with tags: " tags)
(let [prev-tags (get-tags message-id)]
(if prev-tags
(when prev-tags
(update-tags-counter dec prev-tags))
(realm/create @realm/account-realm :discovery discovery true)
(update-tags-counter inc tags)))
(defn exists?
[message-id]
(realm/exists? @realm/account-realm :discovery {:message-id message-id}))
(defn save
[discovery]
(realm/write @realm/account-realm

View File

@ -3,6 +3,7 @@
[status-im.data-store.realm.schemas.account.v2.core :as v2]
[status-im.data-store.realm.schemas.account.v3.core :as v3]
[status-im.data-store.realm.schemas.account.v4.core :as v4]
[status-im.data-store.realm.schemas.account.v5.core :as v5]
))
; put schemas ordered by version
@ -17,4 +18,7 @@
:migration v3/migration}
{:schema v4/schema
:schemaVersion 4
:migration v4/migration}])
:migration v4/migration}
{:schema v5/schema
:schemaVersion 5
:migration v5/migration}])

View File

@ -25,5 +25,4 @@
user-status/schema])
(defn migration [old-realm new-realm]
(log/debug "migrating v2 account database: " old-realm new-realm)
(contact/migration old-realm new-realm))
(log/debug "migrating v2 account database: " old-realm new-realm))

View File

@ -25,5 +25,4 @@
user-status/schema])
(defn migration [old-realm new-realm]
(log/debug "migrating v3 account database: " old-realm new-realm)
(contact/migration old-realm new-realm))
(log/debug "migrating v3 account database: " old-realm new-realm))

View File

@ -0,0 +1,28 @@
(ns status-im.data-store.realm.schemas.account.v5.core
(:require [taoensso.timbre :as log]
[status-im.data-store.realm.schemas.account.v4.chat :as chat]
[status-im.data-store.realm.schemas.account.v3.message :as message]
[status-im.data-store.realm.schemas.account.v2.contact :as contact]
[status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact]
[status-im.data-store.realm.schemas.account.v1.command :as command]
[status-im.data-store.realm.schemas.account.v5.discovery :as discovery]
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
[status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message]
[status-im.data-store.realm.schemas.account.v1.request :as request]
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]))
(def schema [chat/schema
chat-contact/schema
command/schema
contact/schema
discovery/schema
kv-store/schema
message/schema
pending-message/schema
request/schema
tag/schema
user-status/schema])
(defn migration [old-realm new-realm]
(log/debug "migrating v5 account database: " old-realm new-realm))

View File

@ -0,0 +1,16 @@
(ns status-im.data-store.realm.schemas.account.v5.discovery
(:require [taoensso.timbre :as log]))
(def schema {:name :discovery
:primaryKey :message-id
:properties {:message-id "string"
:name {:type "string" :optional true}
:status "string"
:whisper-id "string"
:photo-path {:type "string" :optional true}
:tags {:type "list"
:objectType "tag"}
:created-at {:type "int" :default 0}}})
(defn migration [old-realm new-realm]
(log/debug "migrating discovery schema"))

View File

@ -19,7 +19,7 @@
:new-contact-identity ""
:contacts {}
:discoveries []
:discoveries {}
:discovery-search-tags []
:tags {}

View File

@ -5,103 +5,117 @@
[status-im.protocol.core :as protocol]
[status-im.navigation.handlers :as nav]
[status-im.data-store.discovery :as discoveries]
[status-im.data-store.contacts :as contacts]
[status-im.utils.handlers :as u]
[status-im.utils.datetime :as time]
[status-im.utils.random :as random]
[status-im.data-store.contacts :as contacts]))
[status-im.utils.random :as random]))
(def request-discoveries-interval-s 600)
(register-handler :init-discoveries
(fn [db _]
(-> db
(assoc :discoveries []))))
(assoc :tags [])
(assoc :discoveries {}))))
(defn calculate-priority [{:keys [chats contacts]} from payload]
(let [contact (get contacts from)
chat (get chats from)
seen-online-recently? (< (- (time/now-ms) (get contact :last-online))
time/hour)]
(+ (time/now-ms) ;; message is newer => priority is higher
(if contact time/day 0) ;; user exists in contact list => increase priority
(if chat time/day 0) ;; chat with this user exists => increase priority
(if seen-online-recently? time/hour 0) ;; the user was online recently => increase priority
)))
(defn identities [contacts]
(->> (map second contacts)
(remove (fn [{:keys [dapp? pending]}]
(or pending dapp?)))
(map :whisper-identity)))
(defmethod nav/preload-data! :discovery
[{:keys [discoveries] :as db} _]
[db _]
(-> db
(assoc :tags (discoveries/get-all-tags))
;; todo add limit
;; todo hash-map with whisper-id as key and sorted by last-update
;; may be more efficient here
(assoc :discoveries (discoveries/get-all))))
(register-handler :discovery-response-received
(u/side-effect!
(fn [db [_ {:keys [from payload]}]]
(let [{:keys [discovery-id profile hashtags]} payload
{:keys [name profile-image status]} profile
discovery {:message-id discovery-id
:name name
:photo-path profile-image
:status status
:whisper-id from
:tags (map #(hash-map :name %) hashtags)
:last-updated (js/Date.)
:priority (calculate-priority db from payload)}]
(dispatch [:add-discovery discovery])))))
(register-handler :check-status!
(u/side-effect!
(fn [db [_ {:keys [whisper-identity status]} payload]]
(let [{old-status :status} (contacts/get-by-id whisper-identity)]
(when (not= old-status status)
(let [hashtags (get-hashtags status)]
(when-not (empty? hashtags)
(let [{:keys [message-id content]} payload
{:keys [name profile-image status]} (content :profile)
discovery {:message-id message-id
:name name
:photo-path profile-image
:status status
:whisper-id whisper-identity
:tags (map #(hash-map :name %) hashtags)
:last-updated (js/Date.)
:priority (calculate-priority db whisper-identity payload)}]
(dispatch [:add-discovery discovery])))))))))
(assoc :discoveries (->> (discoveries/get-all :desc)
(map (fn [{:keys [message-id] :as discovery}]
[message-id discovery]))
(into {})))))
(register-handler :broadcast-status
(u/side-effect!
(fn [{:keys [current-public-key web3 current-account-id accounts]}
(fn [{:keys [current-public-key web3 current-account-id accounts contacts]}
[_ status hashtags]]
(let [{:keys [name photo-path]} (get accounts current-account-id)]
(protocol/broadcats-discoveries!
{:web3 web3
:hashtags (set hashtags)
:message {:from current-public-key
:message-id (random/id)
:payload {:status status
:profile {:name name
:status status
:profile-image photo-path}}}})
(protocol/watch-hashtags! {:web3 web3
:hashtags (set hashtags)
:callback #(dispatch [:incoming-message %1 %2])})))))
(let [{:keys [name photo-path]} (get accounts current-account-id)
message-id (random/id)
message {:message-id message-id
:from current-public-key
:payload {:message-id message-id
:status status
:hashtags (vec hashtags)
:profile {:name name
:profile-image photo-path}}}]
(doseq [id (identities contacts)]
(protocol/send-status!
{:web3 web3
:message (assoc message :to id)}))
(dispatch [:status-received message])))))
(register-handler :show-discovery-tag
(fn [db [_ tag]]
(dispatch [:navigate-to :discovery-tag])
(assoc db :current-tag tag)))
(register-handler :status-received
(u/side-effect!
(fn [{:keys [discoveries] :as db} [_ {:keys [from payload]}]]
(when (and (not (discoveries/exists? (:message-id payload)))
(not (get discoveries (:message-id payload))))
(let [{:keys [message-id status hashtags profile]} payload
{:keys [name profile-image]} profile
discovery {:message-id message-id
:name name
:photo-path profile-image
:status status
:whisper-id from
:tags (map #(hash-map :name %) hashtags)
:created-at (time/now-ms)}]
(dispatch [:add-discovery discovery]))))))
(register-handler :start-requesting-discoveries
(fn [{:keys [request-discoveries-timer] :as db}]
(when request-discoveries-timer
(js/clearInterval request-discoveries-timer))
(dispatch [:request-discoveries])
(assoc db :request-discoveries-timer
(js/setInterval #(dispatch [:request-discoveries])
(* request-discoveries-interval-s 1000)))))
(register-handler :request-discoveries
(u/side-effect!
(fn [{:keys [current-public-key web3 contacts]}]
(doseq [id (identities contacts)]
(when-not (protocol/message-pending? web3 :discoveries-request id)
(protocol/send-discoveries-request!
{:web3 web3
:message {:from current-public-key
:to id
:message-id (random/id)}}))))))
(register-handler :discoveries-send-portions
(u/side-effect!
(fn [{:keys [current-public-key contacts web3]} [_ to]]
(when (get contacts to)
(protocol/send-discoveries-response!
{:web3 web3
:discoveries (discoveries/get-all :asc)
:message {:from current-public-key
:to to}})))))
(register-handler :discoveries-request-received
(u/side-effect!
(fn [_ [_ {:keys [from]}]]
(dispatch [:discoveries-send-portions from]))))
(register-handler :discoveries-response-received
(u/side-effect!
(fn [{:keys [discoveries contacts]} [_ {:keys [payload from]}]]
(when (get contacts from)
(when-let [data (:data payload)]
(doseq [{:keys [message-id] :as discovery} data]
(when (and (not (discoveries/exists? message-id))
(not (get discoveries message-id)))
(let [discovery (assoc discovery :created-at (time/now-ms))]
(dispatch [:add-discovery discovery])))))))))
(defn add-discovery
[{db-discoveries :discoveries
:as db} [_ {:keys [message-id] :as discovery}]]
(let [updated-discoveries (if-let [i (first-index #(= (:message-id %) message-id) db-discoveries)]
(assoc db-discoveries i discovery)
(conj db-discoveries discovery))]
(-> db
(assoc :new-discovery discovery)
(assoc :discoveries updated-discoveries))))
[db [_ discovery]]
(assoc db :new-discovery discovery))
(defn save-discovery!
[{:keys [new-discovery]} _]
@ -109,7 +123,11 @@
(defn reload-tags!
[db _]
(assoc db :tags (discoveries/get-all-tags)))
(assoc db :tags (discoveries/get-all-tags)
:discoveries (->> (discoveries/get-all :desc)
(map (fn [{:keys [message-id] :as discovery}]
[message-id discovery]))
(into {}))))
(register-handler :add-discovery
(-> add-discovery
@ -120,4 +138,4 @@
:remove-old-discoveries!
(u/side-effect!
(fn [_ _]
(discoveries/delete :priority :asc 1000 200))))
(discoveries/delete :created-at :asc 1000 200))))

View File

@ -16,7 +16,8 @@
[status-im.components.carousel.carousel :refer [carousel]]
[status-im.discovery.views.popular-list :refer [discovery-popular-list]]
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]
[status-im.contacts.styles :as contacts-styles]))
[status-im.contacts.styles :as contacts-styles]
[status-im.utils.platform :refer [platform-specific]]))
(defn get-hashtags [status]
(let [hashtags (map #(str/lower-case (str/replace % #"#" "")) (re-seq #"[^ !?,;:.]+" status))]
@ -35,7 +36,7 @@
(dispatch [:navigate-to :discovery-search-results])))}]
[view
[text {:style st/discovery-title
:font :default}
:font :toolbar-title}
(label :t/discovery)]])])
(defn toogle-search [current-value]
@ -52,46 +53,51 @@
:style st/search-icon}
:handler #(toogle-search show-search?)}]}])
(defn title [label-kw]
(defn title [label-kw spacing?]
[view st/section-spacing
[text {:style st/discovery-subtitle
:font :medium}
[text {:style (merge (get-in platform-specific [:component-styles :discovery :subtitle])
(when spacing? {:margin-top 16}))
:uppercase? (get-in platform-specific [:discovery :uppercase-subtitles?])
:font :medium}
(label label-kw)]])
(defview discovery-popular [{:keys [contacts]}]
[popular-tags [:get-popular-tags 10]]
(if (seq popular-tags)
[view
[title :t/popular-tags]
(if (pos? (count popular-tags))
[carousel {:pageStyle st/carousel-page-style}
(for [{:keys [name count]} popular-tags]
[discovery-popular-list {:tag name
:count count
:contacts contacts}])]
[text (label :t/none)])]
[view contacts-styles/empty-contact-groups
;; todo change icon
[icon :group_big contacts-styles/empty-contacts-icon]
[text {:style contacts-styles/empty-contacts-text}
(label :t/no-statuses-discovered)]]))
[view st/popular-container
[title :t/popular-tags false]
(if (pos? (count popular-tags))
[carousel {:pageStyle st/carousel-page-style
:gap 0
:sneak (if (> (count popular-tags) 1) 16 8)}
(for [{:keys [name]} popular-tags]
[discovery-popular-list {:tag name
:contacts contacts}])]
[text (label :t/none)])])
(defview discovery-recent [{:keys [contacts]}]
[discoveries [:get :discoveries]]
[discoveries [:get-recent-discoveries]]
(when (seq discoveries)
[view
[title :t/recent]
[view st/recent-container
[title :t/recent true]
[view st/recent-list
(for [{:keys [message-id] :as discovery} discoveries]
^{:key (str "message-" message-id)}
[discovery-list-item discovery])]]))
(let [discoveries (map-indexed vector discoveries)]
(for [[i {:keys [message-id] :as discovery}] discoveries]
^{:key (str "message-" message-id)}
[discovery-list-item discovery (not= (inc i) (count discoveries))]))]]))
(defview discovery []
[show-search? [:get ::show-search?]
contacts [:get :contacts]]
contacts [:get :contacts]
discoveries [:get-recent-discoveries]]
[view st/discovery-container
[discovery-toolbar show-search?]
[scroll-view st/scroll-view-container
[discovery-popular {:contacts contacts}]
[discovery-recent {:contacts contacts}]]
(if discoveries
[scroll-view st/scroll-view-container
[discovery-popular {:contacts contacts}]
[discovery-recent {:contacts contacts}]]
[view contacts-styles/empty-contact-groups
;; todo change icon
[icon :group_big contacts-styles/empty-contacts-icon]
[text {:style contacts-styles/empty-contacts-text}
(label :t/no-statuses-discovered)]])
[bottom-gradient]])

View File

@ -2,39 +2,59 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.components.react :refer [view text list-view list-item]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.react :refer [view
text
icon
list-view
list-item
scroll-view]]
[status-im.i18n :refer [label]]
[status-im.components.toolbar.view :refer [toolbar]]
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]
[status-im.discovery.styles :as st]))
[status-im.discovery.styles :as st]
[status-im.utils.platform :refer [platform-specific]]
[status-im.contacts.styles :as contacts-styles]
[taoensso.timbre :as log]))
(defn render-separator [_ row-id _]
(list-item [view {:style st/row-separator
:key row-id}]))
(defn title-content [tags]
[view st/tag-title-container
(for [tag (take 3 tags)]
^{:key (str "tag-" tag)}
[view {:style st/tag-container}
[text {:style st/tag-title
:font :default}
(str " #" tag)]])])
[scroll-view {:horizontal true
:bounces false
:flex 1
:contentContainerStyle st/tag-title-scroll}
[view st/tag-title-container
(for [tag (take 3 tags)]
^{:key (str "tag-" tag)}
[view (merge (get-in platform-specific [:component-styles :discovery :tag])
{:margin-left 2 :margin-right 2})
[text {:style st/tag-title
:font :default}
(str " #" tag)]])]])
(defview discovery-search-results []
[discoveries [:get-discovery-search-results]
[discoveries [:get-popular-discoveries 250]
tags [:get :discovery-search-tags]]
(let [datasource (to-datasource discoveries)]
(let [discoveries (:discoveries discoveries)
datasource (to-datasource discoveries)]
[view st/discovery-tag-container
[status-bar]
[toolbar {:nav-action {:image {:source {:uri :icon_back}
:style st/icon-back}
:handler #(dispatch [:navigate-back])}
:custom-content (title-content tags)
:actions [{:image {:source {:uri :icon_search}
:style st/icon-search}
:handler (fn [])}]}]
[list-view {:dataSource datasource
:renderRow (fn [row _ _]
(list-item [discovery-list-item row]))
:renderSeparator render-separator
:style st/recent-list}]]))
:style st/discovery-tag-toolbar}]
(if (empty? discoveries)
[view st/empty-view
;; todo change icon
[icon :group_big contacts-styles/empty-contacts-icon]
[text {:style contacts-styles/empty-contacts-text}
(label :t/no-statuses-found)]]
[list-view {:dataSource datasource
:renderRow (fn [row _ _]
(list-item [discovery-list-item row]))
:renderSeparator render-separator
:style st/recent-list}])]))

View File

@ -1,5 +1,7 @@
(ns status-im.discovery.styles
(:require [status-im.components.styles :refer [color-gray2]]))
(:require [status-im.components.styles :refer [color-gray2
color-white]]
[status-im.components.toolbar.styles :refer [toolbar-background2]]))
;; common
@ -8,11 +10,18 @@
:border-bottom-color "#eff2f3"})
(def row
{:flex-direction :row})
{:flex-direction :row
:margin-bottom 10})
(def column
{:flex-direction :column})
(def empty-view
{:flex 1
:background-color color-white
:align-items :center
:justify-content :center})
;; Toolbar
(def discovery-toolbar-content
@ -21,7 +30,7 @@
:justify-content :center})
(def discovery-toolbar
{:background-color "#eef2f5"
{:background-color toolbar-background2
:elevation 0})
(def discovery-search-input
@ -30,7 +39,7 @@
:margin-left 18
:line-height 42
:font-size 14
:color "#9CBFC0"})
:color "#7099e6"})
(def discovery-title
{:color "#000000de"
@ -38,25 +47,19 @@
:text-align :center
:font-size 16})
(def discovery-subtitle
{:color color-gray2
:font-size 14})
(def section-spacing
{:padding 16})
(def scroll-view-container
{})
{:bounces false})
;; Popular
(def popular-container
{:background-color toolbar-background2})
(def carousel-page-style
{:borderRadius 1
:shadowColor "black"
:shadowRadius 1
:shadowOpacity 0.8
:elevation 2
:marginBottom 10})
{})
(def tag-name
{:color "#7099e6"
@ -66,16 +69,10 @@
:align-items :center
:justify-content :center})
(def tag-name-container
{:flex-direction "column"
:background-color "#eef2f5"
:border-radius 5
:padding 4})
(def tag-count
{:color "#838c93"
:font-size 12
:padding-right 5
:padding-right 6
:padding-bottom 2
:align-items :center
:justify-content :center})
@ -84,63 +81,67 @@
{:flex 0.2
:flex-direction "column"
:align-items "flex-end"
:padding-top 10
:padding-top 6
:padding-right 9})
(def separator
{:background-color "rgb(200, 199, 204)"
:height 0.5})
;; Popular list item
(def popular-list-container
{:flex 1
:background-color :white
:padding-left 10
:padding-top 16})
(def popular-list
{:background-color :white
:padding-top 13})
;; Popular list item
:margin-left 16
:padding-left 16
:padding-top 18})
(def popular-list-item
{:flex-direction :row
:padding-top 10
:padding-bottom 10})
(def popular-list-item-status
{:color "black"
:line-height 22
:font-size 14})
:padding-bottom 16
:top 1})
(def popular-list-item-name
{:color "black"
:font-size 14
:line-height 24})
{:color "black"
:font-size 15
:padding-bottom 4})
(def popular-list-item-name-container
{:flex 0.8
:flex-direction "column"})
:flex-direction "column"
:padding-top 16})
(def popular-list-item-avatar-container
{:flex 0.2
:flex-direction "column"
:align-items :center
:padding-top 5})
(def popular-list-item-avatar
{:border-radius 18
:width 36
:height 36})
:padding-top 16})
;; discovery_recent
(def recent-container
{:background-color toolbar-background2})
(def recent-list
{:background-color :white
:padding-left 16})
;; Discovery tag
(def discovery-tag-toolbar
{:border-bottom-color "#D7D7D7"
:border-bottom-width 1})
(def discovery-tag-container
{:flex 1
:backgroundColor "#eef2f5"})
(def tag-title-scroll
{:flex 1
:alignItems "center"
:justifyContent "center"})
(def tag-title-container
{:flex 1
:alignItems "center"
@ -153,14 +154,6 @@
:padding-right 5
:padding-bottom 2})
(def tag-container
{:backgroundColor "#eef2f5"
:flexWrap :wrap
:borderRadius 5
:padding 4
:margin-left 2
:margin-right 2})
(def icon-back
{:width 8
:height 14})
@ -171,7 +164,7 @@
(def discovery-container
{:flex 1
:backgroundColor :#eef2f5})
:backgroundColor color-white})
(def hamburger-icon
{:width 16

View File

@ -1,21 +1,44 @@
(ns status-im.discovery.subs
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub]]))
(:require [re-frame.core :refer [register-sub]]
[status-im.utils.datetime :as time]))
(defn- get-discoveries-by-tags [{:keys [discoveries current-tag]} tags limit]
(let [tags' (or tags [current-tag])
filter-tag (filter #(every? (->> (map :name (:tags %))
(into (hash-set)))
tags'))
xform (if limit
(comp filter-tag (take limit))
filter-tag)]
(into [] xform discoveries)))
(defn- calculate-priority [{:keys [chats contacts current-public-key]}
{:keys [whisper-id created-at]}]
(let [contact (get contacts whisper-id)
chat (get chats whisper-id)
seen-online-recently? (< (- (time/now-ms) (get contact :last-online))
time/hour)
me? (= current-public-key whisper-id)]
(+ created-at ;; message is newer => priority is higher
(if (or me? contact) time/day 0) ;; user exists in contact list => increase priority
(if (or me? chat) time/day 0) ;; chat with this user exists => increase priority
(if (or me? seen-online-recently?) time/hour 0) ;; the user was online recently => increase priority
)))
(register-sub :get-discoveries-by-tags
(fn [db [_ tags limit]]
(-> (get-discoveries-by-tags @db tags limit)
(reaction))))
(defn- get-discoveries-by-tags [discoveries current-tag tags]
(let [tags' (or tags [current-tag])]
(filter #(every? (->> (map :name (:tags %))
(into (hash-set)))
tags')
(vals discoveries))))
(register-sub :get-popular-discoveries
(fn [db [_ limit tags]]
(let [discoveries (reaction (:discoveries @db))
current-tag (reaction (:current-tag @db))
search-tags (reaction (:discovery-search-tags @db))
discoveries (->> (get-discoveries-by-tags @discoveries @current-tag (or tags @search-tags))
(map #(assoc % :priority (calculate-priority db %)))
(sort-by :priority >))]
(reaction {:discoveries (take limit discoveries)
:total (count discoveries)}))))
(register-sub :get-recent-discoveries
(fn [db]
(->> (:discoveries @db)
(vals)
(reaction))))
(register-sub :get-popular-tags
(fn [db [_ limit]]
@ -24,6 +47,8 @@
(register-sub :get-discovery-search-results
(fn [db _]
(let [tags (get-in @db [:discovery-search-tags])]
(-> (get-discoveries-by-tags @db tags nil)
(let [discoveries (reaction (:discoveries @db))
current-tag (reaction (:current-tag @db))
tags (reaction (:discovery-search-tags @db))]
(-> (get-discoveries-by-tags @discoveries @current-tag @tags)
(reaction)))))

View File

@ -1,36 +0,0 @@
(ns status-im.discovery.tag
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.components.react :refer [view text list-view list-item]]
[status-im.components.toolbar.view :refer [toolbar]]
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]
[status-im.discovery.styles :as st]))
(defn render-separator [_ row-id _]
(list-item [view {:style st/row-separator
:key row-id}]))
(defn title-content [tag]
[view st/tag-title-container
[view {:style st/tag-container}
[text {:style st/tag-title} (str " #" tag)]]])
(defview discovery-tag []
[tag [:get :current-tag]
discoveries [:get-discoveries-by-tags]]
(let [datasource (to-datasource discoveries)]
[view st/discovery-tag-container
[toolbar {:nav-action {:image {:source {:uri :icon_back}
:style st/icon-back}
:handler #(dispatch [:navigate-back])}
:custom-content (title-content tag)
:actions [{:image {:source {:uri :icon_search}
:style st/icon-search}
:handler (fn [])}]}]
[list-view {:dataSource datasource
:renderRow (fn [row _ _]
(list-item [discovery-list-item row]))
:renderSeparator render-separator
:style st/recent-list}]]))

View File

@ -2,32 +2,54 @@
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[clojure.string :as str]
[status-im.components.react :refer [view text image]]
[status-im.components.react :refer [view text image touchable-highlight]]
[status-im.discovery.styles :as st]
[status-im.utils.gfycat.core :refer [generate-gfy]]
[status-im.utils.identicon :refer [identicon]]
[status-im.i18n :refer [label]]
[status-im.components.chat-icon.screen :as ci]))
[status-im.components.chat-icon.screen :as ci]
[status-im.utils.platform :refer [platform-specific]]
[taoensso.timbre :as log]))
(defview discovery-list-item [{:keys [name photo-path status whisper-id]}]
(defn tag-view [tag]
[text {:style {:color "#7099e6"}
:font :medium}
(str tag " ")])
(defn status-view [item-style {:keys [message-id status]}]
[text {:style (:status-text item-style)
:font :default}
(for [[i status] (map-indexed vector (str/split status #" "))]
(if (.startsWith status "#")
^{:key (str "item-" message-id "-" i)}
[tag-view status]
^{:key (str "item-" message-id "-" i)}
(str status " ")))])
(defview discovery-list-item [{:keys [name photo-path whisper-id] :as message}
show-separator?]
[{contact-name :name
contact-photo-path :photo-path} [:get-in [:contacts whisper-id]]]
[view st/popular-list-item
[view st/popular-list-item-name-container
[text {:style st/popular-list-item-name
:font :medium
:number-of-lines 1}
(cond
(not (str/blank? contact-name)) contact-name
(not (str/blank? name)) name
:else (generate-gfy))]
[text {:style st/popular-list-item-status
:font :default
:number-of-lines 2}
status]]
[view st/popular-list-item-avatar-container
[ci/chat-icon (cond
(not (str/blank? contact-photo-path)) contact-photo-path
(not (str/blank? photo-path)) photo-path
:else (identicon whisper-id))
{:size 36}]]])
(let [item-style (get-in platform-specific [:component-styles :discovery :item])]
[view
[view st/popular-list-item
[view st/popular-list-item-name-container
[text {:style st/popular-list-item-name
:font :medium
:number-of-lines 1}
(cond
(not (str/blank? contact-name)) contact-name
(not (str/blank? name)) name
:else (generate-gfy))]
[status-view item-style message]]
[view (merge st/popular-list-item-avatar-container
(:icon item-style))
[touchable-highlight {:on-press #(dispatch [:start-chat whisper-id])}
[view
[ci/chat-icon (cond
(not (str/blank? contact-photo-path)) contact-photo-path
(not (str/blank? photo-path)) photo-path
:else (identicon whisper-id))
{:size 36}]]]]]
(when show-separator?
[view st/separator])]))

View File

@ -3,20 +3,23 @@
(:require
[re-frame.core :refer [subscribe dispatch]]
[status-im.components.react :refer [view
list-view
list-item
touchable-highlight
text]]
list-view
list-item
touchable-highlight
text]]
[status-im.discovery.styles :as st]
[status-im.utils.listview :refer [to-datasource]]
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]))
[status-im.discovery.views.discovery-list-item :refer [discovery-list-item]]
[status-im.utils.platform :refer [platform-specific]]))
(defview discovery-popular-list [{:keys [tag count contacts]}]
[discoveries [:get-discoveries-by-tags [tag] 3]]
[view st/popular-list-container
(defview discovery-popular-list [{:keys [tag contacts]}]
[discoveries [:get-popular-discoveries 3 [tag]]]
[view (merge st/popular-list-container
(get-in platform-specific [:component-styles :discovery :popular]))
[view st/row
[view st/tag-name-container
[touchable-highlight {:onPress #(dispatch [:show-discovery-tag tag])}
[view (get-in platform-specific [:component-styles :discovery :tag])
[touchable-highlight {:on-press #(do (dispatch [:set :discovery-search-tags [tag]])
(dispatch [:navigate-to :discovery-search-results]))}
[view
[text {:style st/tag-name
:font :medium}
@ -24,7 +27,8 @@
[view st/tag-count-container
[text {:style st/tag-count
:font :default}
count]]]
(for [{:keys [message-id] :as discovery} discoveries]
^{:key (str "message-" message-id)}
[discovery-list-item discovery])])
(:total discoveries)]]]
(let [discoveries (map-indexed vector (:discoveries discoveries))]
(for [[i {:keys [message-id] :as discovery}] discoveries]
^{:key (str "message-" message-id)}
[discovery-list-item discovery (not= (inc i) (count discoveries))]))])

View File

@ -64,6 +64,7 @@
(dispatch [:init-chat])
(dispatch [:init-discoveries])
(dispatch [:send-account-update-if-needed])
(dispatch [:start-requesting-discoveries])
(dispatch [:remove-old-discoveries!]))))
(register-handler :reset-app

View File

@ -13,7 +13,6 @@
[status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]]
[status-im.qr-scanner.screen :refer [qr-scanner]]
[status-im.discovery.tag :refer [discovery-tag]]
[status-im.discovery.search-results :refer [discovery-search-results]]
[status-im.chat.screen :refer [chat]]
[status-im.accounts.login.screen :refer [login]]
@ -74,7 +73,6 @@
(let [current-view (validate-current-view @view-id @signed-up?)]
(let [component (case current-view
:discovery main-tabs
:discovery-tag discovery-tag
:discovery-search-results discovery-search-results
:add-participants new-participants
:remove-participants remove-participants

View File

@ -21,6 +21,27 @@
:border-bottom-width 0.5}
:chat {:new-message {:border-top-color styles/color-gray3
:border-top-width 0.5}}
:discovery {:subtitle {:color styles/color-steel
:font-size 13
:letter-spacing 1}
:popular {:border-radius 3
:border-width 1
:border-color "#D7D7D7"}
:tag {:flex-direction "column"
:background-color "rgb(227, 235, 250)"
:border-radius 4
:border-width 1
:border-color "rgba(112, 153, 230, 0.31)"
:padding 6}
:item {:status-text {:color styles/color-steel
:font-size 14
:letter-spacing -0.1}
:icon {:padding-top 0
:bottom -4
:justify-content :flex-end}}}
:contacts {:subtitle {:color styles/color-steel
:font-size 13
:letter-spacing 1}}
:bottom-gradient {:height 1}
:input-label {:left 0}
:input-error-text {:margin-left 0}
@ -60,5 +81,8 @@
:chats {:action-button? false
:new-chat-in-toolbar? true}
:contacts {:action-button? false
:new-contact-in-toolbar? true}})
:new-contact-in-toolbar? true
:uppercase-subtitles? true
:group-block-shadows? false}
:discovery {:uppercase-subtitles? true}})

View File

@ -36,9 +36,12 @@
;; discoveries
(def watch-user! discoveries/watch-user!)
(def contact-request! discoveries/contact-request!)
(def watch-hashtags! discoveries/watch-hashtags!)
(def broadcats-profile! discoveries/broadcats-profile!)
(def broadcats-discoveries! discoveries/broadcats-discoveries!)
(def broadcast-profile! discoveries/broadcast-profile!)
(def send-status! discoveries/send-status!)
(def send-discoveries-request! discoveries/send-discoveries-request!)
(def send-discoveries-response! discoveries/send-discoveries-response!)
(def message-pending? d/message-pending?)
;; initialization
(s/def ::rpc-url string?)
@ -82,10 +85,6 @@
{:topics [chat-id]}
(l/message-listener (assoc listener-options :callback callback
:keypair keypair))))
;; start listening to discoveries
(watch-hashtags! {:web3 web3
:hashtags hashtags
:callback callback})
;; start listening to profiles
(doseq [{:keys [identity keypair]} contacts]
(watch-user! {:web3 web3

View File

@ -9,13 +9,9 @@
[status-im.protocol.validation :refer-macros [valid?]]
[status-im.utils.random :as random]))
(def discovery-topic "status-discovery")
(def discovery-topic-prefix "status-discovery-")
(def discovery-hashtag-prefix "status-hashtag-")
(defn- add-hashtag-prefix [hashtag]
(str discovery-hashtag-prefix hashtag))
(defn- make-discovery-topic [identity]
(str discovery-topic-prefix identity))
@ -72,35 +68,12 @@
(defonce watched-hashtag-topics (atom nil))
(defn- hashtags->topics
"Create topics from hashtags."
[hashtags]
(->> hashtags
(map (fn [tag]
[tag [(add-hashtag-prefix tag) discovery-topic]]))
(into {})))
(s/def :discoveries/hashtags (s/every string? :kind-of set?))
(defn stop-watching-hashtags!
[web3]
(doseq [topics @watched-hashtag-topics]
(f/remove-filter! web3 topics)))
(s/def ::callback fn?)
(s/def :watch-hashtags/options
(s/keys :req-un [:options/web3 :discoveries/hashtags ::callback]))
(defn watch-hashtags!
[{:keys [web3 hashtags] :as options}]
{:pre [(valid? :watch-hashtags/options options)]}
(debug :watch-hashtags hashtags)
(stop-watching-hashtags! web3)
(let [hashtag-topics (vals (hashtags->topics hashtags))]
(reset! watched-hashtag-topics hashtag-topics)
(doseq [topics hashtag-topics]
(f/add-filter! web3 {:topics topics} (l/message-listener options)))))
(s/def ::status (s/nilable string?))
(s/def ::profile (s/keys :req-un [::status]))
(s/def :profile/payload
@ -111,7 +84,7 @@
(s/def :broadcast-profile/options
(s/keys :req-un [:profile/message :options/web3]))
(defn broadcats-profile!
(defn broadcast-profile!
[{:keys [web3 message] :as options}]
{:pre [(valid? :broadcast-profile/options options)]}
(debug :broadcasting-status)
@ -132,18 +105,32 @@
(s/def :broadcast-hasthags/options
(s/keys :req-un [:discoveries/hashtags :status/message :options/web3]))
(defn broadcats-discoveries!
[{:keys [web3 hashtags message] :as options}]
{:pre [(valid? :broadcast-hasthags/options options)]}
(defn send-status!
[{:keys [web3 message]}]
(debug :broadcasting-status)
(let [discovery-id (random/id)]
(doseq [[tag hashtag-topics] (hashtags->topics hashtags)]
(d/add-pending-message!
web3
(-> message
(assoc :type :discovery
:topics hashtag-topics)
(assoc-in [:payload :tag] tag)
(assoc-in [:payload :hashtags] (vec hashtags))
(assoc-in [:payload :discovery-id] discovery-id)
(update :message-id str tag))))))
(let [message (-> message
(assoc :type :discovery
:topics [(make-discovery-topic (:from message))]))]
(d/add-pending-message! web3 message)))
(defn send-discoveries-request!
[{:keys [web3 message]}]
(debug :sending-discoveries-request)
(d/add-pending-message!
web3
(-> message
(assoc :type :discoveries-request
:topics [(make-discovery-topic (:from message))]))))
(defn send-discoveries-response!
[{:keys [web3 discoveries message]}]
(debug :sending-discoveries-response)
(doseq [portion (->> (take 100 discoveries)
(partition 10 10 nil))]
(d/add-pending-message!
web3
(-> message
(assoc :type :discoveries-response
:topics [(make-discovery-topic (:from message))]
:message-id (random/id)
:payload {:data (into [] portion)})))))

View File

@ -85,7 +85,9 @@
:add-group-identity (dispatch [:participant-invited-to-group message])
:leave-group (dispatch [:participant-left-group message])
:contact-request (dispatch [:contact-request-received message])
:discovery (dispatch [:discovery-response-received message])
:discovery (dispatch [:status-received message])
:discoveries-request (dispatch [:discoveries-request-received message])
:discoveries-response (dispatch [:discoveries-response-received message])
:profile (dispatch [:contact-update-received message])
:online (dispatch [:contact-online-received message])
:pending (dispatch [:pending-message-upsert message])

View File

@ -129,7 +129,7 @@
(defn delivery-callback
[web3 {:keys [id requires-ack? to]}]
(fn [error _]
(when error (log/error :shh-post-error error))
(when error (log/warn :shh-post-error error))
(when-not error
(debug :delivery-callback)
(message-was-sent! web3 id to)
@ -159,7 +159,7 @@
;; todo add some notification about network issues
(<= attempts (* 5 max-attempts-number))
(and
;; if message was not send lees then max-attempts-number times
;; if message was not send less then max-attempts-number times
;; continue attempts
(<= attempts max-attempts-number)
;; check retransmition interval
@ -169,6 +169,15 @@
[message message-type ttl-config default-ttl]
(update message :ttl #(or % ((keyword message-type) ttl-config) default-ttl)))
(defn message-pending?
[web3 required-type required-to]
(some (fn [[_ messages]]
(some (fn [[_ {:keys [type to]}]]
(and (= type required-type)
(= to required-to)))
messages))
(@messages web3)))
(defn run-delivery-loop!
[web3 {:keys [delivery-loop-ms-interval default-ttl ttl-config
send-online-s-interval online-message]

View File

@ -107,6 +107,7 @@
:popular-tags "Popular tags"
:recent "Recent"
:no-statuses-discovered "No statuses discovered"
:no-statuses-found "No statuses found"
;settings
:settings "Settings"