diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index 9868d2a53b..8ae711a7a3 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -8,7 +8,8 @@ [status-im.utils.platform :as platform] [status-im.utils.gfycat.core :as gfycat] [status-im.i18n :as i18n] - [status-im.models.transactions :as transactions])) + [status-im.models.transactions :as transactions] + [clojure.set :as clojure.set])) (reg-sub :get-chats :chats) @@ -75,11 +76,19 @@ platform/ios? kb-height :default 0))) -(defn active-chats [chats] - (into {} (filter (comp :is-active second) chats))) +(defn active-chats [[contacts chats]] + (reduce (fn [acc [chat-id {:keys [is-active] :as chat}]] + (if is-active + (assoc acc chat-id (if-let [contact (get contacts chat-id)] + (update chat :tags clojure.set/union (:tags contact)) + chat)) + acc)) + {} + chats)) (reg-sub :get-active-chats + :<- [:get-contacts] :<- [:get-chats] active-chats) diff --git a/src/status_im/contact/core.cljs b/src/status_im/contact/core.cljs index 93e57fc1d6..0c08850651 100644 --- a/src/status_im/contact/core.cljs +++ b/src/status_im/contact/core.cljs @@ -67,14 +67,16 @@ (add-new-contact contact) (send-contact-request contact)))) -(fx/defn add-contact-tag +(fx/defn add-tag "add a tag to the contact" - [{:keys [db] :as cofx} whisper-id tag] - (let [tags (conj (get-in db [:contacts/contacts whisper-id :tags] #{}) tag)] + [{:keys [db] :as cofx}] + (let [tag (get-in db [:ui/contact :contact/new-tag]) + whisper-id (get-in db [:current-chat-id]) + tags (conj (get-in db [:contacts/contacts whisper-id :tags] #{}) tag)] {:db (assoc-in db [:contacts/contacts whisper-id :tags] tags) :data-store/tx [(contacts-store/add-contact-tag-tx whisper-id tag)]})) -(fx/defn remove-contact-tag +(fx/defn remove-tag "remove a tag from the contact" [{:keys [db] :as cofx} whisper-id tag] (let [tags (disj (get-in db [:contacts/contacts whisper-id :tags] #{}) tag)] diff --git a/src/status_im/contact/db.cljs b/src/status_im/contact/db.cljs index 001948fc42..d93f27aabe 100644 --- a/src/status_im/contact/db.cljs +++ b/src/status_im/contact/db.cljs @@ -36,32 +36,30 @@ (spec/def :contact/debug? boolean?) (spec/def :contact/tags (spec/coll-of string? :kind set?)) -(spec/def :contact/contact - (allowed-keys - :req-un [:contact/name] - :opt-un [:contact/whisper-identity - :contact/address - :contact/public-key - :contact/photo-path - :contact/status - :contact/last-updated - :contact/last-online - :contact/pending? - :contact/hide-contact? - :contact/unremovable? - :contact/dapp? - :contact/dapp-url - :contact/dapp-hash - :contact/bot-url - :contact/jail-loaded? - :contact/jail-loaded-events - :contact/command - :contact/response - :contact/debug? - :contact/subscriptions - :contact/fcm-token - :contact/description - :contact/tags])) +(spec/def :contact/contact (spec/keys :req-un [:contact/name] + :opt-un [:contact/whisper-identity + :contact/address + :contact/public-key + :contact/photo-path + :contact/status + :contact/last-updated + :contact/last-online + :contact/pending? + :contact/hide-contact? + :contact/unremovable? + :contact/dapp? + :contact/dapp-url + :contact/dapp-hash + :contact/bot-url + :contact/jail-loaded? + :contact/jail-loaded-events + :contact/command + :contact/response + :contact/debug? + :contact/subscriptions + :contact/fcm-token + :contact/description + :contact/tags])) ;;Contact list ui props (spec/def :contact-list-ui/edit? boolean?) @@ -83,3 +81,6 @@ (spec/def :contacts/click-action (spec/nilable #{:send :request})) ;;used in modal list (for example for wallet) (spec/def :contacts/click-params (spec/nilable map?)) + +(spec/def :contact/new-tag string?) +(spec/def :ui/contact (spec/keys :opt [:contact/new-tag])) diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index a1556fbd77..ead36c283c 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -30,6 +30,7 @@ [status-im.privacy-policy.core :as privacy-policy] [status-im.protocol.core :as protocol] [status-im.qr-scanner.core :as qr-scanner] + [status-im.search.core :as search] [status-im.signals.core :as signals] [status-im.transport.inbox :as inbox] [status-im.transport.message.core :as transport.message] @@ -1073,3 +1074,20 @@ [(re-frame/inject-cofx :random-id-generator)] (fn [cofx _] (contact/add-new-identity-to-contacts cofx))) + +(handlers/register-handler-fx + :contact.ui/add-tag + (fn [cofx _] + (contact/add-tag cofx))) + +(handlers/register-handler-fx + :contact.ui/set-tag-input-field + (fn [cofx [_ text]] + {:db (assoc-in (:db cofx) [:ui/contact :contact/new-tag] text)})) + +;; search module + +(handlers/register-handler-fx + :search/filter-changed + (fn [cofx [_ search-filter]] + (search/filter-changed cofx search-filter))) diff --git a/src/status_im/search/core.cljs b/src/status_im/search/core.cljs new file mode 100644 index 0000000000..a10e88873e --- /dev/null +++ b/src/status_im/search/core.cljs @@ -0,0 +1,5 @@ +(ns status-im.search.core + (:require [status-im.utils.fx :as fx])) + +(fx/defn filter-changed [cofx search-filter] + {:db (assoc-in (:db cofx) [:ui/search :filter] search-filter)}) diff --git a/src/status_im/search/subs.cljs b/src/status_im/search/subs.cljs new file mode 100644 index 0000000000..4fd0f07ec8 --- /dev/null +++ b/src/status_im/search/subs.cljs @@ -0,0 +1,28 @@ +(ns status-im.search.subs + (:require [clojure.string :as string] + [re-frame.core :as re-frame])) + +(re-frame/reg-sub + :search/filter + (fn [db] + (get-in db [:ui/search :filter] ""))) + +(re-frame/reg-sub + :search/filtered-active-chats + :<- [:get-active-chats] + :<- [:search/filter] + (fn [[chats tag-filter]] + (if (empty? tag-filter) + chats + (keep #(when (some (fn [tag] + (string/includes? (string/lower-case tag) + (string/lower-case tag-filter))) + (into [(:name (val %))] (:tags (val %)))) + %) + chats)))) + +(re-frame/reg-sub + :search/filtered-home-items + :<- [:search/filtered-active-chats] + (fn [active-chats] + active-chats)) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index aa1274d633..f0cd0ac1ff 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -243,8 +243,10 @@ :transport.inbox/request-to :desktop/desktop :dimensions/window - :dapps/permissions] - + :dapps/permissions + :ui/contact + :ui/search + :ui/chat] :opt-un [::current-public-key ::modal diff --git a/src/status_im/ui/screens/desktop/main/tabs/home/views.cljs b/src/status_im/ui/screens/desktop/main/tabs/home/views.cljs index 7f975ed6fd..4672383f50 100644 --- a/src/status_im/ui/screens/desktop/main/tabs/home/views.cljs +++ b/src/status_im/ui/screens/desktop/main/tabs/home/views.cljs @@ -3,7 +3,7 @@ (:require [re-frame.core :as re-frame] [status-im.utils.gfycat.core :as gfycat] [status-im.i18n :as i18n] - + [status-im.ui.components.colors :as colors] [status-im.ui.screens.desktop.main.tabs.home.styles :as styles] [clojure.string :as string] [status-im.ui.screens.home.views.inner-item :as chat-item] @@ -65,17 +65,51 @@ [react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])} [chat-list-item-inner-view (assoc chat :chat-id chat-id)]]) +(defn tag-view [tag {:keys [on-press]}] + [react/touchable-highlight {:style {:border-radius 5 + :margin 2 + :padding 4 + :height 23 + :background-color (if (= tag "clear filter") + colors/red + colors/blue) + :justify-content :center + :align-items :center + :align-content :center} + :on-press on-press} + [react/text {:style {:font-size 9 + :color colors/white} + :font :medium} tag]]) + +(defn search-input [search-filter] + [react/view {:style {:flex 1 + :flex-direction :row}} + [react/text-input {:placeholder "Type here to search chats..." + :auto-focus true + :blur-on-submit true + :style {:flex 1 + :color :black + :height 30 + :margin-left 20 + :margin-right 22} + :default-value search-filter + :on-change (fn [e] + (let [native-event (.-nativeEvent e) + text (.-text native-event)] + (re-frame/dispatch [:search/filter-changed text])))}]]) + (views/defview chat-list-view [] - (views/letsubs [home-items [:home-items]] + (views/letsubs [search-filter [:search/filter] + filtered-home-items [:search/filtered-home-items]] [react/view {:style styles/chat-list-view} [react/view {:style styles/chat-list-header} - [react/view {:style {:flex 1}}] + [search-input search-filter] [react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :new-contact])} [react/view {:style styles/add-new} [icons/icon :icons/add {:style {:tint-color :white}}]]]] [react/view {:style styles/chat-list-separator}] [react/scroll-view {:enableArrayScrollingOptimization true} [react/view - (for [[index chat] (map-indexed vector home-items)] + (for [[index chat] (map-indexed vector filtered-home-items)] ^{:key (first chat)} [chat-list-item chat])]]])) diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index 9532d12e48..71d798957b 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -3,6 +3,7 @@ [status-im.utils.ethereum.core :as ethereum] status-im.chat.subs status-im.contact.subs + status-im.search.subs status-im.ui.screens.accounts.subs status-im.ui.screens.extensions.subs status-im.ui.screens.home.subs diff --git a/src/status_im/utils/db.cljs b/src/status_im/utils/db.cljs index 2efd786b48..a96953e009 100644 --- a/src/status_im/utils/db.cljs +++ b/src/status_im/utils/db.cljs @@ -10,3 +10,7 @@ (spec/def :global/not-empty-string (spec/and string? not-empty)) (spec/def :global/public-key (spec/and :global/not-empty-string valid-public-key?)) (spec/def :global/address ethereum/address?) + +(spec/def :status/tag (spec/and :global/not-empty-string + (partial re-matches #"[a-z0-9\-]+"))) +(spec/def :status/tags (spec/coll-of :status/tag :kind set?)) diff --git a/test/cljs/status_im/test/chat/subs.cljs b/test/cljs/status_im/test/chat/subs.cljs index 8b2e1034ec..f37fcd6873 100644 --- a/test/cljs/status_im/test/chat/subs.cljs +++ b/test/cljs/status_im/test/chat/subs.cljs @@ -118,4 +118,4 @@ (testing "it returns only chats with is-active" (is (= {1 active-chat-1 2 active-chat-2} - (s/active-chats chats)))))) + (s/active-chats [{} chats]))))))