Merge pull request #541 from status-im/feature/toolbar-fixes-and-search

Toolbar refactoring, unification; search for contacts (#448); processed-messages cache (#552); fix for #554
This commit is contained in:
Roman Volosovskyi 2016-12-14 20:40:14 +02:00 committed by GitHub
commit 63e352020d
42 changed files with 553 additions and 291 deletions

View File

@ -1,5 +1,6 @@
(ns status-im.accounts.handlers (ns status-im.accounts.handlers
(:require [status-im.data-store.accounts :as accounts-store] (:require [status-im.data-store.accounts :as accounts-store]
[status-im.data-store.processed-messages :as processed-messages]
[re-frame.core :refer [register-handler after dispatch dispatch-sync debug]] [re-frame.core :refer [register-handler after dispatch dispatch-sync debug]]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[status-im.protocol.core :as protocol] [status-im.protocol.core :as protocol]
@ -18,6 +19,7 @@
[status-im.utils.gfycat.core :refer [generate-gfy]] [status-im.utils.gfycat.core :refer [generate-gfy]]
[status-im.constants :refer [console-chat-id]] [status-im.constants :refer [console-chat-id]]
[status-im.utils.scheduler :as s] [status-im.utils.scheduler :as s]
[status-im.protocol.message-cache :as cache]
[status-im.navigation.handlers :as nav])) [status-im.navigation.handlers :as nav]))
@ -149,6 +151,15 @@
(register-handler :console-create-account console-create-account) (register-handler :console-create-account console-create-account)
(register-handler
:load-processed-messages
(u/side-effect!
(fn [_]
(let [now (time/now-ms)
messages (processed-messages/get-filtered (str "ttl > " now))]
(cache/init! messages)
(processed-messages/delete (str "ttl <=" now))))))
(defmethod nav/preload-data! :qr-code-view (defmethod nav/preload-data! :qr-code-view
[{:keys [current-account-id] :as db} [_ _ {:keys [contact qr-source amount?]}]] [{:keys [current-account-id] :as db} [_ _ {:keys [contact qr-source amount?]}]]
(assoc db :qr-modal {:contact (or contact (assoc db :qr-modal {:contact (or contact

View File

@ -9,6 +9,7 @@
get-dimensions]] get-dimensions]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :refer [toolbar-title-container [status-im.components.toolbar.styles :refer [toolbar-title-container
toolbar-title-text]] toolbar-title-text]]
[status-im.components.text-field.view :refer [text-field]] [status-im.components.text-field.view :refer [text-field]]
@ -66,9 +67,7 @@
:style st/gradient-background}] :style st/gradient-background}]
[status-bar {:type :transparent}] [status-bar {:type :transparent}]
[toolbar {:background-color :transparent [toolbar {:background-color :transparent
:nav-action {:image {:source {:uri :icon_back_white} :nav-action (act/back-white #(dispatch [:navigate-back]))
:style icon-back}
:handler #(dispatch [:navigate-back])}
:custom-content [toolbar-title] :custom-content [toolbar-title]
:actions [{:image {:style icon-search} :actions [{:image {:style icon-search}
:handler #()}]}] :handler #()}]}]

View File

@ -9,13 +9,12 @@
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.text-field.view :refer [text-field]] [status-im.components.text-field.view :refer [text-field]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :refer [toolbar-gradient [status-im.components.toolbar.styles :refer [toolbar-gradient
toolbar-title-container toolbar-title-container
toolbar-title-text]] toolbar-title-text]]
[status-im.components.styles :refer [color-purple [status-im.components.styles :refer [color-purple
color-white color-white
icon-back
icon-search
button-input]] button-input]]
[status-im.components.react :refer [linear-gradient]] [status-im.components.react :refer [linear-gradient]]
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
@ -78,12 +77,8 @@
[view st/screen-container [view st/screen-container
[status-bar {:type :transparent}] [status-bar {:type :transparent}]
[toolbar {:background-color :transparent [toolbar {:background-color :transparent
:nav-action {:image {:source {:uri :icon_back} :nav-action (act/back #(dispatch [:navigate-back]))
:style icon-back} :custom-content [toolbar-title]}]
:handler #(dispatch [:navigate-back])}
:custom-content [toolbar-title]
:actions [{:image {:style icon-search}
:handler #()}]}]
[linear-gradient {:locations [0 0.6 1] [linear-gradient {:locations [0 0.6 1]
:colors gradient-colors :colors gradient-colors
:style toolbar-gradient}] :style toolbar-gradient}]

View File

@ -11,6 +11,7 @@
touchable-highlight]] touchable-highlight]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.styles :refer [color-purple [status-im.components.styles :refer [color-purple
color-white color-white
icon-search icon-search
@ -61,9 +62,9 @@
:style st/gradient-background} :style st/gradient-background}
[status-bar {:type :transparent}] [status-bar {:type :transparent}]
[toolbar {:background-color :transparent [toolbar {:background-color :transparent
:nav-action {:image {:source (if show-back? {:uri :icon_back_white} nil) :nav-action (if show-back?
:style icon-back} (act/back-white #(dispatch [:navigate-back]))
:handler (if show-back? #(dispatch [:navigate-back]) nil)} act/nothing)
:custom-content [toolbar-title] :custom-content [toolbar-title]
:actions [{:image {:style icon-search} :actions [{:image {:style icon-search}
:handler #()}]}]] :handler #()}]}]]

View File

@ -12,6 +12,7 @@
modal modal
splash-screen]] splash-screen]]
[status-im.components.main-tabs :refer [main-tabs]] [status-im.components.main-tabs :refer [main-tabs]]
[status-im.contacts.search-results :refer [contacts-search-results]]
[status-im.contacts.views.contact-list :refer [contact-list]] [status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]] [status-im.contacts.views.new-contact :refer [new-contact]]
[status-im.qr-scanner.screen :refer [qr-scanner]] [status-im.qr-scanner.screen :refer [qr-scanner]]
@ -95,6 +96,7 @@
:new-group new-group :new-group new-group
:group-settings group-settings :group-settings group-settings
:contact-list main-tabs :contact-list main-tabs
:contact-list-search-results contacts-search-results
:group-contacts contact-list :group-contacts contact-list
:new-contact new-contact :new-contact new-contact
:qr-scanner qr-scanner :qr-scanner qr-scanner

View File

@ -8,43 +8,36 @@
text text
image image
touchable-highlight]] touchable-highlight]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.chats-list.views.chat-list-item :refer [chat-list-item]]
[status-im.components.action-button :refer [action-button [status-im.components.action-button :refer [action-button
action-button-item]] action-button-item]]
[status-im.components.drawer.view :refer [open-drawer]] [status-im.components.drawer.view :refer [open-drawer]]
[status-im.components.styles :refer [color-blue]] [status-im.components.styles :refer [color-blue]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar-with-search]]
[status-im.components.toolbar.styles :refer [toolbar-background1 [status-im.components.toolbar.actions :as act]
toolbar-background2]]
[status-im.components.icons.custom-icons :refer [ion-icon]] [status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.components.react :refer [linear-gradient]] [status-im.components.react :refer [linear-gradient]]
[status-im.i18n :refer [label]]
[status-im.chats-list.styles :as st]
[status-im.utils.platform :refer [platform-specific]]
[status-im.components.sync-state.offline :refer [offline-view]] [status-im.components.sync-state.offline :refer [offline-view]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.chats-list.views.chat-list-item :refer [chat-list-item]]
[status-im.i18n :refer [label]]
[status-im.utils.platform :refer [platform-specific]]
[status-im.chats-list.styles :as st]
[status-im.components.tabs.styles :refer [tabs-height]])) [status-im.components.tabs.styles :refer [tabs-height]]))
(defview chats-list-toolbar [] (defview toolbar-view []
[chats-scrolled? [:get :chats-scrolled?]] [chats-scrolled? [:get :chats-scrolled?]]
(let [new-chat? (get-in platform-specific [:chats :new-chat-in-toolbar?]) (let [new-chat? (get-in platform-specific [:chats :new-chat-in-toolbar?])
actions (cond->> [{:image {:source {:uri :icon_search} actions (if new-chat?
:style st/toolbar-icon} [(act/add #(dispatch [:navigate-to :group-contacts :people]))])]
:handler (fn [])}] [toolbar-with-search
new-chat? {:show-search? false
(into [{:image {:source {:uri :icon_add} :search-key :chat-list
:style st/toolbar-icon} :title (label :t/chats)
:handler #(dispatch [:navigate-to :group-contacts :people])}]))] :search-placeholder (label :t/search-for)
[toolbar {:nav-action {:image {:source {:uri :icon_hamburger} :nav-action (act/hamburger open-drawer)
:style st/hamburger-icon} :actions actions
:handler open-drawer} :style (st/toolbar chats-scrolled?)}]))
:title (label :t/chats)
:style (get-in platform-specific [:component-styles :toolbar])
:background-color (if chats-scrolled?
toolbar-background1
toolbar-background2)
:actions actions}]))
(defn chats-action-button [] (defn chats-action-button []
[view {:style (st/action-buttons-container false 0) [view {:style (st/action-buttons-container false 0)
@ -75,7 +68,7 @@
(defview chats-list [] (defview chats-list []
[chats [:get :chats]] [chats [:get :chats]]
[view st/chats-container [view st/chats-container
[chats-list-toolbar] [toolbar-view]
[list-view {:dataSource (to-datasource chats) [list-view {:dataSource (to-datasource chats)
:renderRow (fn [[id :as row] _ _] :renderRow (fn [[id :as row] _ _]
(list-item ^{:key id} [chat-list-item row])) (list-item ^{:key id} [chat-list-item row]))

View File

@ -7,8 +7,16 @@
text2-color text2-color
new-messages-count-color]] new-messages-count-color]]
[status-im.components.tabs.styles :refer [tabs-height]] [status-im.components.tabs.styles :refer [tabs-height]]
[status-im.components.toolbar.styles :refer [toolbar-background1
toolbar-background2]]
[status-im.utils.platform :as p])) [status-im.utils.platform :as p]))
(defn toolbar [chats-scrolled?]
(merge {:background-color (if chats-scrolled?
toolbar-background1
toolbar-background2)}
(get-in p/platform-specific [:component-styles :toolbar])))
(def gradient-top-bottom-shadow (def gradient-top-bottom-shadow
["rgba(24, 52, 76, 0.165)" ["rgba(24, 52, 76, 0.165)"
"rgba(24, 52, 76, 0.03)" "rgba(24, 52, 76, 0.03)"
@ -103,14 +111,6 @@
:color color-blue :color color-blue
:textAlign :center}) :textAlign :center})
(def hamburger-icon
{:width 16
:height 12})
(def toolbar-icon
{:width 17
:height 17})
(def chats-container (def chats-container
{:flex 1}) {:flex 1})

View File

@ -107,8 +107,8 @@
:onScrollBeginDrag #(reset! dragging? true) :onScrollBeginDrag #(reset! dragging? true)
:on-momentum-scroll-end (on-scroll-end swiped? dragging?)}) :on-momentum-scroll-end (on-scroll-end swiped? dragging?)})
[chats-list] [chats-list]
[discover (= @view-id :discover)] [discover (= @view-id :discover)]
[contact-list]] [contact-list (= @view-id :contact-list)]]
[tabs {:selected-view-id @view-id [tabs {:selected-view-id @view-id
:prev-view-id @prev-view-id :prev-view-id @prev-view-id
:tab-list tab-list}] :tab-list tab-list}]

View File

@ -31,10 +31,6 @@
(def flex (def flex
{:flex 1}) {:flex 1})
(def hamburger-icon
{:width 16
:height 12})
(def icon-search (def icon-search
{:width 17 {:width 17
:height 17}) :height 17})

View File

@ -0,0 +1,31 @@
(ns status-im.components.toolbar.actions
(:require [status-im.components.toolbar.styles :as st]))
(def nothing
{:image {:source nil
:style st/action-search}})
(defn hamburger [handler]
{:image {:source {:uri :icon_hamburger}
:style st/action-hamburger}
:handler handler})
(defn add [handler]
{:image {:source {:uri :icon_add}
:style st/action-add}
:handler handler})
(defn search [handler]
{:image {:source {:uri :icon_search}
:style st/action-search}
:handler handler})
(defn back [handler]
{:image {:source {:uri :icon_back}
:style st/action-back}
:handler handler})
(defn back-white [handler]
{:image {:source {:uri :icon_back_white}
:style st/action-back}
:handler handler})

View File

@ -41,7 +41,7 @@
:justifyContent :center}) :justifyContent :center})
(def toolbar-title-text (def toolbar-title-text
{:margin-top -2.5 {:margin-top 0
:color text1-color :color text1-color
:font-size 16}) :font-size 16})
@ -57,4 +57,46 @@
:height toolbar-height :height toolbar-height
:margin-right toolbar-icon-spacing :margin-right toolbar-icon-spacing
:align-items :center :align-items :center
:justify-content :center}) :justify-content :center})
(def toolbar-with-search
{:background-color toolbar-background2
:elevation 0})
(def toolbar-with-search-content
{:flex 1
:align-items :center
:justify-content :center})
(def toolbar-search-input
{:flex 1
:align-self :stretch
:margin-left 18
:margin-top 2
:font-size 14
:color "#7099e6"})
(def toolbar-with-search-title
{:color "#000000de"
:align-self :center
:text-align :center
:font-size 16})
;; Specific actions
(def action-hamburger
{:width 16
:height 12})
(def action-add
{:width 17
:height 17})
(def action-search
{:width 17
:height 17})
(def action-back
{:width 8
:height 14})

View File

@ -3,10 +3,13 @@
[status-im.components.react :refer [view [status-im.components.react :refer [view
icon icon
text text
text-input
image image
touchable-highlight]] touchable-highlight]]
[status-im.components.sync-state.gradient :refer [sync-state-gradient-view]] [status-im.components.sync-state.gradient :refer [sync-state-gradient-view]]
[status-im.components.styles :refer [icon-back]] [status-im.components.styles :refer [icon-back
icon-search]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :as st] [status-im.components.toolbar.styles :as st]
[status-im.utils.platform :refer [platform-specific]])) [status-im.utils.platform :refer [platform-specific]]))
@ -48,3 +51,43 @@
custom-action)]] custom-action)]]
[sync-state-gradient-view]])) [sync-state-gradient-view]]))
(defn- toolbar-search-submit [on-search-submit]
(let [text @(subscribe [:get-in [:toolbar-search :text]])]
(on-search-submit text)
(dispatch [:set-in [:toolbar-search :text] nil])))
(defn- toolbar-with-search-content [{:keys [show-search?
search-key
search-placeholder
title
on-search-submit]}]
[view st/toolbar-with-search-content
(if show-search?
[text-input
{:style st/toolbar-search-input
:auto-focus true
:placeholder search-placeholder
:on-change-text #(dispatch [:set-in [:toolbar-search :text] %])
:on-submit-editing #(toolbar-search-submit on-search-submit)}]
[view
[text {:style st/toolbar-with-search-title
:font :toolbar-title}
title]])])
(defn toolbar-with-search [{:keys [show-search?
search-key
nav-action
actions
style
on-search-submit]
:as opts}]
(let [toggle-search-fn #(dispatch [:set-in [:toolbar-search :show] %])
actions (if show-search?
[(act/search #(toolbar-search-submit on-search-submit))]
(into actions [(act/search #(toggle-search-fn search-key))]))]
[toolbar {:style (merge st/toolbar-with-search style)
:nav-action (if show-search?
(act/back #(toggle-search-fn nil))
nav-action)
:custom-content [toolbar-with-search-content opts]
:actions actions}]))

View File

@ -11,6 +11,7 @@
[status-im.utils.utils :refer [require]] [status-im.utils.utils :refer [require]]
[status-im.navigation.handlers :as nav] [status-im.navigation.handlers :as nav]
[status-im.utils.random :as random] [status-im.utils.random :as random]
[status-im.i18n :refer [label]]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[cljs.reader :refer [read-string]])) [cljs.reader :refer [read-string]]))
@ -31,9 +32,10 @@
(defmethod nav/preload-data! :contact-list (defmethod nav/preload-data! :contact-list
[db [_ _ click-handler]] [db [_ _ click-handler]]
(assoc db :contacts-click-handler click-handler (-> db
:contacts-filter nil)) (assoc-in [:toolbar-search :show] nil)
(assoc :contacts-click-handler click-handler
:contacts-filter nil)))
(register-handler :remove-contacts-click-handler (register-handler :remove-contacts-click-handler
(fn [db] (fn [db]
@ -56,6 +58,13 @@
(register-handler :watch-contact (u/side-effect! watch-contact)) (register-handler :watch-contact (u/side-effect! watch-contact))
(defn stop-watching-contact
[{:keys [web3]} [_ {:keys [whisper-identity]}]]
(protocol/stop-watching-user! {:web3 web3
:identity whisper-identity}))
(register-handler :stop-watching-contact (u/side-effect! stop-watching-contact))
(defn send-contact-request (defn send-contact-request
[{:keys [current-public-key web3 current-account-id accounts]} [_ contact]] [{:keys [current-public-key web3 current-account-id accounts]} [_ contact]]
(let [{:keys [whisper-identity]} contact (let [{:keys [whisper-identity]} contact
@ -199,11 +208,13 @@
(register-handler :add-pending-contact (register-handler :add-pending-contact
(u/side-effect! (u/side-effect!
(fn [{:keys [chats]} [_ chat-id]] (fn [{:keys [chats contacts]} [_ chat-id]]
(let [contact (read-string (get-in chats [chat-id :contact-info]))] (let [contact (if-let [contact-info (get-in chats [chat-id :contact-info])]
(read-string contact-info)
(-> (get contacts chat-id)
(assoc :pending false)))]
(dispatch [::prepare-contact contact]) (dispatch [::prepare-contact contact])
(dispatch [:update-chat! {:chat-id chat-id (dispatch [:update-chat! {:chat-id chat-id
:contact-info nil
:pending-contact? false}]) :pending-contact? false}])
(dispatch [:watch-contact contact]) (dispatch [:watch-contact contact])
(dispatch [:discoveries-send-portions chat-id]))))) (dispatch [:discoveries-send-portions chat-id])))))
@ -242,3 +253,22 @@
(dispatch [:update-contact! {:whisper-identity from (dispatch [:update-contact! {:whisper-identity from
:last-online timestamp}])))))) :last-online timestamp}]))))))
(register-handler :remove-contact
(-> (u/side-effect!
(fn [_ [_ {:keys [whisper-identity] :as contact}]]
(dispatch [:update-chat! {:chat-id whisper-identity
:pending-contact? true}])
(dispatch [:update-contact! (assoc contact :pending true)])))
((after stop-watching-contact))))
(register-handler :open-contact-menu
(u/side-effect!
(fn [_ [_ list-selection-fn {:keys [name] :as contact}]]
(list-selection-fn {:title name
:options [(label :t/remove-contact)]
:callback (fn [index]
(case index
0 (dispatch [:remove-contact contact])
:default))
:cancel-text (label :t/cancel)}))))

View File

@ -1,7 +1,8 @@
(ns status-im.contacts.screen (ns status-im.contacts.screen
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [reagent.core :as r]
[reagent.core :as r] [clojure.string :as str]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.components.react :refer [view [status-im.components.react :refer [view
text text
image image
@ -12,38 +13,40 @@
list-item] :as react] list-item] :as react]
[status-im.components.action-button :refer [action-button [status-im.components.action-button :refer [action-button
action-button-item]] action-button-item]]
[status-im.contacts.views.contact :refer [contact-extended-view on-press]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar-with-search]]
[status-im.components.toolbar.styles :refer [toolbar-background2]] [status-im.components.toolbar.actions :as act]
[status-im.components.drawer.view :refer [open-drawer]] [status-im.components.drawer.view :refer [open-drawer]]
[status-im.components.icons.custom-icons :refer [ion-icon]] [status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.components.styles :refer [color-blue [status-im.contacts.views.contact :refer [contact-view]]
hamburger-icon [status-im.utils.platform :refer [platform-specific]]
icon-search
create-icon]]
[status-im.contacts.styles :as st]
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[status-im.utils.platform :refer [platform-specific]])) [status-im.contacts.styles :as st]
[status-im.components.styles :refer [color-blue
create-icon
icon-search]]))
(def contacts-limit 50) (def contacts-limit 50)
(defn toolbar-view [] (defn toolbar-view [show-search?]
(let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?]) (let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?])
actions (cond->> [{:image {:source {:uri :icon_search} actions (if new-contact?
:style icon-search} [(act/add #(dispatch [:navigate-to :new-contact]))])]
:handler (fn [])}] (toolbar-with-search
new-contact? {:show-search? show-search?
(into [{:image {:source {:uri :icon_add} :search-key :contact-list
:style icon-search} :title (label :t/contacts)
:handler #(dispatch [:navigate-to :new-contact])}]))] :search-placeholder (label :t/search-for)
[toolbar {:nav-action {:image {:source {:uri :icon_hamburger} :nav-action (act/hamburger open-drawer)
:style hamburger-icon} :actions actions
:handler open-drawer} :on-search-submit (fn [text]
:title (label :t/contacts) (when-not (str/blank? text)
:background-color toolbar-background2 (dispatch [:set :contacts-filter #(let [name (-> (or (:name %) "")
:style {:elevation 0} (str/lower-case))
:actions actions}])) text (str/lower-case text)]
(not= (.indexOf name text) -1))])
(dispatch [:set :contact-list-search-text text])
(dispatch [:navigate-to :contact-list-search-results])))})))
(defn subtitle-view [subtitle contacts-count] (defn subtitle-view [subtitle contacts-count]
[view st/contact-group-header-inner [view st/contact-group-header-inner
@ -81,9 +84,11 @@
[view [view
(doall (doall
(map (fn [contact] (map (fn [contact]
(let [click-handler (or click-handler on-press)] ^{:key contact}
^{:key contact} [contact-view {:contact contact
[contact-extended-view contact nil (click-handler contact) nil])) :extended? true
:on-click click-handler
:more-on-click nil}])
contacts))] contacts))]
(when (<= contacts-limit (count contacts)) (when (<= contacts-limit (count contacts))
[view st/show-all [view st/show-all
@ -110,16 +115,18 @@
[ion-icon {:name :md-create [ion-icon {:name :md-create
:style create-icon}]]]]) :style create-icon}]]]])
(defn contact-list [] (defn contact-list [_]
(let [peoples (subscribe [:get-added-people-with-limit contacts-limit]) (let [peoples (subscribe [:get-added-people-with-limit contacts-limit])
dapps (subscribe [:get-added-dapps-with-limit contacts-limit]) dapps (subscribe [:get-added-dapps-with-limit contacts-limit])
people-count (subscribe [:added-people-count]) people-count (subscribe [:added-people-count])
dapps-count (subscribe [:added-dapps-count]) dapps-count (subscribe [:added-dapps-count])
click-handler (subscribe [:get :contacts-click-handler]) click-handler (subscribe [:get :contacts-click-handler])
show-search (subscribe [:get-in [:toolbar-search :show]])
show-toolbar-shadow? (r/atom false)] show-toolbar-shadow? (r/atom false)]
(fn [] (fn [current-view?]
[view st/contacts-list-container [view st/contacts-list-container
[toolbar-view] [toolbar-view (and current-view?
(= @show-search :contact-list))]
[view {:style st/toolbar-shadow} [view {:style st/toolbar-shadow}
(when @show-toolbar-shadow? (when @show-toolbar-shadow?
[linear-gradient {:style st/contact-group-header-gradient-bottom [linear-gradient {:style st/contact-group-header-gradient-bottom
@ -128,7 +135,8 @@
[scroll-view {:style st/contact-groups [scroll-view {:style st/contact-groups
:onScroll (fn [e] :onScroll (fn [e]
(let [offset (.. e -nativeEvent -contentOffset -y)] (let [offset (.. e -nativeEvent -contentOffset -y)]
(reset! show-toolbar-shadow? (<= st/contact-group-header-height offset))))} (reset! show-toolbar-shadow?
(<= st/contact-group-header-height offset))))}
(when (pos? @dapps-count) (when (pos? @dapps-count)
[contact-group-view [contact-group-view
@dapps @dapps

View File

@ -0,0 +1,36 @@
(ns status-im.contacts.search-results
(:require-macros [status-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch]]
[status-im.components.status-bar :refer [status-bar]]
[status-im.components.react :refer [view
text
icon
list-view
list-item]]
[status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.contacts.views.contact :refer [contact-view]]
[status-im.utils.listview :refer [to-datasource]]
[status-im.utils.platform :refer [platform-specific]]
[status-im.i18n :refer [label]]
[status-im.contacts.styles :as st]))
(defview contacts-search-results []
[search-text [:get :contact-list-search-text]
contacts [:contacts-with-letters]]
[view st/search-container
[status-bar]
[toolbar {:nav-action (act/back #(dispatch [:navigate-back]))
:title search-text
:style (get-in platform-specific [:component-styles :toolbar])}]
(if (empty? contacts)
[view st/search-empty-view
;; todo change icon
[icon :group_big st/empty-contacts-icon]
[text {:style st/empty-contacts-text}
"No contacts found"]]
[list-view {:dataSource (to-datasource contacts)
:renderRow (fn [row _ _]
(list-item [contact-view {:contact row
:letter? true
:extended? true}]))}])])

View File

@ -10,17 +10,19 @@
color-gray2]] color-gray2]]
[status-im.components.toolbar.styles :refer [toolbar-background2]])) [status-im.components.toolbar.styles :refer [toolbar-background2]]))
(def contacts-list-container ;; Contacts list
{:flex 1})
(def toolbar-shadow (def toolbar-shadow
{:height 2 {:height 2
:backgroundColor toolbar-background2}) :background-color toolbar-background2})
(def contact-groups (def contact-groups
{:flex 1 {:flex 1
:background-color toolbar-background2}) :background-color toolbar-background2})
(def contacts-list-container
{:flex 1})
(def empty-contact-groups (def empty-contact-groups
(merge contact-groups (merge contact-groups
{:align-items :center {:align-items :center
@ -170,7 +172,7 @@
{:width 4 {:width 4
:height 16}) :height 16})
; new contact ; New contact
(def contact-form-container (def contact-form-container
{:flex 1 {:flex 1
@ -221,4 +223,18 @@
:margin-right 20 :margin-right 20
:margin-top 18 :margin-top 18
:width 20 :width 20
:height 20}) :height 20})
;; Contacts search
(def search-container
{:flex 1
:background-color color-white})
(def search-empty-view
{:flex 1
:background-color color-white
:align-items :center
:justify-content :center})

View File

@ -1,6 +1,7 @@
(ns status-im.contacts.subs (ns status-im.contacts.subs
(:require-macros [reagent.ratom :refer [reaction]]) (:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub subscribe]] (:require [re-frame.core :refer [register-sub subscribe]]
[clojure.string :as str]
[status-im.utils.identicon :refer [identicon]] [status-im.utils.identicon :refer [identicon]]
[taoensso.timbre :as log])) [taoensso.timbre :as log]))
@ -34,7 +35,6 @@
(let [contacts (subscribe [:all-added-contacts])] (let [contacts (subscribe [:all-added-contacts])]
(reaction (filter :dapp? @contacts))))) (reaction (filter :dapp? @contacts)))))
(register-sub :get-added-people-with-limit (register-sub :get-added-people-with-limit
(fn [_ [_ limit]] (fn [_ [_ limit]]
(let [contacts (subscribe [:all-added-people])] (let [contacts (subscribe [:all-added-people])]

View File

@ -7,8 +7,11 @@
(defn is-address? [s] (defn is-address? [s]
(.isAddress web3.prototype s)) (.isAddress web3.prototype s))
(defn unique-identity? [identity] (defn contact-can-be-added? [identity]
(not (contacts/exists? identity))) (if (contacts/exists? identity)
(-> (contacts/get-by-id identity)
(get :pending))
true))
(defn valid-length? [identity] (defn valid-length? [identity]
(let [length (count identity)] (let [length (count identity)]
@ -18,11 +21,11 @@
(is-address? identity)))) (is-address? identity))))
(s/def ::identity-length valid-length?) (s/def ::identity-length valid-length?)
(s/def ::unique-identity unique-identity?) (s/def ::contact-can-be-added contact-can-be-added?)
(s/def ::not-empty-string (s/and string? not-empty)) (s/def ::not-empty-string (s/and string? not-empty))
(s/def ::name ::not-empty-string) (s/def ::name ::not-empty-string)
(s/def ::whisper-identity (s/and ::not-empty-string (s/def ::whisper-identity (s/and ::not-empty-string
::unique-identity ::contact-can-be-added
::identity-length)) ::identity-length))
(s/def ::contact (s/keys :req-un [::name ::whisper-identity] (s/def ::contact (s/keys :req-un [::name ::whisper-identity]

View File

@ -3,37 +3,31 @@
(:require [status-im.components.react :refer [view text icon touchable-highlight]] (:require [status-im.components.react :refer [view text icon touchable-highlight]]
[re-frame.core :refer [dispatch]] [re-frame.core :refer [dispatch]]
[status-im.contacts.styles :as st] [status-im.contacts.styles :as st]
[status-im.contacts.views.contact-inner :refer [contact-inner-view]])) [status-im.contacts.views.contact-inner :refer [contact-inner-view]]
[status-im.utils.platform :refer [platform-specific]]))
(defn on-press [{:keys [whisper-identity]}] (defn- on-press [{:keys [whisper-identity]}]
#(dispatch [:start-chat whisper-identity {} :navigation-replace])) (dispatch [:start-chat whisper-identity {} :navigation-replace]))
(defn- more-on-press [contact]
(dispatch [:open-contact-menu (:list-selection-fn platform-specific) contact]))
(defn letter-view [letter] (defn letter-view [letter]
[view st/letter-container [view st/letter-container
(when letter (when letter
[text {:style st/letter-text} letter])]) [text {:style st/letter-text} letter])])
(defview contact-view-with-letter [{:keys [whisper-identity letter] :as contact} click-handler action params] (defview contact-view [{{:keys [whisper-identity letter dapp?] :as contact} :contact
[touchable-highlight :keys [extended? letter? on-click more-on-click info]}]
{:onPress #(click-handler contact action params)}
[view st/contact-container
[letter-view letter]
[contact-inner-view contact]]])
(defview contact-view [{:keys [whisper-identity] :as contact}]
[chat [:get-chat whisper-identity]] [chat [:get-chat whisper-identity]]
[touchable-highlight [touchable-highlight
{:onPress (on-press contact)} {:on-press #((or on-click on-press) contact)}
[view st/contact-container
[contact-inner-view contact]]])
(defview contact-extended-view [{:keys [whisper-identity] :as contact} info click-handler more-click-handler]
[chat [:get-chat whisper-identity]]
[touchable-highlight
{:onPress click-handler}
[view st/contact-container [view st/contact-container
(when letter?
[letter-view letter])
[contact-inner-view contact info] [contact-inner-view contact info]
[touchable-highlight (when (and extended? (not dapp?))
{:on-press more-click-handler} [touchable-highlight
[view st/more-btn {:on-press #((or more-on-click more-on-press) contact)}
[icon :more_vertical st/more-btn-icon]]]]]) [view st/more-btn
[icon :more_vertical st/more-btn-icon]]])]])

View File

@ -6,12 +6,11 @@
touchable-highlight touchable-highlight
list-view list-view
list-item]] list-item]]
[status-im.contacts.views.contact :refer [contact-view [status-im.contacts.views.contact :refer [contact-view]]
on-press
contact-view-with-letter]]
[status-im.components.text-field.view :refer [text-field]] [status-im.components.text-field.view :refer [text-field]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :refer [toolbar-background1]] [status-im.components.toolbar.styles :refer [toolbar-background1]]
[status-im.components.drawer.view :refer [drawer-view open-drawer]] [status-im.components.drawer.view :refer [drawer-view open-drawer]]
[status-im.components.styles :refer [icon-search [status-im.components.styles :refer [icon-search
@ -42,11 +41,10 @@
(defn render-row [chat-modal click-handler action params] (defn render-row [chat-modal click-handler action params]
(fn [row _ _] (fn [row _ _]
(list-item (list-item
(if chat-modal [contact-view {:contact row
[contact-view-with-letter row click-handler action params] :letter? chat-modal
[contact-view row :on-click (if click-handler
(or click-handler #(click-handler row action params))}])))
(on-press row))]))))
(defn contact-list-entry [{:keys [click-handler icon icon-style label]}] (defn contact-list-entry [{:keys [click-handler icon icon-style label]}]
[touchable-highlight [touchable-highlight
@ -71,14 +69,10 @@
:t/contacts-group-dapps :t/contacts-group-dapps
:t/contacts-group-new-chat))) :t/contacts-group-new-chat)))
:nav-action (when modal :nav-action (when modal
{:handler #(dispatch [:navigate-back]) (act/back #(dispatch [:navigate-back])))
:image {:source {:uri :icon_back}
:style icon-back}})
:background-color toolbar-background1 :background-color toolbar-background1
:style (get-in platform-specific [:component-styles :toolbar]) :style (get-in platform-specific [:component-styles :toolbar])
:actions [{:image {:source {:uri :icon_search} :actions [(act/search #())]}]])
:style icon-search}
:handler (fn [])}]}]])
(defview contact-list [] (defview contact-list []
[contacts [:contacts-with-letters] [contacts [:contacts-with-letters]

View File

@ -11,6 +11,7 @@
[status-im.utils.identicon :refer [identicon]] [status-im.utils.identicon :refer [identicon]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :refer [toolbar-title-container [status-im.components.toolbar.styles :refer [toolbar-title-container
toolbar-title-text toolbar-title-text
toolbar-background1]] toolbar-background1]]
@ -24,6 +25,7 @@
[cljs.spec :as s] [cljs.spec :as s]
[status-im.contacts.validations :as v] [status-im.contacts.validations :as v]
[status-im.contacts.styles :as st] [status-im.contacts.styles :as st]
[status-im.data-store.contacts :as contacts]
[status-im.utils.gfycat.core :refer [generate-gfy]] [status-im.utils.gfycat.core :refer [generate-gfy]]
[status-im.utils.hex :refer [normalize-hex]] [status-im.utils.hex :refer [normalize-hex]]
[status-im.utils.platform :refer [platform-specific]])) [status-im.utils.platform :refer [platform-specific]]))
@ -44,11 +46,15 @@
:address id :address id
:photo-path (identicon whisper-identity) :photo-path (identicon whisper-identity)
:whisper-identity whisper-identity}] :whisper-identity whisper-identity}]
(dispatch [:add-new-contact contact])) (if (contacts/exists? whisper-identity)
(dispatch [:add-pending-contact whisper-identity])
(dispatch [:add-new-contact contact])))
(dispatch [:set :new-contact-public-key-error (label :t/unknown-address)])))) (dispatch [:set :new-contact-public-key-error (label :t/unknown-address)]))))
(dispatch [:add-new-contact {:name (generate-gfy) (if (contacts/exists? id)
:photo-path (identicon id) (dispatch [:add-pending-contact id])
:whisper-identity id}]))) (dispatch [:add-new-contact {:name (generate-gfy)
:photo-path (identicon id)
:whisper-identity id}]))))
(defn- validation-error-message (defn- validation-error-message
[whisper-identity {:keys [address public-key]} error] [whisper-identity {:keys [address public-key]} error]
@ -57,7 +63,7 @@
(normalize-hex whisper-identity)) (normalize-hex whisper-identity))
(label :t/can-not-add-yourself) (label :t/can-not-add-yourself)
(not (s/valid? ::v/unique-identity whisper-identity)) (not (s/valid? ::v/contact-can-be-added whisper-identity))
(label :t/contact-already-added) (label :t/contact-already-added)
(not (s/valid? ::v/whisper-identity whisper-identity)) (not (s/valid? ::v/whisper-identity whisper-identity))
@ -103,9 +109,7 @@
[status-bar] [status-bar]
[toolbar {:background-color toolbar-background1 [toolbar {:background-color toolbar-background1
:style (get-in platform-specific [:component-styles :toolbar]) :style (get-in platform-specific [:component-styles :toolbar])
:nav-action {:image {:source {:uri :icon_back} :nav-action (act/back #(dispatch [:navigate-back]))
:style icon-back}
:handler #(dispatch [:navigate-back])}
:title (label :t/add-new-contact) :title (label :t/add-new-contact)
:actions (toolbar-actions new-contact-identity account error)}] :actions (toolbar-actions new-contact-identity account error)}]
[view st/form-container [view st/form-container

View File

@ -9,26 +9,25 @@
(defn get-by-id (defn get-by-id
[whisper-identity] [whisper-identity]
(data-store/get-by-id whisper-identity)) (data-store/get-by-id-cljs whisper-identity))
(defn save (defn save
[{:keys [whisper-identity pending] :as contact}] [{:keys [whisper-identity pending] :as contact}]
(let [{pending-db :pending (let [{pending-db :pending
:as contact-db} (data-store/get-by-id whisper-identity) :as contact-db} (data-store/get-by-id whisper-identity)
contact (assoc contact :pending (boolean (if contact-db contact (assoc contact :pending
;; TODO: (boolean (if contact-db
;; this is temporary fix for pending users (if (nil? pending) pending-db pending)
;; we need to change this (if ...) to (and pending-db pending) pending)))]
(if (nil? pending)
pending-db
(and pending-db pending))
pending)))]
(data-store/save contact (if contact-db true false)))) (data-store/save contact (if contact-db true false))))
(defn save-all (defn save-all
[contacts] [contacts]
(mapv save contacts)) (mapv save contacts))
(defn delete [contact]
(data-store/delete contact))
(defn exists? (defn exists?
[whisper-identity] [whisper-identity]
(data-store/exists? whisper-identity)) (data-store/exists? whisper-identity))

View File

@ -0,0 +1,15 @@
(ns status-im.data-store.processed-messages
(:require [status-im.data-store.realm.processed-messages :as data-store]
[taoensso.timbre :as log])
(:refer-clojure :exclude [exists?]))
(defn get-filtered
[condition]
(data-store/get-filtered-as-list condition))
(defn save
[processed-message]
(data-store/save processed-message))
(defn delete [condition]
(data-store/delete condition))

View File

@ -14,12 +14,21 @@
(defn get-by-id (defn get-by-id
[whisper-identity] [whisper-identity]
(realm/get-one-by-field-clj @realm/account-realm :contact :whisper-identity whisper-identity)) (realm/get-one-by-field @realm/account-realm :contact :whisper-identity whisper-identity))
(defn get-by-id-cljs
[whisper-identity]
(some-> (get-by-id whisper-identity)
(js->clj :keywordize-keys true)))
(defn save (defn save
[contact update?] [contact update?]
(realm/save @realm/account-realm :contact contact update?)) (realm/save @realm/account-realm :contact contact update?))
(defn delete
[{:keys [whisper-identity]}]
(realm/delete @realm/account-realm (get-by-id whisper-identity)))
(defn exists? (defn exists?
[whisper-identity] [whisper-identity]
(realm/exists? @realm/account-realm :contact {:whisper-identity whisper-identity})) (realm/exists? @realm/account-realm :contact {:whisper-identity whisper-identity}))

View File

@ -0,0 +1,25 @@
(ns status-im.data-store.realm.processed-messages
(:require [status-im.data-store.realm.core :as realm])
(:refer-clojure :exclude [exists?]))
(defn get-all
[]
(-> (realm/get-all @realm/account-realm :processed-message)
(realm/sorted :ttl :asc)))
(defn get-filtered
[condition]
(realm/filtered (get-all) condition))
(defn get-filtered-as-list
[condition]
(-> (get-filtered condition)
realm/realm-collection->list))
(defn save
[processed-message]
(realm/save @realm/account-realm :processed-message processed-message))
(defn delete
[condition]
(realm/delete @realm/account-realm (get-filtered condition)))

View File

@ -7,6 +7,7 @@
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store] [status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
[status-im.data-store.realm.schemas.account.v1.message :as message] [status-im.data-store.realm.schemas.account.v1.message :as message]
[status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message] [status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message]
[status-im.data-store.realm.schemas.account.v1.processed-message :as processed-message]
[status-im.data-store.realm.schemas.account.v1.request :as request] [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.tag :as tag]
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status] [status-im.data-store.realm.schemas.account.v1.user-status :as user-status]
@ -20,6 +21,7 @@
kv-store/schema kv-store/schema
message/schema message/schema
pending-message/schema pending-message/schema
processed-message/schema
request/schema request/schema
tag/schema tag/schema
user-status/schema]) user-status/schema])
@ -34,6 +36,7 @@
(kv-store/migration old-realm new-realm) (kv-store/migration old-realm new-realm)
(message/migration old-realm new-realm) (message/migration old-realm new-realm)
(pending-message/migration old-realm new-realm) (pending-message/migration old-realm new-realm)
(processed-message/migration old-realm new-realm)
(request/migration old-realm new-realm) (request/migration old-realm new-realm)
(tag/migration old-realm new-realm) (tag/migration old-realm new-realm)
(user-status/migration old-realm new-realm)) (user-status/migration old-realm new-realm))

View File

@ -0,0 +1,13 @@
(ns status-im.data-store.realm.schemas.account.v1.processed-message
(:require [taoensso.timbre :as log]))
(def schema {:name :processed-message
:primaryKey :id
:properties {:id :string
:message-id :string
:type {:type "string"
:optional true}
:ttl :int}})
(defn migration [old-realm new-realm]
(log/debug "migrating processed-message schema"))

View File

@ -25,8 +25,8 @@
(defmethod nav/preload-data! :discover (defmethod nav/preload-data! :discover
[db _] [db _]
(dispatch [:set :discover-show-search? false])
(-> db (-> db
(assoc-in [:toolbar-search :show] nil)
(assoc :tags (discoveries/get-all-tags)) (assoc :tags (discoveries/get-all-tags))
(assoc :discoveries (->> (discoveries/get-all :desc) (assoc :discoveries (->> (discoveries/get-all :desc)
(map (fn [{:keys [message-id] :as discover}] (map (fn [{:keys [message-id] :as discover}]

View File

@ -1,6 +1,7 @@
(ns status-im.discover.screen (ns status-im.discover.screen
(:require-macros [status-im.utils.views :refer [defview]]) (:require-macros [status-im.utils.views :refer [defview]])
(:require (:require
[reagent.core :as r]
[re-frame.core :refer [dispatch subscribe]] [re-frame.core :refer [dispatch subscribe]]
[clojure.string :as str] [clojure.string :as str]
[status-im.components.react :refer [view [status-im.components.react :refer [view
@ -8,52 +9,33 @@
text text
text-input text-input
icon]] icon]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar-with-search]]
[status-im.components.toolbar.actions :as act]
[status-im.components.drawer.view :refer [open-drawer]] [status-im.components.drawer.view :refer [open-drawer]]
[status-im.discover.styles :as st]
[status-im.i18n :refer [label]]
[status-im.components.carousel.carousel :refer [carousel]] [status-im.components.carousel.carousel :refer [carousel]]
[status-im.discover.views.popular-list :refer [discover-popular-list]] [status-im.discover.views.popular-list :refer [discover-popular-list]]
[status-im.discover.views.discover-list-item :refer [discover-list-item]] [status-im.discover.views.discover-list-item :refer [discover-list-item]]
[status-im.contacts.styles :as contacts-styles]
[status-im.utils.platform :refer [platform-specific]] [status-im.utils.platform :refer [platform-specific]]
[reagent.core :as r])) [status-im.i18n :refer [label]]
[status-im.discover.styles :as st]
[status-im.contacts.styles :as contacts-st]))
(defn get-hashtags [status] (defn get-hashtags [status]
(let [hashtags (map #(str/lower-case (str/replace % #"#" "")) (re-seq #"[^ !?,;:.]+" status))] (let [hashtags (map #(str/lower-case (str/replace % #"#" "")) (re-seq #"[^ !?,;:.]+" status))]
(or hashtags []))) (or hashtags [])))
(defn title-content [show-search?] (defn toolbar-view [show-search?]
[view st/discover-toolbar-content [toolbar-with-search
(if show-search? {:show-search? show-search?
[text-input {:style st/discover-search-input :search-key :discover
:auto-focus true :title (label :t/discover)
:placeholder (label :t/search-tags) :search-placeholder (label :t/search-tags)
:on-blur (fn [e] :nav-action (act/hamburger open-drawer)
(dispatch [:set :discover-show-search? false])) :on-search-submit (fn [text]
:on-submit-editing (fn [e] (when-not (str/blank? text)
(let [search (aget e "nativeEvent" "text") (let [hashtags (get-hashtags text)]
hashtags (get-hashtags search)] (dispatch [:set :discover-search-tags hashtags])
(dispatch [:set :discover-search-tags hashtags]) (dispatch [:navigate-to :discover-search-results]))))}])
(dispatch [:navigate-to :discover-search-results])))}]
[view
[text {:style st/discover-title
:font :toolbar-title}
(label :t/discover)]])])
(defn toogle-search [current-value]
(dispatch [:set :discover-show-search? (not current-value)]))
(defn discover-toolbar [show-search?]
[toolbar
{:style st/discover-toolbar
:nav-action {:image {:source {:uri :icon_hamburger}
:style st/hamburger-icon}
:handler open-drawer}
:custom-content [title-content show-search?]
:actions [{:image {:source {:uri :icon_search}
:style st/search-icon}
:handler #(toogle-search show-search?)}]}])
(defn title [label-kw spacing?] (defn title [label-kw spacing?]
[view st/section-spacing [view st/section-spacing
@ -91,19 +73,20 @@
:current-account current-account}]))]])) :current-account current-account}]))]]))
(defview discover [current-view?] (defview discover [current-view?]
[show-search? [:get :discover-show-search?] [show-search [:get-in [:toolbar-search :show]]
contacts [:get :contacts] contacts [:get :contacts]
current-account [:get-current-account] current-account [:get-current-account]
discoveries [:get-recent-discoveries]] discoveries [:get-recent-discoveries]]
[view st/discover-container [view st/discover-container
[discover-toolbar (and current-view? show-search?)] [toolbar-view (and current-view?
(= show-search :discover))]
(if discoveries (if discoveries
[scroll-view st/scroll-view-container [scroll-view st/scroll-view-container
[discover-popular {:contacts contacts [discover-popular {:contacts contacts
:current-account current-account}] :current-account current-account}]
[discover-recent {:current-account current-account}]] [discover-recent {:current-account current-account}]]
[view contacts-styles/empty-contact-groups [view contacts-st/empty-contact-groups
;; todo change icon ;; todo change icon
[icon :group_big contacts-styles/empty-contacts-icon] [icon :group_big contacts-st/empty-contacts-icon]
[text {:style contacts-styles/empty-contacts-text} [text {:style contacts-st/empty-contacts-text}
(label :t/no-statuses-discovered)]])]) (label :t/no-statuses-discovered)]])])

View File

@ -9,12 +9,13 @@
list-view list-view
list-item list-item
scroll-view]] scroll-view]]
[status-im.i18n :refer [label]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.discover.views.discover-list-item :refer [discover-list-item]] [status-im.discover.views.discover-list-item :refer [discover-list-item]]
[status-im.discover.styles :as st]
[status-im.utils.platform :refer [platform-specific]] [status-im.utils.platform :refer [platform-specific]]
[status-im.contacts.styles :as contacts-styles] [status-im.i18n :refer [label]]
[status-im.discover.styles :as st]
[status-im.contacts.styles :as contacts-st]
[taoensso.timbre :as log])) [taoensso.timbre :as log]))
(defn render-separator [_ row-id _] (defn render-separator [_ row-id _]
@ -43,20 +44,19 @@
datasource (to-datasource discoveries)] datasource (to-datasource discoveries)]
[view st/discover-tag-container [view st/discover-tag-container
[status-bar] [status-bar]
[toolbar {:nav-action {:image {:source {:uri :icon_back} [toolbar {:nav-action (act/back #(dispatch [:navigate-back]))
:style st/icon-back}
:handler #(dispatch [:navigate-back])}
:custom-content (title-content tags) :custom-content (title-content tags)
:style st/discover-tag-toolbar}] :style st/discover-tag-toolbar}]
(if (empty? discoveries) (if (empty? discoveries)
[view st/empty-view [view st/empty-view
;; todo change icon ;; todo change icon
[icon :group_big contacts-styles/empty-contacts-icon] [icon :group_big contacts-st/empty-contacts-icon]
[text {:style contacts-styles/empty-contacts-text} [text {:style contacts-st/empty-contacts-text}
(label :t/no-statuses-found)]] (label :t/no-statuses-found)]]
[list-view {:dataSource datasource [list-view {:dataSource datasource
:renderRow (fn [row _ _] :renderRow (fn [row _ _]
(list-item [discover-list-item {:message row (list-item [discover-list-item
:current-account current-account}])) {:message row
:current-account current-account}]))
:renderSeparator render-separator :renderSeparator render-separator
:style st/recent-list}])])) :style st/recent-list}])]))

View File

@ -1,9 +1,10 @@
(ns status-im.discover.styles (ns status-im.discover.styles
(:require [status-im.components.styles :refer [color-gray2 (:require [status-im.components.styles :refer [color-gray2
color-white]] color-white
color-light-gray]]
[status-im.components.toolbar.styles :refer [toolbar-background2]])) [status-im.components.toolbar.styles :refer [toolbar-background2]]))
;; common ;; Common
(def row-separator (def row-separator
{:border-bottom-width 1 {:border-bottom-width 1
@ -22,30 +23,6 @@
:align-items :center :align-items :center
:justify-content :center}) :justify-content :center})
;; Toolbar
(def discover-toolbar-content
{:flex 1
:align-items :center
:justify-content :center})
(def discover-toolbar
{:background-color toolbar-background2
:elevation 0})
(def discover-search-input
{:flex 1
:align-self "stretch"
:margin-left 18
:font-size 14
:color "#7099e6"})
(def discover-title
{:color "#000000de"
:align-self :center
:text-align :center
:font-size 16})
(def section-spacing (def section-spacing
{:padding 16}) {:padding 16})
@ -134,7 +111,7 @@
(def discover-tag-container (def discover-tag-container
{:flex 1 {:flex 1
:backgroundColor "#eef2f5"}) :backgroundColor color-light-gray})
(def tag-title-scroll (def tag-title-scroll
{:flex 1 {:flex 1
@ -165,10 +142,6 @@
{:flex 1 {:flex 1
:backgroundColor color-white}) :backgroundColor color-white})
(def hamburger-icon
{:width 16
:height 12})
(def search-icon (def search-icon
{:width 17 {:width 17
:height 17}) :height 17})

View File

@ -1,9 +1,12 @@
(ns status-im.group-settings.views.member (ns status-im.group-settings.views.member
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[status-im.contacts.views.contact :refer [contact-extended-view]] [status-im.contacts.views.contact :refer [contact-view]]
[status-im.i18n :refer [label]])) [status-im.i18n :refer [label]]))
(defn member-view [{:keys [whisper-identity role] :as contact}] (defn member-view [{:keys [whisper-identity role] :as contact}]
;; TODO implement :role property for group chat contact ;; TODO implement :role property for group chat contact
[contact-extended-view contact role [contact-view
#(dispatch [:set :selected-participants #{whisper-identity}])]) {:contact contact
:extended? true
:info role
:on-click #(dispatch [:set :selected-participants #{whisper-identity}])}])

View File

@ -68,6 +68,7 @@
(u/side-effect! (u/side-effect!
(fn [_ [_ address]] (fn [_ [_ address]]
(dispatch [:initialize-account-db]) (dispatch [:initialize-account-db])
(dispatch [:load-processed-messages])
(dispatch [:initialize-protocol address]) (dispatch [:initialize-protocol address])
(dispatch [:initialize-sync-listener]) (dispatch [:initialize-sync-listener])
(dispatch [:initialize-chats]) (dispatch [:initialize-chats])

View File

@ -10,6 +10,7 @@
orientation orientation
splash-screen]] splash-screen]]
[status-im.components.main-tabs :refer [main-tabs]] [status-im.components.main-tabs :refer [main-tabs]]
[status-im.contacts.search-results :refer [contacts-search-results]]
[status-im.contacts.views.contact-list :refer [contact-list]] [status-im.contacts.views.contact-list :refer [contact-list]]
[status-im.contacts.views.new-contact :refer [new-contact]] [status-im.contacts.views.new-contact :refer [new-contact]]
[status-im.qr-scanner.screen :refer [qr-scanner]] [status-im.qr-scanner.screen :refer [qr-scanner]]
@ -82,6 +83,7 @@
:new-group new-group :new-group new-group
:group-settings group-settings :group-settings group-settings
:contact-list main-tabs :contact-list main-tabs
:contact-list-search-results contacts-search-results
:group-contacts contact-list :group-contacts contact-list
:new-contact new-contact :new-contact new-contact
:qr-scanner qr-scanner :qr-scanner qr-scanner

View File

@ -12,6 +12,7 @@
[status-im.components.icons.custom-icons :refer [ion-icon]] [status-im.components.icons.custom-icons :refer [ion-icon]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :refer [toolbar-background1]] [status-im.components.toolbar.styles :refer [toolbar-background1]]
[status-im.utils.image-processing :refer [img->base64]] [status-im.utils.image-processing :refer [img->base64]]
[status-im.profile.photo-capture.styles :as st] [status-im.profile.photo-capture.styles :as st]
@ -35,9 +36,7 @@
[view st/container [view st/container
[status-bar] [status-bar]
[toolbar {:title (label :t/image-source-title) [toolbar {:title (label :t/image-source-title)
:nav-action {:image {:source {:uri :icon_back} :nav-action (act/back #(dispatch [:navigate-back]))
:style icon-back}
:handler #(dispatch [:navigate-back])}
:background-color toolbar-background1}] :background-color toolbar-background1}]
[camera {:style {:flex 1} [camera {:style {:flex 1}
:aspect (:fill aspects) :aspect (:fill aspects)
@ -54,4 +53,4 @@
(.catch #(log/debug "Error capturing image: " %)))))} (.catch #(log/debug "Error capturing image: " %)))))}
[view [view
[ion-icon {:name :md-camera [ion-icon {:name :md-camera
:style {:font-size 36}}]]]]])) :style {:font-size 36}}]]]]]))

View File

@ -35,6 +35,7 @@
;; discoveries ;; discoveries
(def watch-user! discoveries/watch-user!) (def watch-user! discoveries/watch-user!)
(def stop-watching-user! discoveries/stop-watching-user!)
(def contact-request! discoveries/contact-request!) (def contact-request! discoveries/contact-request!)
(def broadcast-profile! discoveries/broadcast-profile!) (def broadcast-profile! discoveries/broadcast-profile!)
(def send-status! discoveries/send-status!) (def send-status! discoveries/send-status!)

View File

@ -46,6 +46,13 @@
:topics [(make-discover-topic identity)]} :topics [(make-discover-topic identity)]}
(l/message-listener (dissoc options :identity)))) (l/message-listener (dissoc options :identity))))
(defn stop-watching-user!
[{:keys [web3 identity] :as options}]
(f/remove-filter!
web3
{:from identity
:topics [(make-discover-topic identity)]}))
(s/def :contact-request/contact map?) (s/def :contact-request/contact map?)
(s/def :contact-request/payload (s/def :contact-request/payload

View File

@ -5,12 +5,15 @@
[status-im.data-store.contacts :as contacts] [status-im.data-store.contacts :as contacts]
[status-im.data-store.messages :as messages] [status-im.data-store.messages :as messages]
[status-im.data-store.pending-messages :as pending-messages] [status-im.data-store.pending-messages :as pending-messages]
[status-im.data-store.processed-messages :as processed-messages]
[status-im.data-store.chats :as chats] [status-im.data-store.chats :as chats]
[status-im.protocol.core :as protocol] [status-im.protocol.core :as protocol]
[status-im.constants :refer [text-content-type [status-im.constants :refer [text-content-type
blocks-per-hour]] blocks-per-hour]]
[status-im.i18n :refer [label]] [status-im.i18n :refer [label]]
[status-im.utils.random :as random] [status-im.utils.random :as random]
[status-im.protocol.message-cache :as cache]
[status-im.utils.datetime :as dt]
[taoensso.timbre :as log :refer-macros [debug]] [taoensso.timbre :as log :refer-macros [debug]]
[status-im.constants :as c] [status-im.constants :as c]
[status-im.components.status :as status])) [status-im.components.status :as status]))
@ -77,33 +80,41 @@
(register-handler :incoming-message (register-handler :incoming-message
(u/side-effect! (u/side-effect!
(fn [_ [_ type {:keys [payload] :as message}]] (fn [_ [_ type {:keys [payload ttl id] :as message}]]
(debug :incoming-message type) (let [message-id (or id (:message-id payload))]
(case type (when-not (cache/exists? message-id type)
:message (dispatch [:received-protocol-message! message]) (let [ttl-s (* 1000 (or ttl 120))
:group-message (dispatch [:received-protocol-message! message]) processed-message {:id (random/id)
:ack (if (#{:message :group-message} (:type payload)) :message-id message-id
(dispatch [:message-delivered message]) :type type
(dispatch [:pending-message-remove message])) :ttl (+ (dt/now-ms) ttl-s)}]
:seen (dispatch [:message-seen message]) (cache/add! processed-message)
:group-invitation (dispatch [:group-chat-invite-received message]) (processed-messages/save processed-message))
:update-group (dispatch [:update-group-message message]) (case type
:add-group-identity (dispatch [:participant-invited-to-group message]) :message (dispatch [:received-protocol-message! message])
:remove-group-identity (dispatch [:participant-removed-from-group message]) :group-message (dispatch [:received-protocol-message! message])
:leave-group (dispatch [:participant-left-group message]) :ack (if (#{:message :group-message} (:type payload))
:contact-request (dispatch [:contact-request-received message]) (dispatch [:message-delivered message])
:discover (dispatch [:status-received message]) (dispatch [:pending-message-remove message]))
:discoveries-request (dispatch [:discoveries-request-received message]) :seen (dispatch [:message-seen message])
:discoveries-response (dispatch [:discoveries-response-received message]) :group-invitation (dispatch [:group-chat-invite-received message])
:profile (dispatch [:contact-update-received message]) :update-group (dispatch [:update-group-message message])
:online (dispatch [:contact-online-received message]) :add-group-identity (dispatch [:participant-invited-to-group message])
:pending (dispatch [:pending-message-upsert message]) :remove-group-identity (dispatch [:participant-removed-from-group message])
:sent (let [{:keys [to id group-id]} message :leave-group (dispatch [:participant-left-group message])
message' {:from to :contact-request (dispatch [:contact-request-received message])
:payload {:message-id id :discover (dispatch [:status-received message])
:group-id group-id}}] :discoveries-request (dispatch [:discoveries-request-received message])
(dispatch [:message-sent message'])) :discoveries-response (dispatch [:discoveries-response-received message])
(debug "Unknown message type" type))))) :profile (dispatch [:contact-update-received message])
:online (dispatch [:contact-online-received message])
:pending (dispatch [:pending-message-upsert message])
:sent (let [{:keys [to id group-id]} message
message' {:from to
:payload {:message-id id
:group-id group-id}}]
(dispatch [:message-sent message']))
(debug "Unknown message type" type)))))))
(defn system-message (defn system-message
([message-id timestamp content] ([message-id timestamp content]

View File

@ -0,0 +1,21 @@
(ns status-im.protocol.message-cache)
(defonce messages-set (atom #{}))
(defonce messages-map (atom {}))
(defn init!
[messages]
(reset! messages-set (into #{} messages))
(reset! messages-map (->> messages
(map (fn [{:keys [message-id type] :as message}]
[[message-id type] message]))
(into {}))))
(defn add!
[{:keys [message-id type] :as message}]
(swap! messages-set conj message)
(swap! messages-map conj [[message-id type] message]))
(defn exists?
[message-id type]
(get @messages-map [message-id type]))

View File

@ -28,7 +28,8 @@
(assoc :content content') (assoc :content content')
prn-str prn-str
u/from-utf8)] u/from-utf8)]
(-> message (select-keys [:from :to :topics :ttl]) (-> message
(select-keys [:from :to :topics :ttl])
(assoc :payload payload')))) (assoc :payload payload'))))
(s/def :shh/pending-message (s/def :shh/pending-message
@ -110,7 +111,7 @@
(let [message (get-in messages [id to]) (let [message (get-in messages [id to])
message' (when message message' (when message
(assoc message :was-sent? true (assoc message :was-sent? true
:attemps 1))] :attempts 1))]
(if message' (if message'
(assoc-in messages [id to] message') (assoc-in messages [id to] message')
messages))))] messages))))]

View File

@ -8,6 +8,7 @@
icon-back]] icon-back]]
[status-im.components.status-bar :refer [status-bar]] [status-im.components.status-bar :refer [status-bar]]
[status-im.components.toolbar.view :refer [toolbar]] [status-im.components.toolbar.view :refer [toolbar]]
[status-im.components.toolbar.actions :as act]
[status-im.components.toolbar.styles :refer [toolbar-background1]] [status-im.components.toolbar.styles :refer [toolbar-background1]]
[status-im.qr-scanner.styles :as st] [status-im.qr-scanner.styles :as st]
[status-im.utils.types :refer [json->clj]] [status-im.utils.types :refer [json->clj]]
@ -20,12 +21,7 @@
[toolbar {:title title [toolbar {:title title
:background-color toolbar-background1 :background-color toolbar-background1
:nav-action (when modal :nav-action (when modal
{:handler #(dispatch [:navigate-back]) (act/back #(dispatch [:navigate-back])))}]])
:image {:source {:uri :icon_back}
:style icon-back}})
:actions [{:image {:source {:uri :icon_lock_white}
:style icon-search}
:handler #()}]}]])
(defview qr-scanner [] (defview qr-scanner []
[identifier [:get :current-qr-context]] [identifier [:get :current-qr-context]]

View File

@ -8,6 +8,8 @@
:chat-name "Chat name" :chat-name "Chat name"
:notifications-title "Notifications and sounds" :notifications-title "Notifications and sounds"
:offline "Offline" :offline "Offline"
:search-for "Search for..."
:cancel "Cancel"
;drawer ;drawer
:invite-friends "Invite friends" :invite-friends "Invite friends"
@ -108,7 +110,6 @@
:new-group-chat "New group chat" :new-group-chat "New group chat"
;discover ;discover
:discover "Discover" :discover "Discover"
:none "None" :none "None"
:search-tags "Type your search tags here" :search-tags "Type your search tags here"
@ -123,6 +124,7 @@
;contacts ;contacts
:contacts "Contacts" :contacts "Contacts"
:new-contact "New Contact" :new-contact "New Contact"
:remove-contact "Remove contact"
:show-all "SHOW ALL" :show-all "SHOW ALL"
:contacts-group-dapps "ÐApps" :contacts-group-dapps "ÐApps"
:contacts-group-people "People" :contacts-group-people "People"