From 395aa9d807683663e5db95b77a7d4db13f6c68e9 Mon Sep 17 00:00:00 2001 From: alwx Date: Mon, 5 Dec 2016 13:50:47 +0300 Subject: [PATCH] Contacts search (#448); Processed messages cache (#552); Fix for adding pending contacts manually (#554); Lots of fixes for toolbar & contact item --- src/status_im/accounts/handlers.cljs | 11 +++ src/status_im/accounts/login/screen.cljs | 5 +- src/status_im/accounts/recover/screen.cljs | 11 +-- src/status_im/accounts/screen.cljs | 7 +- src/status_im/android/core.cljs | 2 + src/status_im/chats_list/screen.cljs | 45 +++++------ src/status_im/chats_list/styles.cljs | 16 ++-- src/status_im/components/main_tabs.cljs | 4 +- src/status_im/components/styles.cljs | 4 - src/status_im/components/toolbar/actions.cljs | 31 ++++++++ src/status_im/components/toolbar/styles.cljs | 46 +++++++++++- src/status_im/components/toolbar/view.cljs | 45 ++++++++++- src/status_im/contacts/handlers.cljs | 42 +++++++++-- src/status_im/contacts/screen.cljs | 74 ++++++++++--------- src/status_im/contacts/search_results.cljs | 36 +++++++++ src/status_im/contacts/styles.cljs | 28 +++++-- src/status_im/contacts/subs.cljs | 2 +- src/status_im/contacts/validations.cljs | 11 ++- src/status_im/contacts/views/contact.cljs | 40 +++++----- .../contacts/views/contact_list.cljs | 22 ++---- src/status_im/contacts/views/new_contact.cljs | 20 +++-- src/status_im/data_store/contacts.cljs | 19 +++-- .../data_store/processed_messages.cljs | 15 ++++ src/status_im/data_store/realm/contacts.cljs | 13 +++- .../data_store/realm/processed_messages.cljs | 25 +++++++ .../realm/schemas/account/v1/core.cljs | 5 +- .../schemas/account/v1/processed_message.cljs | 13 ++++ src/status_im/discover/handlers.cljs | 2 +- src/status_im/discover/screen.cljs | 65 ++++++---------- src/status_im/discover/search_results.cljs | 20 ++--- src/status_im/discover/styles.cljs | 35 +-------- .../group_settings/views/member.cljs | 9 ++- src/status_im/handlers.cljs | 1 + src/status_im/ios/core.cljs | 2 + .../profile/photo_capture/screen.cljs | 7 +- src/status_im/protocol/core.cljs | 1 + src/status_im/protocol/discoveries.cljs | 7 ++ src/status_im/protocol/handlers.cljs | 65 +++++++++------- src/status_im/protocol/message_cache.cljs | 21 ++++++ src/status_im/protocol/web3/delivery.cljs | 5 +- src/status_im/qr_scanner/screen.cljs | 8 +- src/status_im/translations/en.cljs | 4 +- 42 files changed, 553 insertions(+), 291 deletions(-) create mode 100644 src/status_im/components/toolbar/actions.cljs create mode 100644 src/status_im/contacts/search_results.cljs create mode 100644 src/status_im/data_store/processed_messages.cljs create mode 100644 src/status_im/data_store/realm/processed_messages.cljs create mode 100644 src/status_im/data_store/realm/schemas/account/v1/processed_message.cljs create mode 100644 src/status_im/protocol/message_cache.cljs diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index 1e14a9716e..d668d863f2 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -1,5 +1,6 @@ (ns status-im.accounts.handlers (: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]] [taoensso.timbre :as log] [status-im.protocol.core :as protocol] @@ -18,6 +19,7 @@ [status-im.utils.gfycat.core :refer [generate-gfy]] [status-im.constants :refer [console-chat-id]] [status-im.utils.scheduler :as s] + [status-im.protocol.message-cache :as cache] [status-im.navigation.handlers :as nav])) @@ -149,6 +151,15 @@ (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 [{:keys [current-account-id] :as db} [_ _ {:keys [contact qr-source amount?]}]] (assoc db :qr-modal {:contact (or contact diff --git a/src/status_im/accounts/login/screen.cljs b/src/status_im/accounts/login/screen.cljs index de4182ed49..34fe5c178a 100644 --- a/src/status_im/accounts/login/screen.cljs +++ b/src/status_im/accounts/login/screen.cljs @@ -9,6 +9,7 @@ get-dimensions]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :refer [toolbar-title-container toolbar-title-text]] [status-im.components.text-field.view :refer [text-field]] @@ -66,9 +67,7 @@ :style st/gradient-background}] [status-bar {:type :transparent}] [toolbar {:background-color :transparent - :nav-action {:image {:source {:uri :icon_back_white} - :style icon-back} - :handler #(dispatch [:navigate-back])} + :nav-action (act/back-white #(dispatch [:navigate-back])) :custom-content [toolbar-title] :actions [{:image {:style icon-search} :handler #()}]}] diff --git a/src/status_im/accounts/recover/screen.cljs b/src/status_im/accounts/recover/screen.cljs index da17d95995..47986bd191 100644 --- a/src/status_im/accounts/recover/screen.cljs +++ b/src/status_im/accounts/recover/screen.cljs @@ -9,13 +9,12 @@ [status-im.components.status-bar :refer [status-bar]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :refer [toolbar-gradient toolbar-title-container toolbar-title-text]] [status-im.components.styles :refer [color-purple color-white - icon-back - icon-search button-input]] [status-im.components.react :refer [linear-gradient]] [status-im.i18n :refer [label]] @@ -78,12 +77,8 @@ [view st/screen-container [status-bar {:type :transparent}] [toolbar {:background-color :transparent - :nav-action {:image {:source {:uri :icon_back} - :style icon-back} - :handler #(dispatch [:navigate-back])} - :custom-content [toolbar-title] - :actions [{:image {:style icon-search} - :handler #()}]}] + :nav-action (act/back #(dispatch [:navigate-back])) + :custom-content [toolbar-title]}] [linear-gradient {:locations [0 0.6 1] :colors gradient-colors :style toolbar-gradient}] diff --git a/src/status_im/accounts/screen.cljs b/src/status_im/accounts/screen.cljs index cf56699740..5600b9c58e 100644 --- a/src/status_im/accounts/screen.cljs +++ b/src/status_im/accounts/screen.cljs @@ -11,6 +11,7 @@ touchable-highlight]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.actions :as act] [status-im.components.styles :refer [color-purple color-white icon-search @@ -61,9 +62,9 @@ :style st/gradient-background} [status-bar {:type :transparent}] [toolbar {:background-color :transparent - :nav-action {:image {:source (if show-back? {:uri :icon_back_white} nil) - :style icon-back} - :handler (if show-back? #(dispatch [:navigate-back]) nil)} + :nav-action (if show-back? + (act/back-white #(dispatch [:navigate-back])) + act/nothing) :custom-content [toolbar-title] :actions [{:image {:style icon-search} :handler #()}]}]] diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index ccc6489a55..385fe4026f 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -12,6 +12,7 @@ modal splash-screen]] [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.new-contact :refer [new-contact]] [status-im.qr-scanner.screen :refer [qr-scanner]] @@ -95,6 +96,7 @@ :new-group new-group :group-settings group-settings :contact-list main-tabs + :contact-list-search-results contacts-search-results :group-contacts contact-list :new-contact new-contact :qr-scanner qr-scanner diff --git a/src/status_im/chats_list/screen.cljs b/src/status_im/chats_list/screen.cljs index c7a8a5b95e..073a8109d2 100644 --- a/src/status_im/chats_list/screen.cljs +++ b/src/status_im/chats_list/screen.cljs @@ -8,43 +8,36 @@ text image 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 action-button-item]] [status-im.components.drawer.view :refer [open-drawer]] [status-im.components.styles :refer [color-blue]] [status-im.components.status-bar :refer [status-bar]] - [status-im.components.toolbar.view :refer [toolbar]] - [status-im.components.toolbar.styles :refer [toolbar-background1 - toolbar-background2]] + [status-im.components.toolbar.view :refer [toolbar-with-search]] + [status-im.components.toolbar.actions :as act] [status-im.components.icons.custom-icons :refer [ion-icon]] [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.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]])) -(defview chats-list-toolbar [] +(defview toolbar-view [] [chats-scrolled? [:get :chats-scrolled?]] (let [new-chat? (get-in platform-specific [:chats :new-chat-in-toolbar?]) - actions (cond->> [{:image {:source {:uri :icon_search} - :style st/toolbar-icon} - :handler (fn [])}] - new-chat? - (into [{:image {:source {:uri :icon_add} - :style st/toolbar-icon} - :handler #(dispatch [:navigate-to :group-contacts :people])}]))] - [toolbar {:nav-action {:image {:source {:uri :icon_hamburger} - :style st/hamburger-icon} - :handler open-drawer} - :title (label :t/chats) - :style (get-in platform-specific [:component-styles :toolbar]) - :background-color (if chats-scrolled? - toolbar-background1 - toolbar-background2) - :actions actions}])) + actions (if new-chat? + [(act/add #(dispatch [:navigate-to :group-contacts :people]))])] + [toolbar-with-search + {:show-search? false + :search-key :chat-list + :title (label :t/chats) + :search-placeholder (label :t/search-for) + :nav-action (act/hamburger open-drawer) + :actions actions + :style (st/toolbar chats-scrolled?)}])) (defn chats-action-button [] [view {:style (st/action-buttons-container false 0) @@ -75,7 +68,7 @@ (defview chats-list [] [chats [:get :chats]] [view st/chats-container - [chats-list-toolbar] + [toolbar-view] [list-view {:dataSource (to-datasource chats) :renderRow (fn [[id :as row] _ _] (list-item ^{:key id} [chat-list-item row])) diff --git a/src/status_im/chats_list/styles.cljs b/src/status_im/chats_list/styles.cljs index a08b375192..b89ab110e5 100644 --- a/src/status_im/chats_list/styles.cljs +++ b/src/status_im/chats_list/styles.cljs @@ -7,8 +7,16 @@ text2-color new-messages-count-color]] [status-im.components.tabs.styles :refer [tabs-height]] + [status-im.components.toolbar.styles :refer [toolbar-background1 + toolbar-background2]] [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 ["rgba(24, 52, 76, 0.165)" "rgba(24, 52, 76, 0.03)" @@ -103,14 +111,6 @@ :color color-blue :textAlign :center}) -(def hamburger-icon - {:width 16 - :height 12}) - -(def toolbar-icon - {:width 17 - :height 17}) - (def chats-container {:flex 1}) diff --git a/src/status_im/components/main_tabs.cljs b/src/status_im/components/main_tabs.cljs index 1c6f4cf929..e075308ada 100644 --- a/src/status_im/components/main_tabs.cljs +++ b/src/status_im/components/main_tabs.cljs @@ -107,8 +107,8 @@ :onScrollBeginDrag #(reset! dragging? true) :on-momentum-scroll-end (on-scroll-end swiped? dragging?)}) [chats-list] - [discover (= @view-id :discover)] - [contact-list]] + [discover (= @view-id :discover)] + [contact-list (= @view-id :contact-list)]] [tabs {:selected-view-id @view-id :prev-view-id @prev-view-id :tab-list tab-list}] diff --git a/src/status_im/components/styles.cljs b/src/status_im/components/styles.cljs index a996c5fc0c..05dea54728 100644 --- a/src/status_im/components/styles.cljs +++ b/src/status_im/components/styles.cljs @@ -31,10 +31,6 @@ (def flex {:flex 1}) -(def hamburger-icon - {:width 16 - :height 12}) - (def icon-search {:width 17 :height 17}) diff --git a/src/status_im/components/toolbar/actions.cljs b/src/status_im/components/toolbar/actions.cljs new file mode 100644 index 0000000000..d38c3bcf39 --- /dev/null +++ b/src/status_im/components/toolbar/actions.cljs @@ -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}) diff --git a/src/status_im/components/toolbar/styles.cljs b/src/status_im/components/toolbar/styles.cljs index 0ced83aad6..0e4a57acc1 100644 --- a/src/status_im/components/toolbar/styles.cljs +++ b/src/status_im/components/toolbar/styles.cljs @@ -41,7 +41,7 @@ :justifyContent :center}) (def toolbar-title-text - {:margin-top -2.5 + {:margin-top 0 :color text1-color :font-size 16}) @@ -57,4 +57,46 @@ :height toolbar-height :margin-right toolbar-icon-spacing :align-items :center - :justify-content :center}) \ No newline at end of file + :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}) diff --git a/src/status_im/components/toolbar/view.cljs b/src/status_im/components/toolbar/view.cljs index d02b6f85c4..3e16b1c35a 100644 --- a/src/status_im/components/toolbar/view.cljs +++ b/src/status_im/components/toolbar/view.cljs @@ -3,10 +3,13 @@ [status-im.components.react :refer [view icon text + text-input image touchable-highlight]] [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.utils.platform :refer [platform-specific]])) @@ -48,3 +51,43 @@ custom-action)]] [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}])) diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index 657c095ad9..fbc77c8bb7 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -11,6 +11,7 @@ [status-im.utils.utils :refer [require]] [status-im.navigation.handlers :as nav] [status-im.utils.random :as random] + [status-im.i18n :refer [label]] [taoensso.timbre :as log] [cljs.reader :refer [read-string]])) @@ -31,9 +32,10 @@ (defmethod nav/preload-data! :contact-list [db [_ _ click-handler]] - (assoc db :contacts-click-handler click-handler - :contacts-filter nil)) - + (-> db + (assoc-in [:toolbar-search :show] nil) + (assoc :contacts-click-handler click-handler + :contacts-filter nil))) (register-handler :remove-contacts-click-handler (fn [db] @@ -56,6 +58,13 @@ (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 [{:keys [current-public-key web3 current-account-id accounts]} [_ contact]] (let [{:keys [whisper-identity]} contact @@ -199,11 +208,13 @@ (register-handler :add-pending-contact (u/side-effect! - (fn [{:keys [chats]} [_ chat-id]] - (let [contact (read-string (get-in chats [chat-id :contact-info]))] + (fn [{:keys [chats contacts]} [_ chat-id]] + (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 [:update-chat! {:chat-id chat-id - :contact-info nil :pending-contact? false}]) (dispatch [:watch-contact contact]) (dispatch [:discoveries-send-portions chat-id]))))) @@ -242,3 +253,22 @@ (dispatch [:update-contact! {:whisper-identity from :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)})))) + diff --git a/src/status_im/contacts/screen.cljs b/src/status_im/contacts/screen.cljs index eb9ff23803..5187116b74 100644 --- a/src/status_im/contacts/screen.cljs +++ b/src/status_im/contacts/screen.cljs @@ -1,7 +1,8 @@ (ns status-im.contacts.screen (:require-macros [status-im.utils.views :refer [defview]]) - (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] - [reagent.core :as r] + (:require [reagent.core :as r] + [clojure.string :as str] + [re-frame.core :refer [subscribe dispatch dispatch-sync]] [status-im.components.react :refer [view text image @@ -12,38 +13,40 @@ list-item] :as react] [status-im.components.action-button :refer [action-button 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.toolbar.view :refer [toolbar]] - [status-im.components.toolbar.styles :refer [toolbar-background2]] + [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.icons.custom-icons :refer [ion-icon]] - [status-im.components.styles :refer [color-blue - hamburger-icon - icon-search - create-icon]] - [status-im.contacts.styles :as st] + [status-im.contacts.views.contact :refer [contact-view]] + [status-im.utils.platform :refer [platform-specific]] [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) -(defn toolbar-view [] +(defn toolbar-view [show-search?] (let [new-contact? (get-in platform-specific [:contacts :new-contact-in-toolbar?]) - actions (cond->> [{:image {:source {:uri :icon_search} - :style icon-search} - :handler (fn [])}] - new-contact? - (into [{:image {:source {:uri :icon_add} - :style icon-search} - :handler #(dispatch [:navigate-to :new-contact])}]))] - [toolbar {:nav-action {:image {:source {:uri :icon_hamburger} - :style hamburger-icon} - :handler open-drawer} - :title (label :t/contacts) - :background-color toolbar-background2 - :style {:elevation 0} - :actions actions}])) + actions (if new-contact? + [(act/add #(dispatch [:navigate-to :new-contact]))])] + (toolbar-with-search + {:show-search? show-search? + :search-key :contact-list + :title (label :t/contacts) + :search-placeholder (label :t/search-for) + :nav-action (act/hamburger open-drawer) + :actions actions + :on-search-submit (fn [text] + (when-not (str/blank? text) + (dispatch [:set :contacts-filter #(let [name (-> (or (:name %) "") + (str/lower-case)) + 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] [view st/contact-group-header-inner @@ -81,9 +84,11 @@ [view (doall (map (fn [contact] - (let [click-handler (or click-handler on-press)] - ^{:key contact} - [contact-extended-view contact nil (click-handler contact) nil])) + ^{:key contact} + [contact-view {:contact contact + :extended? true + :on-click click-handler + :more-on-click nil}]) contacts))] (when (<= contacts-limit (count contacts)) [view st/show-all @@ -110,16 +115,18 @@ [ion-icon {:name :md-create :style create-icon}]]]]) -(defn contact-list [] +(defn contact-list [_] (let [peoples (subscribe [:get-added-people-with-limit contacts-limit]) dapps (subscribe [:get-added-dapps-with-limit contacts-limit]) people-count (subscribe [:added-people-count]) dapps-count (subscribe [:added-dapps-count]) click-handler (subscribe [:get :contacts-click-handler]) + show-search (subscribe [:get-in [:toolbar-search :show]]) show-toolbar-shadow? (r/atom false)] - (fn [] + (fn [current-view?] [view st/contacts-list-container - [toolbar-view] + [toolbar-view (and current-view? + (= @show-search :contact-list))] [view {:style st/toolbar-shadow} (when @show-toolbar-shadow? [linear-gradient {:style st/contact-group-header-gradient-bottom @@ -128,7 +135,8 @@ [scroll-view {:style st/contact-groups :onScroll (fn [e] (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) [contact-group-view @dapps diff --git a/src/status_im/contacts/search_results.cljs b/src/status_im/contacts/search_results.cljs new file mode 100644 index 0000000000..55e47fb96d --- /dev/null +++ b/src/status_im/contacts/search_results.cljs @@ -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}]))}])]) diff --git a/src/status_im/contacts/styles.cljs b/src/status_im/contacts/styles.cljs index c6a110d0bf..100b7da558 100644 --- a/src/status_im/contacts/styles.cljs +++ b/src/status_im/contacts/styles.cljs @@ -10,17 +10,19 @@ color-gray2]] [status-im.components.toolbar.styles :refer [toolbar-background2]])) -(def contacts-list-container - {:flex 1}) +;; Contacts list (def toolbar-shadow - {:height 2 - :backgroundColor toolbar-background2}) + {:height 2 + :background-color toolbar-background2}) (def contact-groups {:flex 1 :background-color toolbar-background2}) +(def contacts-list-container + {:flex 1}) + (def empty-contact-groups (merge contact-groups {:align-items :center @@ -170,7 +172,7 @@ {:width 4 :height 16}) -; new contact +; New contact (def contact-form-container {:flex 1 @@ -221,4 +223,18 @@ :margin-right 20 :margin-top 18 :width 20 - :height 20}) \ No newline at end of file + :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}) + + diff --git a/src/status_im/contacts/subs.cljs b/src/status_im/contacts/subs.cljs index 1352723d06..0bc89845cf 100644 --- a/src/status_im/contacts/subs.cljs +++ b/src/status_im/contacts/subs.cljs @@ -1,6 +1,7 @@ (ns status-im.contacts.subs (:require-macros [reagent.ratom :refer [reaction]]) (:require [re-frame.core :refer [register-sub subscribe]] + [clojure.string :as str] [status-im.utils.identicon :refer [identicon]] [taoensso.timbre :as log])) @@ -34,7 +35,6 @@ (let [contacts (subscribe [:all-added-contacts])] (reaction (filter :dapp? @contacts))))) - (register-sub :get-added-people-with-limit (fn [_ [_ limit]] (let [contacts (subscribe [:all-added-people])] diff --git a/src/status_im/contacts/validations.cljs b/src/status_im/contacts/validations.cljs index c97e132f1e..ce256e057d 100644 --- a/src/status_im/contacts/validations.cljs +++ b/src/status_im/contacts/validations.cljs @@ -7,8 +7,11 @@ (defn is-address? [s] (.isAddress web3.prototype s)) -(defn unique-identity? [identity] - (not (contacts/exists? identity))) +(defn contact-can-be-added? [identity] + (if (contacts/exists? identity) + (-> (contacts/get-by-id identity) + (get :pending)) + true)) (defn valid-length? [identity] (let [length (count identity)] @@ -18,11 +21,11 @@ (is-address? identity)))) (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 ::name ::not-empty-string) (s/def ::whisper-identity (s/and ::not-empty-string - ::unique-identity + ::contact-can-be-added ::identity-length)) (s/def ::contact (s/keys :req-un [::name ::whisper-identity] diff --git a/src/status_im/contacts/views/contact.cljs b/src/status_im/contacts/views/contact.cljs index 2c1fb16980..3a62bbb50c 100644 --- a/src/status_im/contacts/views/contact.cljs +++ b/src/status_im/contacts/views/contact.cljs @@ -3,37 +3,31 @@ (:require [status-im.components.react :refer [view text icon touchable-highlight]] [re-frame.core :refer [dispatch]] [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]}] - #(dispatch [:start-chat whisper-identity {} :navigation-replace])) +(defn- on-press [{:keys [whisper-identity]}] + (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] [view st/letter-container (when letter [text {:style st/letter-text} letter])]) -(defview contact-view-with-letter [{:keys [whisper-identity letter] :as contact} click-handler action params] - [touchable-highlight - {: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}] +(defview contact-view [{{:keys [whisper-identity letter dapp?] :as contact} :contact + :keys [extended? letter? on-click more-on-click info]}] [chat [:get-chat whisper-identity]] [touchable-highlight - {:onPress (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} + {:on-press #((or on-click on-press) contact)} [view st/contact-container + (when letter? + [letter-view letter]) [contact-inner-view contact info] - [touchable-highlight - {:on-press more-click-handler} - [view st/more-btn - [icon :more_vertical st/more-btn-icon]]]]]) + (when (and extended? (not dapp?)) + [touchable-highlight + {:on-press #((or more-on-click more-on-press) contact)} + [view st/more-btn + [icon :more_vertical st/more-btn-icon]]])]]) diff --git a/src/status_im/contacts/views/contact_list.cljs b/src/status_im/contacts/views/contact_list.cljs index 5442f836b9..d7477a8fe5 100644 --- a/src/status_im/contacts/views/contact_list.cljs +++ b/src/status_im/contacts/views/contact_list.cljs @@ -6,12 +6,11 @@ touchable-highlight list-view list-item]] - [status-im.contacts.views.contact :refer [contact-view - on-press - contact-view-with-letter]] + [status-im.contacts.views.contact :refer [contact-view]] [status-im.components.text-field.view :refer [text-field]] [status-im.components.status-bar :refer [status-bar]] [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.drawer.view :refer [drawer-view open-drawer]] [status-im.components.styles :refer [icon-search @@ -42,11 +41,10 @@ (defn render-row [chat-modal click-handler action params] (fn [row _ _] (list-item - (if chat-modal - [contact-view-with-letter row click-handler action params] - [contact-view row - (or click-handler - (on-press row))])))) + [contact-view {:contact row + :letter? chat-modal + :on-click (if click-handler + #(click-handler row action params))}]))) (defn contact-list-entry [{:keys [click-handler icon icon-style label]}] [touchable-highlight @@ -71,14 +69,10 @@ :t/contacts-group-dapps :t/contacts-group-new-chat))) :nav-action (when modal - {:handler #(dispatch [:navigate-back]) - :image {:source {:uri :icon_back} - :style icon-back}}) + (act/back #(dispatch [:navigate-back]))) :background-color toolbar-background1 :style (get-in platform-specific [:component-styles :toolbar]) - :actions [{:image {:source {:uri :icon_search} - :style icon-search} - :handler (fn [])}]}]]) + :actions [(act/search #())]}]]) (defview contact-list [] [contacts [:contacts-with-letters] diff --git a/src/status_im/contacts/views/new_contact.cljs b/src/status_im/contacts/views/new_contact.cljs index c05d06591b..170d5b1b28 100644 --- a/src/status_im/contacts/views/new_contact.cljs +++ b/src/status_im/contacts/views/new_contact.cljs @@ -11,6 +11,7 @@ [status-im.utils.identicon :refer [identicon]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :refer [toolbar-title-container toolbar-title-text toolbar-background1]] @@ -24,6 +25,7 @@ [cljs.spec :as s] [status-im.contacts.validations :as v] [status-im.contacts.styles :as st] + [status-im.data-store.contacts :as contacts] [status-im.utils.gfycat.core :refer [generate-gfy]] [status-im.utils.hex :refer [normalize-hex]] [status-im.utils.platform :refer [platform-specific]])) @@ -44,11 +46,15 @@ :address id :photo-path (identicon 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 [:add-new-contact {:name (generate-gfy) - :photo-path (identicon id) - :whisper-identity id}]))) + (if (contacts/exists? id) + (dispatch [:add-pending-contact id]) + (dispatch [:add-new-contact {:name (generate-gfy) + :photo-path (identicon id) + :whisper-identity id}])))) (defn- validation-error-message [whisper-identity {:keys [address public-key]} error] @@ -57,7 +63,7 @@ (normalize-hex whisper-identity)) (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) (not (s/valid? ::v/whisper-identity whisper-identity)) @@ -103,9 +109,7 @@ [status-bar] [toolbar {:background-color toolbar-background1 :style (get-in platform-specific [:component-styles :toolbar]) - :nav-action {:image {:source {:uri :icon_back} - :style icon-back} - :handler #(dispatch [:navigate-back])} + :nav-action (act/back #(dispatch [:navigate-back])) :title (label :t/add-new-contact) :actions (toolbar-actions new-contact-identity account error)}] [view st/form-container diff --git a/src/status_im/data_store/contacts.cljs b/src/status_im/data_store/contacts.cljs index 0a8a62b056..1fc3d271d0 100644 --- a/src/status_im/data_store/contacts.cljs +++ b/src/status_im/data_store/contacts.cljs @@ -9,26 +9,25 @@ (defn get-by-id [whisper-identity] - (data-store/get-by-id whisper-identity)) + (data-store/get-by-id-cljs whisper-identity)) (defn save [{:keys [whisper-identity pending] :as contact}] (let [{pending-db :pending :as contact-db} (data-store/get-by-id whisper-identity) - contact (assoc contact :pending (boolean (if contact-db - ;; 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)))] + contact (assoc contact :pending + (boolean (if contact-db + (if (nil? pending) pending-db pending) + pending)))] (data-store/save contact (if contact-db true false)))) (defn save-all [contacts] (mapv save contacts)) +(defn delete [contact] + (data-store/delete contact)) + (defn exists? [whisper-identity] - (data-store/exists? whisper-identity)) \ No newline at end of file + (data-store/exists? whisper-identity)) diff --git a/src/status_im/data_store/processed_messages.cljs b/src/status_im/data_store/processed_messages.cljs new file mode 100644 index 0000000000..d934614417 --- /dev/null +++ b/src/status_im/data_store/processed_messages.cljs @@ -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)) diff --git a/src/status_im/data_store/realm/contacts.cljs b/src/status_im/data_store/realm/contacts.cljs index dddb3acf09..7efe73eee4 100644 --- a/src/status_im/data_store/realm/contacts.cljs +++ b/src/status_im/data_store/realm/contacts.cljs @@ -14,12 +14,21 @@ (defn get-by-id [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 [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? [whisper-identity] - (realm/exists? @realm/account-realm :contact {:whisper-identity whisper-identity})) \ No newline at end of file + (realm/exists? @realm/account-realm :contact {:whisper-identity whisper-identity})) diff --git a/src/status_im/data_store/realm/processed_messages.cljs b/src/status_im/data_store/realm/processed_messages.cljs new file mode 100644 index 0000000000..917f807d29 --- /dev/null +++ b/src/status_im/data_store/realm/processed_messages.cljs @@ -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))) diff --git a/src/status_im/data_store/realm/schemas/account/v1/core.cljs b/src/status_im/data_store/realm/schemas/account/v1/core.cljs index 1ae00e10fc..6e4732349c 100644 --- a/src/status_im/data_store/realm/schemas/account/v1/core.cljs +++ b/src/status_im/data_store/realm/schemas/account/v1/core.cljs @@ -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.message :as 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.tag :as tag] [status-im.data-store.realm.schemas.account.v1.user-status :as user-status] @@ -20,6 +21,7 @@ kv-store/schema message/schema pending-message/schema + processed-message/schema request/schema tag/schema user-status/schema]) @@ -34,6 +36,7 @@ (kv-store/migration old-realm new-realm) (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) (tag/migration old-realm new-realm) - (user-status/migration old-realm new-realm)) \ No newline at end of file + (user-status/migration old-realm new-realm)) diff --git a/src/status_im/data_store/realm/schemas/account/v1/processed_message.cljs b/src/status_im/data_store/realm/schemas/account/v1/processed_message.cljs new file mode 100644 index 0000000000..a6ce431abf --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v1/processed_message.cljs @@ -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")) diff --git a/src/status_im/discover/handlers.cljs b/src/status_im/discover/handlers.cljs index 0b464fed2e..fc483e140f 100644 --- a/src/status_im/discover/handlers.cljs +++ b/src/status_im/discover/handlers.cljs @@ -25,8 +25,8 @@ (defmethod nav/preload-data! :discover [db _] - (dispatch [:set :discover-show-search? false]) (-> db + (assoc-in [:toolbar-search :show] nil) (assoc :tags (discoveries/get-all-tags)) (assoc :discoveries (->> (discoveries/get-all :desc) (map (fn [{:keys [message-id] :as discover}] diff --git a/src/status_im/discover/screen.cljs b/src/status_im/discover/screen.cljs index f9a4b3b6f3..f73f93b9cf 100644 --- a/src/status_im/discover/screen.cljs +++ b/src/status_im/discover/screen.cljs @@ -1,6 +1,7 @@ (ns status-im.discover.screen (:require-macros [status-im.utils.views :refer [defview]]) (:require + [reagent.core :as r] [re-frame.core :refer [dispatch subscribe]] [clojure.string :as str] [status-im.components.react :refer [view @@ -8,52 +9,33 @@ text text-input 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.discover.styles :as st] - [status-im.i18n :refer [label]] [status-im.components.carousel.carousel :refer [carousel]] [status-im.discover.views.popular-list :refer [discover-popular-list]] [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]] - [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] (let [hashtags (map #(str/lower-case (str/replace % #"#" "")) (re-seq #"[^ !?,;:.]+" status))] (or hashtags []))) -(defn title-content [show-search?] - [view st/discover-toolbar-content - (if show-search? - [text-input {:style st/discover-search-input - :auto-focus true - :placeholder (label :t/search-tags) - :on-blur (fn [e] - (dispatch [:set :discover-show-search? false])) - :on-submit-editing (fn [e] - (let [search (aget e "nativeEvent" "text") - hashtags (get-hashtags search)] - (dispatch [:set :discover-search-tags hashtags]) - (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 toolbar-view [show-search?] + [toolbar-with-search + {:show-search? show-search? + :search-key :discover + :title (label :t/discover) + :search-placeholder (label :t/search-tags) + :nav-action (act/hamburger open-drawer) + :on-search-submit (fn [text] + (when-not (str/blank? text) + (let [hashtags (get-hashtags text)] + (dispatch [:set :discover-search-tags hashtags]) + (dispatch [:navigate-to :discover-search-results]))))}]) (defn title [label-kw spacing?] [view st/section-spacing @@ -91,19 +73,20 @@ :current-account current-account}]))]])) (defview discover [current-view?] - [show-search? [:get :discover-show-search?] + [show-search [:get-in [:toolbar-search :show]] contacts [:get :contacts] current-account [:get-current-account] discoveries [:get-recent-discoveries]] [view st/discover-container - [discover-toolbar (and current-view? show-search?)] + [toolbar-view (and current-view? + (= show-search :discover))] (if discoveries [scroll-view st/scroll-view-container [discover-popular {:contacts contacts :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 - [icon :group_big contacts-styles/empty-contacts-icon] - [text {:style contacts-styles/empty-contacts-text} + [icon :group_big contacts-st/empty-contacts-icon] + [text {:style contacts-st/empty-contacts-text} (label :t/no-statuses-discovered)]])]) diff --git a/src/status_im/discover/search_results.cljs b/src/status_im/discover/search_results.cljs index 06b2394040..5275eeeff6 100644 --- a/src/status_im/discover/search_results.cljs +++ b/src/status_im/discover/search_results.cljs @@ -9,12 +9,13 @@ list-view list-item scroll-view]] - [status-im.i18n :refer [label]] [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.styles :as st] [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])) (defn render-separator [_ row-id _] @@ -43,20 +44,19 @@ datasource (to-datasource discoveries)] [view st/discover-tag-container [status-bar] - [toolbar {:nav-action {:image {:source {:uri :icon_back} - :style st/icon-back} - :handler #(dispatch [:navigate-back])} + [toolbar {:nav-action (act/back #(dispatch [:navigate-back])) :custom-content (title-content tags) :style st/discover-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} + [icon :group_big contacts-st/empty-contacts-icon] + [text {:style contacts-st/empty-contacts-text} (label :t/no-statuses-found)]] [list-view {:dataSource datasource :renderRow (fn [row _ _] - (list-item [discover-list-item {:message row - :current-account current-account}])) + (list-item [discover-list-item + {:message row + :current-account current-account}])) :renderSeparator render-separator :style st/recent-list}])])) diff --git a/src/status_im/discover/styles.cljs b/src/status_im/discover/styles.cljs index 45066fc9b5..e09db0c1d1 100644 --- a/src/status_im/discover/styles.cljs +++ b/src/status_im/discover/styles.cljs @@ -1,9 +1,10 @@ (ns status-im.discover.styles (:require [status-im.components.styles :refer [color-gray2 - color-white]] + color-white + color-light-gray]] [status-im.components.toolbar.styles :refer [toolbar-background2]])) -;; common +;; Common (def row-separator {:border-bottom-width 1 @@ -22,30 +23,6 @@ :align-items :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 {:padding 16}) @@ -134,7 +111,7 @@ (def discover-tag-container {:flex 1 - :backgroundColor "#eef2f5"}) + :backgroundColor color-light-gray}) (def tag-title-scroll {:flex 1 @@ -165,10 +142,6 @@ {:flex 1 :backgroundColor color-white}) -(def hamburger-icon - {:width 16 - :height 12}) - (def search-icon {:width 17 :height 17}) diff --git a/src/status_im/group_settings/views/member.cljs b/src/status_im/group_settings/views/member.cljs index e73d46cc2a..e2edc020d7 100644 --- a/src/status_im/group_settings/views/member.cljs +++ b/src/status_im/group_settings/views/member.cljs @@ -1,9 +1,12 @@ (ns status-im.group-settings.views.member (: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]])) (defn member-view [{:keys [whisper-identity role] :as contact}] ;; TODO implement :role property for group chat contact - [contact-extended-view contact role - #(dispatch [:set :selected-participants #{whisper-identity}])]) + [contact-view + {:contact contact + :extended? true + :info role + :on-click #(dispatch [:set :selected-participants #{whisper-identity}])}]) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index 4e63173000..3d05f1a7fb 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -68,6 +68,7 @@ (u/side-effect! (fn [_ [_ address]] (dispatch [:initialize-account-db]) + (dispatch [:load-processed-messages]) (dispatch [:initialize-protocol address]) (dispatch [:initialize-sync-listener]) (dispatch [:initialize-chats]) diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index d604f6556b..3d5ed73da5 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -10,6 +10,7 @@ orientation splash-screen]] [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.new-contact :refer [new-contact]] [status-im.qr-scanner.screen :refer [qr-scanner]] @@ -82,6 +83,7 @@ :new-group new-group :group-settings group-settings :contact-list main-tabs + :contact-list-search-results contacts-search-results :group-contacts contact-list :new-contact new-contact :qr-scanner qr-scanner diff --git a/src/status_im/profile/photo_capture/screen.cljs b/src/status_im/profile/photo_capture/screen.cljs index 80be3a6b6c..0c74dc8592 100644 --- a/src/status_im/profile/photo_capture/screen.cljs +++ b/src/status_im/profile/photo_capture/screen.cljs @@ -12,6 +12,7 @@ [status-im.components.icons.custom-icons :refer [ion-icon]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :refer [toolbar-background1]] [status-im.utils.image-processing :refer [img->base64]] [status-im.profile.photo-capture.styles :as st] @@ -35,9 +36,7 @@ [view st/container [status-bar] [toolbar {:title (label :t/image-source-title) - :nav-action {:image {:source {:uri :icon_back} - :style icon-back} - :handler #(dispatch [:navigate-back])} + :nav-action (act/back #(dispatch [:navigate-back])) :background-color toolbar-background1}] [camera {:style {:flex 1} :aspect (:fill aspects) @@ -54,4 +53,4 @@ (.catch #(log/debug "Error capturing image: " %)))))} [view [ion-icon {:name :md-camera - :style {:font-size 36}}]]]]])) \ No newline at end of file + :style {:font-size 36}}]]]]])) diff --git a/src/status_im/protocol/core.cljs b/src/status_im/protocol/core.cljs index bd6919478d..0445ae1703 100644 --- a/src/status_im/protocol/core.cljs +++ b/src/status_im/protocol/core.cljs @@ -35,6 +35,7 @@ ;; discoveries (def watch-user! discoveries/watch-user!) +(def stop-watching-user! discoveries/stop-watching-user!) (def contact-request! discoveries/contact-request!) (def broadcast-profile! discoveries/broadcast-profile!) (def send-status! discoveries/send-status!) diff --git a/src/status_im/protocol/discoveries.cljs b/src/status_im/protocol/discoveries.cljs index 07223c5654..2432f44988 100644 --- a/src/status_im/protocol/discoveries.cljs +++ b/src/status_im/protocol/discoveries.cljs @@ -46,6 +46,13 @@ :topics [(make-discover-topic 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/payload diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 423b883b54..a1fa1a0182 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -5,12 +5,15 @@ [status-im.data-store.contacts :as contacts] [status-im.data-store.messages :as 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.protocol.core :as protocol] [status-im.constants :refer [text-content-type blocks-per-hour]] [status-im.i18n :refer [label]] [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]] [status-im.constants :as c] [status-im.components.status :as status])) @@ -77,33 +80,41 @@ (register-handler :incoming-message (u/side-effect! - (fn [_ [_ type {:keys [payload] :as message}]] - (debug :incoming-message type) - (case type - :message (dispatch [:received-protocol-message! message]) - :group-message (dispatch [:received-protocol-message! message]) - :ack (if (#{:message :group-message} (:type payload)) - (dispatch [:message-delivered message]) - (dispatch [:pending-message-remove message])) - :seen (dispatch [:message-seen message]) - :group-invitation (dispatch [:group-chat-invite-received message]) - :update-group (dispatch [:update-group-message message]) - :add-group-identity (dispatch [:participant-invited-to-group message]) - :remove-group-identity (dispatch [:participant-removed-from-group message]) - :leave-group (dispatch [:participant-left-group message]) - :contact-request (dispatch [:contact-request-received message]) - :discover (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]) - :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))))) + (fn [_ [_ type {:keys [payload ttl id] :as message}]] + (let [message-id (or id (:message-id payload))] + (when-not (cache/exists? message-id type) + (let [ttl-s (* 1000 (or ttl 120)) + processed-message {:id (random/id) + :message-id message-id + :type type + :ttl (+ (dt/now-ms) ttl-s)}] + (cache/add! processed-message) + (processed-messages/save processed-message)) + (case type + :message (dispatch [:received-protocol-message! message]) + :group-message (dispatch [:received-protocol-message! message]) + :ack (if (#{:message :group-message} (:type payload)) + (dispatch [:message-delivered message]) + (dispatch [:pending-message-remove message])) + :seen (dispatch [:message-seen message]) + :group-invitation (dispatch [:group-chat-invite-received message]) + :update-group (dispatch [:update-group-message message]) + :add-group-identity (dispatch [:participant-invited-to-group message]) + :remove-group-identity (dispatch [:participant-removed-from-group message]) + :leave-group (dispatch [:participant-left-group message]) + :contact-request (dispatch [:contact-request-received message]) + :discover (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]) + :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 ([message-id timestamp content] diff --git a/src/status_im/protocol/message_cache.cljs b/src/status_im/protocol/message_cache.cljs new file mode 100644 index 0000000000..8a1fd5d55d --- /dev/null +++ b/src/status_im/protocol/message_cache.cljs @@ -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])) diff --git a/src/status_im/protocol/web3/delivery.cljs b/src/status_im/protocol/web3/delivery.cljs index 5d9ecbde5b..862ee9d8d1 100644 --- a/src/status_im/protocol/web3/delivery.cljs +++ b/src/status_im/protocol/web3/delivery.cljs @@ -28,7 +28,8 @@ (assoc :content content') prn-str u/from-utf8)] - (-> message (select-keys [:from :to :topics :ttl]) + (-> message + (select-keys [:from :to :topics :ttl]) (assoc :payload payload')))) (s/def :shh/pending-message @@ -110,7 +111,7 @@ (let [message (get-in messages [id to]) message' (when message (assoc message :was-sent? true - :attemps 1))] + :attempts 1))] (if message' (assoc-in messages [id to] message') messages))))] diff --git a/src/status_im/qr_scanner/screen.cljs b/src/status_im/qr_scanner/screen.cljs index b0595c0e2e..2a95f8a768 100644 --- a/src/status_im/qr_scanner/screen.cljs +++ b/src/status_im/qr_scanner/screen.cljs @@ -8,6 +8,7 @@ icon-back]] [status-im.components.status-bar :refer [status-bar]] [status-im.components.toolbar.view :refer [toolbar]] + [status-im.components.toolbar.actions :as act] [status-im.components.toolbar.styles :refer [toolbar-background1]] [status-im.qr-scanner.styles :as st] [status-im.utils.types :refer [json->clj]] @@ -20,12 +21,7 @@ [toolbar {:title title :background-color toolbar-background1 :nav-action (when modal - {:handler #(dispatch [:navigate-back]) - :image {:source {:uri :icon_back} - :style icon-back}}) - :actions [{:image {:source {:uri :icon_lock_white} - :style icon-search} - :handler #()}]}]]) + (act/back #(dispatch [:navigate-back])))}]]) (defview qr-scanner [] [identifier [:get :current-qr-context]] diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index e9c7688308..035517fe6d 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -8,6 +8,8 @@ :chat-name "Chat name" :notifications-title "Notifications and sounds" :offline "Offline" + :search-for "Search for..." + :cancel "Cancel" ;drawer :invite-friends "Invite friends" @@ -108,7 +110,6 @@ :new-group-chat "New group chat" ;discover - :discover "Discover" :none "None" :search-tags "Type your search tags here" @@ -123,6 +124,7 @@ ;contacts :contacts "Contacts" :new-contact "New Contact" + :remove-contact "Remove contact" :show-all "SHOW ALL" :contacts-group-dapps "ÐApps" :contacts-group-people "People"