No more newline characters in statuses (#463) Copyable address and key in profile (#462), several fixes
This commit is contained in:
parent
b49c3e92d1
commit
2f7d75c90f
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}})
|
||||
|
|
|
@ -393,10 +393,12 @@
|
|||
|
||||
(register-handler :start-chat
|
||||
(u/side-effect!
|
||||
(fn [{:keys [chats]} [_ 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])))))
|
||||
(dispatch [::start-chat! contact-id options navigation-type]))))))
|
||||
|
||||
(register-handler :add-chat
|
||||
(u/side-effect!
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" %)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,7 +216,8 @@
|
|||
|
||||
(register-handler :contact-update-received
|
||||
(u/side-effect!
|
||||
(fn [{:keys [chats] :as db} [_ {:keys [from payload]}]]
|
||||
(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])]
|
||||
|
@ -225,11 +227,10 @@
|
|||
: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}]))))))))
|
||||
:name name}])))))))))
|
||||
|
||||
(register-handler :contact-online-received
|
||||
(u/side-effect!
|
||||
|
|
|
@ -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,24 +46,41 @@
|
|||
: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?
|
||||
(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}])
|
||||
[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}
|
||||
|
||||
(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
|
||||
;; TODO not imlemented: contact more button handler
|
||||
(map (fn [contact]
|
||||
(let [whisper-identity (:whisper-identity contact)
|
||||
click-handler (or click-handler on-press)]
|
||||
|
@ -72,7 +91,12 @@
|
|||
[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)]]]])])
|
||||
[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]
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
|
||||
(def contact-groups
|
||||
{:flex 1
|
||||
:backgroundColor toolbar-background2})
|
||||
:background-color toolbar-background2})
|
||||
|
||||
(def empty-contact-groups
|
||||
(merge contact-groups
|
||||
{:align-items :center
|
||||
:padding-top 150}))
|
||||
: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
|
||||
|
|
|
@ -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)))))
|
||||
|
||||
|
|
|
@ -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))))
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}])
|
||||
|
|
|
@ -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))
|
|
@ -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))
|
|
@ -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))
|
|
@ -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"))
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
:new-contact-identity ""
|
||||
:contacts {}
|
||||
:discoveries []
|
||||
:discoveries {}
|
||||
:discovery-search-tags []
|
||||
:tags {}
|
||||
|
||||
|
|
|
@ -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))))
|
||||
(assoc :discoveries (->> (discoveries/get-all :desc)
|
||||
(map (fn [{:keys [message-id] :as discovery}]
|
||||
[message-id discovery]))
|
||||
(into {})))))
|
||||
|
||||
(register-handler :discovery-response-received
|
||||
(register-handler :broadcast-status
|
||||
(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
|
||||
(fn [{:keys [current-public-key web3 current-account-id accounts contacts]}
|
||||
[_ status hashtags]]
|
||||
(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 :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)
|
||||
:last-updated (js/Date.)
|
||||
:priority (calculate-priority db from payload)}]
|
||||
(dispatch [:add-discovery discovery])))))
|
||||
:created-at (time/now-ms)}]
|
||||
(dispatch [:add-discovery discovery]))))))
|
||||
|
||||
(register-handler :check-status!
|
||||
(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 [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)}]
|
||||
(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])))))))))
|
||||
|
||||
(register-handler :broadcast-status
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-public-key web3 current-account-id accounts]}
|
||||
[_ 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])})))))
|
||||
|
||||
(register-handler :show-discovery-tag
|
||||
(fn [db [_ tag]]
|
||||
(dispatch [:navigate-to :discovery-tag])
|
||||
(assoc db :current-tag tag)))
|
||||
|
||||
(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))))
|
||||
|
|
|
@ -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
|
||||
[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]
|
||||
[view st/popular-container
|
||||
[title :t/popular-tags false]
|
||||
(if (pos? (count popular-tags))
|
||||
[carousel {:pageStyle st/carousel-page-style}
|
||||
(for [{:keys [name 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
|
||||
:count count
|
||||
:contacts contacts}])]
|
||||
[text (label :t/none)])]
|
||||
[text (label :t/none)])])
|
||||
|
||||
(defview discovery-recent [{:keys [contacts]}]
|
||||
[discoveries [:get-recent-discoveries]]
|
||||
(when (seq discoveries)
|
||||
[view st/recent-container
|
||||
[title :t/recent true]
|
||||
[view st/recent-list
|
||||
(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]
|
||||
discoveries [:get-recent-discoveries]]
|
||||
[view st/discovery-container
|
||||
[discovery-toolbar show-search?]
|
||||
(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)]]))
|
||||
|
||||
(defview discovery-recent [{:keys [contacts]}]
|
||||
[discoveries [:get :discoveries]]
|
||||
(when (seq discoveries)
|
||||
[view
|
||||
[title :t/recent]
|
||||
[view st/recent-list
|
||||
(for [{:keys [message-id] :as discovery} discoveries]
|
||||
^{:key (str "message-" message-id)}
|
||||
[discovery-list-item discovery])]]))
|
||||
|
||||
(defview discovery []
|
||||
[show-search? [:get ::show-search?]
|
||||
contacts [:get :contacts]]
|
||||
[view st/discovery-container
|
||||
[discovery-toolbar show-search?]
|
||||
[scroll-view st/scroll-view-container
|
||||
[discovery-popular {:contacts contacts}]
|
||||
[discovery-recent {:contacts contacts}]]
|
||||
(label :t/no-statuses-discovered)]])
|
||||
[bottom-gradient]])
|
||||
|
|
|
@ -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]
|
||||
[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 {:style st/tag-container}
|
||||
[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)]])])
|
||||
(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 [])}]}]
|
||||
|
||||
: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}]]))
|
||||
:style st/recent-list}])]))
|
||||
|
|
|
@ -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})
|
||||
: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
|
||||
|
|
|
@ -1,20 +1,43 @@
|
|||
(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 %))
|
||||
(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
|
||||
)))
|
||||
|
||||
(defn- get-discoveries-by-tags [discoveries current-tag tags]
|
||||
(let [tags' (or tags [current-tag])]
|
||||
(filter #(every? (->> (map :name (:tags %))
|
||||
(into (hash-set)))
|
||||
tags'))
|
||||
xform (if limit
|
||||
(comp filter-tag (take limit))
|
||||
filter-tag)]
|
||||
(into [] xform discoveries)))
|
||||
tags')
|
||||
(vals discoveries))))
|
||||
|
||||
(register-sub :get-discoveries-by-tags
|
||||
(fn [db [_ tags limit]]
|
||||
(-> (get-discoveries-by-tags @db tags limit)
|
||||
(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
|
||||
|
@ -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)))))
|
||||
|
|
|
@ -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}]]))
|
|
@ -2,16 +2,36 @@
|
|||
(: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]]]
|
||||
(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
|
||||
|
@ -21,13 +41,15 @@
|
|||
(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
|
||||
[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}]]])
|
||||
{:size 36}]]]]]
|
||||
(when show-separator?
|
||||
[view st/separator])]))
|
||||
|
|
|
@ -9,14 +9,17 @@
|
|||
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]
|
||||
(: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])])
|
||||
[discovery-list-item discovery (not= (inc i) (count discoveries))]))])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}})
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
(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 :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))))))
|
||||
(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)})))))
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue