From b80e02d8cf5da6d79fdc180fd8cda787710d7957 Mon Sep 17 00:00:00 2001 From: yenda Date: Thu, 20 Dec 2018 15:50:02 +0100 Subject: [PATCH] [feature] add block user feature in user profile - add block/unblock action to user profile - blocking deletes all messages from user and ignores future messages - unblocking stops ignoring new messages from user but doesn't recover past ones [feature] add contact list [tests] added scroll to BackupRecoveryPhraseButton [tests] added scroll to public key Signed-off-by: yenda --- resources/icons/add.svg | 3 - resources/icons/add_contact.svg | 4 +- resources/icons/bottom/contacts_active.svg | 6 - resources/icons/bottom/contacts_gray.svg | 2 +- resources/icons/contacts.svg | 3 + resources/icons/group_big.svg | 3 - resources/icons/in_contacts.svg | 4 +- resources/icons/main/add.svg | 3 + resources/icons/main/cancel.svg | 3 + resources/icons/main/group_chat.svg | 6 + resources/icons/main/in_contacts.svg | 4 + resources/icons/main/message.svg | 5 + resources/icons/main/send.svg | 3 + resources/icons/main/share.svg | 4 + resources/icons/tiny/tiny_group.svg | 3 + src/status_im/chat/models.cljs | 2 +- src/status_im/chat/models/loading.cljs | 7 -- src/status_im/contact/core.cljs | 119 +++++++++++++++++- src/status_im/contact/db.cljs | 21 ++++ src/status_im/contact/subs.cljs | 22 +++- src/status_im/data_store/contacts.cljs | 52 +++++++- src/status_im/data_store/messages.cljs | 17 ++- src/status_im/events.cljs | 18 +++ src/status_im/notifications/core.cljs | 15 ++- src/status_im/transport/message/core.cljs | 7 +- .../ui/components/icons/vector_icons.cljs | 32 +++-- src/status_im/ui/components/list/styles.cljs | 47 ++++++- src/status_im/ui/components/list/views.cljs | 34 +++++ .../ui/components/toolbar/actions.cljs | 2 +- src/status_im/ui/screens/add_new/views.cljs | 4 +- .../ui/screens/chat/stickers/views.cljs | 2 +- src/status_im/ui/screens/chat/views.cljs | 2 +- .../ui/screens/contacts_list/views.cljs | 54 ++++++++ .../ui/screens/desktop/main/chat/views.cljs | 4 +- .../screens/desktop/main/tabs/home/views.cljs | 6 +- .../ui/screens/hardwallet/settings/views.cljs | 2 +- src/status_im/ui/screens/home/views.cljs | 3 +- .../ui/screens/home/views/inner_item.cljs | 2 +- src/status_im/ui/screens/pairing/views.cljs | 2 +- .../ui/screens/profile/components/styles.cljs | 12 +- .../ui/screens/profile/components/views.cljs | 19 ++- .../ui/screens/profile/contact/styles.cljs | 13 +- .../ui/screens/profile/contact/views.cljs | 39 ++++-- .../ui/screens/profile/group_chat/views.cljs | 2 +- .../ui/screens/profile/user/views.cljs | 37 ++++-- src/status_im/ui/screens/views.cljs | 3 + .../ui/screens/wallet/request/views.cljs | 2 +- .../atomic/chats/test_chats_management.py | 11 +- test/appium/views/profile_view.py | 5 + translations/en.json | 6 + 50 files changed, 570 insertions(+), 111 deletions(-) delete mode 100644 resources/icons/add.svg delete mode 100644 resources/icons/bottom/contacts_active.svg create mode 100644 resources/icons/contacts.svg delete mode 100644 resources/icons/group_big.svg create mode 100644 resources/icons/main/add.svg create mode 100644 resources/icons/main/cancel.svg create mode 100644 resources/icons/main/group_chat.svg create mode 100644 resources/icons/main/in_contacts.svg create mode 100644 resources/icons/main/message.svg create mode 100644 resources/icons/main/send.svg create mode 100644 resources/icons/main/share.svg create mode 100644 resources/icons/tiny/tiny_group.svg create mode 100644 src/status_im/ui/screens/contacts_list/views.cljs diff --git a/resources/icons/add.svg b/resources/icons/add.svg deleted file mode 100644 index b575ddf761..0000000000 --- a/resources/icons/add.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/resources/icons/add_contact.svg b/resources/icons/add_contact.svg index e334a58286..f530bf3a6d 100644 --- a/resources/icons/add_contact.svg +++ b/resources/icons/add_contact.svg @@ -1,5 +1,5 @@ - - + + diff --git a/resources/icons/bottom/contacts_active.svg b/resources/icons/bottom/contacts_active.svg deleted file mode 100644 index d3021a98f8..0000000000 --- a/resources/icons/bottom/contacts_active.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/icons/bottom/contacts_gray.svg b/resources/icons/bottom/contacts_gray.svg index d9a15a611d..caceaff91a 100644 --- a/resources/icons/bottom/contacts_gray.svg +++ b/resources/icons/bottom/contacts_gray.svg @@ -1,3 +1,3 @@ - + diff --git a/resources/icons/contacts.svg b/resources/icons/contacts.svg new file mode 100644 index 0000000000..74ba703212 --- /dev/null +++ b/resources/icons/contacts.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/group_big.svg b/resources/icons/group_big.svg deleted file mode 100644 index e8c3ca6cb4..0000000000 --- a/resources/icons/group_big.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/resources/icons/in_contacts.svg b/resources/icons/in_contacts.svg index e4a1db2559..31d6a0d409 100644 --- a/resources/icons/in_contacts.svg +++ b/resources/icons/in_contacts.svg @@ -1,5 +1,5 @@ - - + + diff --git a/resources/icons/main/add.svg b/resources/icons/main/add.svg new file mode 100644 index 0000000000..7c17e5e067 --- /dev/null +++ b/resources/icons/main/add.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/main/cancel.svg b/resources/icons/main/cancel.svg new file mode 100644 index 0000000000..aed62c601e --- /dev/null +++ b/resources/icons/main/cancel.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/main/group_chat.svg b/resources/icons/main/group_chat.svg new file mode 100644 index 0000000000..7f4b624c19 --- /dev/null +++ b/resources/icons/main/group_chat.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/icons/main/in_contacts.svg b/resources/icons/main/in_contacts.svg new file mode 100644 index 0000000000..9e4533a75d --- /dev/null +++ b/resources/icons/main/in_contacts.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/main/message.svg b/resources/icons/main/message.svg new file mode 100644 index 0000000000..f37dcb899f --- /dev/null +++ b/resources/icons/main/message.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/icons/main/send.svg b/resources/icons/main/send.svg new file mode 100644 index 0000000000..24b34e2c79 --- /dev/null +++ b/resources/icons/main/send.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/icons/main/share.svg b/resources/icons/main/share.svg new file mode 100644 index 0000000000..d11dbf615b --- /dev/null +++ b/resources/icons/main/share.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/tiny/tiny_group.svg b/resources/icons/tiny/tiny_group.svg new file mode 100644 index 0000000000..495fe1e05d --- /dev/null +++ b/resources/icons/tiny/tiny_group.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/status_im/chat/models.cljs b/src/status_im/chat/models.cljs index 2f5d1895e6..9fcc5c1cc1 100644 --- a/src/status_im/chat/models.cljs +++ b/src/status_im/chat/models.cljs @@ -119,7 +119,7 @@ :unviewed-messages-count 0 :deleted-at-clock-value last-message-clock-value}) :data-store/tx [(chats-store/clear-history-tx chat-id last-message-clock-value) - (messages-store/delete-messages-tx chat-id)]})) + (messages-store/delete-chat-messages-tx chat-id)]})) (fx/defn deactivate-chat [{:keys [db now] :as cofx} chat-id] diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index 1665eeaf13..41d74bfc33 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -35,13 +35,6 @@ db (group-by (comp time/day-relative :timestamp) messages))}) -(fx/defn group-messages - [{:keys [db]}] - (reduce-kv (fn [fx chat-id {:keys [messages]}] - (group-chat-messages fx chat-id (vals messages))) - {:db db} - (:chats db))) - (defn- get-referenced-ids "Takes map of `message-id->messages` and returns set of maps of `{:response-to old-message-id :response-to-v2 message-id}`, diff --git a/src/status_im/contact/core.cljs b/src/status_im/contact/core.cljs index beeb3dbd76..be6c84849b 100644 --- a/src/status_im/contact/core.cljs +++ b/src/status_im/contact/core.cljs @@ -4,6 +4,8 @@ [status-im.chat.models :as chat.models] [status-im.contact.db :as contact.db] [status-im.data-store.contacts :as contacts-store] + [status-im.data-store.messages :as data-store.messages] + [status-im.data-store.chats :as data-store.chats] [status-im.i18n :as i18n] [status-im.transport.message.contact :as message.contact] [status-im.transport.message.protocol :as protocol] @@ -12,13 +14,17 @@ [status-im.utils.fx :as fx] [status-im.utils.utils :as utils] [status-im.transport.partitioned-topic :as transport.topic] - [status-im.utils.config :as config])) + [status-im.utils.config :as config] + [status-im.chat.models.loading :as chat.models.loading] + [status-im.chat.models.message :as chat.models.message])) (fx/defn load-contacts [{:keys [db all-contacts]}] (let [contacts-list (map #(vector (:public-key %) %) all-contacts) contacts (into {} contacts-list)] - {:db (update db :contacts/contacts #(merge contacts %))})) + {:db (-> db + (update :contacts/contacts #(merge contacts %)) + (assoc :contacts/blocked (contact.db/get-blocked-contacts all-contacts)))})) (defn can-add-to-contacts? [{:keys [pending? dapp?]}] (and (not dapp?) @@ -28,11 +34,10 @@ (defn build-contact [{{:keys [chats] :account/keys [account] :contacts/keys [contacts]} :db} public-key] - (cond-> (assoc (or (get contacts public-key) - (contact.db/public-key->new-contact public-key)) + (cond-> (assoc (contact.db/public-key->contact contacts public-key) :address (contact.db/public-key->address public-key)) - - (= public-key (:public-key account)) (assoc :name (:name account)))) + (= public-key (:public-key account)) + (assoc :name (:name account)))) (defn- own-info [db] (let [{:keys [name photo-path address]} (:account/account db) @@ -101,6 +106,108 @@ {:db (assoc-in db [:contacts/contacts public-key :tags] tags) :data-store/tx [(contacts-store/remove-contact-tag-tx public-key tag)]})) +(fx/defn block-contact-confirmation + [cofx public-key] + {:utils/show-confirmation + {:title (i18n/label :t/block-contact) + :content (i18n/label :t/block-contact-details) + :confirm-button-text (i18n/label :t/to-block) + :on-accept #(re-frame/dispatch [:contact.ui/block-contact-confirmed public-key])}}) + +(defn get-removed-unseen-count + [current-public-key user-statuses removed-messages-ids] + (- (count removed-messages-ids) + (count (filter (fn [[_ statuses]] + (= :seen + (:status (get statuses + current-public-key)))) + user-statuses)))) + +(fx/defn clean-up-chat + [{:keys [db get-stored-user-statuses] :as cofx} chat-id removed-chat-messages] + (let [current-public-key (accounts.db/current-public-key cofx) + removed-messages-ids (map :message-id removed-chat-messages) + user-statuses (get-stored-user-statuses chat-id + removed-messages-ids) + removed-unseen-count (get-removed-unseen-count current-public-key + user-statuses + removed-messages-ids) + db (-> db + ;; remove messages + (update-in [:chats chat-id :messages] + #(apply dissoc % removed-messages-ids)) + ;; remove message statuses + (update-in [:chats chat-id :messages-statuses] + #(apply dissoc % removed-messages-ids)) + ;; remove message groups + (update-in [:chats chat-id] + dissoc :message-groups))] + (fx/merge cofx + {:db db} + ;; update unviewed messages count + (chat.models/upsert-chat + {:chat-id chat-id + :unviewed-messages-count + (- (get-in db [:chats chat-id :unviewed-messages-count]) + removed-unseen-count)}) + ;; recompute message group + (chat.models.loading/group-chat-messages + chat-id + (vals (get-in db [:chats chat-id :messages])))))) + +(fx/defn clean-up-chats + [cofx removed-messages-by-chat] + (apply fx/merge cofx + (map (fn [[chat-id messages]] + (clean-up-chat chat-id messages)) + removed-messages-by-chat))) + +(fx/defn remove-current-chat-id + [{:keys [db] :as cofx}] + (fx/merge cofx + {:db (dissoc db :current-chat-id)} + (navigation/navigate-to-clean :home {}))) + +(fx/defn block-contact + [{:keys [db get-user-messages] :as cofx} public-key] + (let [contact (assoc (contact.db/public-key->contact + (:contacts/contacts db) + public-key) + :blocked? true) + user-messages (get-user-messages public-key) + user-messages-ids (map :message-id user-messages) + ;; we make sure to remove the 1-1 chat which we delete entirely + removed-messages-by-chat (-> (group-by :chat-id user-messages) + (dissoc public-key)) + from-one-to-one-chat? (not (get-in db [:chats (:current-chat-id db) :group-chat]))] + (fx/merge cofx + {:db (-> db + ;; add the contact to blocked contacts + (update :contacts/blocked conj public-key) + ;; update the contact in contacts list + (assoc-in [:contacts/contacts public-key] contact) + ;; remove the 1-1 chat if it exists + (update-in [:chats] dissoc public-key)) + :data-store/tx [(contacts-store/block-user-tx contact + user-messages-ids)]} + ;;remove the messages from chat + (clean-up-chats removed-messages-by-chat) + (chat.models.message/update-last-messages + (keys removed-messages-by-chat)) + ;; reset navigation to avoid going back to non existing one to one chat + (if from-one-to-one-chat? + remove-current-chat-id + (navigation/navigate-back))))) + +(fx/defn unblock-contact + [{:keys [db]} public-key] + (let [contact (assoc (get-in db [:contacts/contacts public-key]) + :blocked? false)] + {:db (-> db + (update :contacts/blocked disj public-key) + (assoc-in [:contacts/contacts public-key] contact)) + :data-store/tx [(contacts-store/save-contact-tx contact)]})) + (defn handle-contact-update [public-key timestamp diff --git a/src/status_im/contact/db.cljs b/src/status_im/contact/db.cljs index ea9b3677ed..58c8cffa08 100644 --- a/src/status_im/contact/db.cljs +++ b/src/status_im/contact/db.cljs @@ -68,6 +68,12 @@ :photo-path (identicon/identicon public-key) :public-key public-key}) +(defn public-key->contact + [contacts public-key] + (when public-key + (get contacts public-key + (public-key->new-contact public-key)))) + (defn public-key->address [public-key] (let [length (count public-key) normalized-key (case length @@ -94,6 +100,13 @@ (clojure.string/lower-case name2)))) (vals contacts))) +(defn active + [contacts] + (->> contacts + (remove (fn [[_ {:keys [pending? hide-contact? blocked?]}]] + (or pending? hide-contact? blocked?))) + sort-contacts)) + (defn filter-dapps [v dev-mode?] (remove #(when-not dev-mode? (true? (:developer? %))) v)) @@ -121,3 +134,11 @@ (map #(if (admins (:public-key %)) (assoc % :admin? true) %))))) + +(defn get-blocked-contacts + [contacts] + (into #{} (map :public-key (filter :blocked? contacts)))) + +(defn blocked? + [db contact] + (get-in db [:contacts/contacts contact :blocked?])) diff --git a/src/status_im/contact/subs.cljs b/src/status_im/contact/subs.cljs index 6bb495096e..64189a955e 100644 --- a/src/status_im/contact/subs.cljs +++ b/src/status_im/contact/subs.cljs @@ -23,12 +23,30 @@ (re-frame/reg-sub :contacts/active :<- [:contacts/contacts] + (fn [contacts] + (contact.db/active contacts))) + +(re-frame/reg-sub + :contacts/active-count + :<- [:contacts/active] + (fn [active-contacts] + (count active-contacts))) + +(re-frame/reg-sub + :contacts/blocked + :<- [:contacts/contacts] (fn [contacts] (->> contacts - (remove (fn [[_ {:keys [pending? hide-contact?]}]] - (or pending? hide-contact?))) + (filter (fn [[_ {:keys [blocked?]}]] + blocked?)) (contact.db/sort-contacts)))) +(re-frame/reg-sub + :contacts/blocked-count + :<- [:contacts/blocked] + (fn [blocked-contacts] + (count blocked-contacts))) + (re-frame/reg-sub :contacts/current-contact-identity (fn [db] diff --git a/src/status_im/data_store/contacts.cljs b/src/status_im/data_store/contacts.cljs index c6480599fa..825ab1bbb7 100644 --- a/src/status_im/data_store/contacts.cljs +++ b/src/status_im/data_store/contacts.cljs @@ -1,7 +1,8 @@ (ns status-im.data-store.contacts (:require [goog.object :as object] [re-frame.core :as re-frame] - [status-im.data-store.realm.core :as core])) + [status-im.data-store.realm.core :as core] + [clojure.set :as clojure.set])) (defn- normalize-contact [contact] (-> contact @@ -21,7 +22,7 @@ (fn [realm] (core/create realm :contact - (dissoc contact :command :response :subscriptions) + contact true))) (defn save-contacts-tx @@ -34,6 +35,53 @@ (defn- get-contact-by-id [public-key realm] (core/single (core/get-by-field realm :contact :public-key public-key))) +(defn- get-messages-by-messages-ids + [message-ids] + (when (not-empty message-ids) + (-> @core/account-realm + (.objects "message") + (.filtered (str "(" (core/in-query "message-id" message-ids) ")"))))) + +(defn- get-statuses-by-messages-ids + [message-ids] + (when-not (empty message-ids) + (-> @core/account-realm + (.objects "user-status") + (.filtered (str "(" (core/in-query "message-id" message-ids) ")"))))) + +(defn- get-user-statuses + [public-key] + (core/get-by-field @core/account-realm + :user-status + :public-key + public-key)) + +(defn- get-chat + [public-key] + (core/single + (core/get-by-field @core/account-realm + :chat + :chat-id + public-key))) + +(defn block-user-tx + "Returns tx function for deleting user messages" + [{:keys [public-key] :as contact} messages-ids] + (fn [realm] + (core/create realm :contact contact true) + (when-let [user-messages + (get-messages-by-messages-ids messages-ids)] + (core/delete realm user-messages)) + (when-let [user-messages-statuses + (get-statuses-by-messages-ids messages-ids)] + (core/delete realm user-messages-statuses)) + (when-let [user-statuses + (get-user-statuses public-key)] + (core/delete realm user-statuses)) + (when-let [chat + (get-chat public-key)] + (core/delete realm chat)))) + (defn delete-contact-tx "Returns tx function for deleting contact" [public-key] diff --git a/src/status_im/data_store/messages.cljs b/src/status_im/data_store/messages.cljs index a4da79d431..472e9298b8 100644 --- a/src/status_im/data_store/messages.cljs +++ b/src/status_im/data_store/messages.cljs @@ -85,6 +85,21 @@ (fn [cofx _] (assoc cofx :get-referenced-messages get-references-by-ids))) +(defn get-user-messages + [public-key] + (.reduce (core/get-by-field @core/account-realm + :message :from public-key) + (fn [acc message-object _ _] + (conj acc + {:message-id (aget message-object "message-id") + :chat-id (aget message-object "chat-id")})) + [])) + +(re-frame/reg-cofx + :data-store/get-user-messages + (fn [cofx _] + (assoc cofx :get-user-messages get-user-messages))) + (defn prepare-content [content] (if (string? content) content @@ -112,7 +127,7 @@ (core/delete realm message) (core/delete realm (core/get-by-field realm :user-status :message-id message-id))))) -(defn delete-messages-tx +(defn delete-chat-messages-tx "Returns tx function for deleting messages with user statuses for given chat-id" [chat-id] (fn [realm] diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index a2b0c12968..7a3e4eef08 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -38,6 +38,7 @@ [status-im.signals.core :as signals] [status-im.transport.message.core :as transport.message] [status-im.ui.screens.currency-settings.models :as currency-settings.models] + [status-im.chat.models.message :as models.message] [status-im.node.core :as node] [status-im.web3.core :as web3] [status-im.ui.screens.navigation :as navigation] @@ -1468,6 +1469,23 @@ (contact/add-contacts-filter cofx public-key :add-contact) (contact/add-contact cofx public-key)))) +(handlers/register-handler-fx + :contact.ui/block-contact-pressed + (fn [cofx [_ public-key]] + (contact/block-contact-confirmation cofx public-key))) + +(handlers/register-handler-fx + :contact.ui/block-contact-confirmed + [(re-frame/inject-cofx :data-store/get-user-messages) + (re-frame/inject-cofx :data-store/get-user-statuses)] + (fn [cofx [_ public-key]] + (contact/block-contact cofx public-key))) + +(handlers/register-handler-fx + :contact.ui/unblock-contact-pressed + (fn [cofx [_ public-key]] + (contact/unblock-contact cofx public-key))) + (handlers/register-handler-fx :contact.ui/close-contact-pressed (fn [cofx [_ public-key]] diff --git a/src/status_im/notifications/core.cljs b/src/status_im/notifications/core.cljs index a9793c0d0b..6037ad3314 100644 --- a/src/status_im/notifications/core.cljs +++ b/src/status_im/notifications/core.cljs @@ -6,6 +6,7 @@ [taoensso.timbre :as log] [status-im.i18n :as i18n] [status-im.accounts.db :as accounts.db] + [status-im.contact.db :as contact.db] [status-im.chat.models :as chat-model] [status-im.utils.platform :as platform] [status-im.utils.fx :as fx] @@ -82,7 +83,7 @@ (:public-key (first (filter #(= (anonymize-pubkey (:public-key %)) hash) - (vals accounts))))) + accounts)))) (defn lookup-contact-pubkey-from-hash [{:keys [db] :as cofx} contact-pubkey-or-hash] @@ -93,13 +94,14 @@ (= (count contact-pubkey-or-hash) pn-pubkey-hash-length)) (if-let [account-pubkey (hash->pubkey contact-pubkey-or-hash - (:accounts/accounts db))] + (vals (:accounts/accounts db)))] account-pubkey (if (accounts.db/logged-in? cofx) ;; TODO: for simplicity we're doing a linear lookup of the contacts, ;; but we might want to build a map of hashed pubkeys to pubkeys ;; for this purpose - (hash->pubkey contact-pubkey-or-hash (:contacts/contacts db)) + (hash->pubkey contact-pubkey-or-hash + (contact.db/active (:contacts/contacts db))) (do (log/warn "failed to lookup contact from hash, not logged in") contact-pubkey-or-hash))) @@ -202,7 +204,7 @@ (and (valid-notification-payload? rehydrated-payload) (accounts.db/logged-in? cofx) (some #(= (:public-key %) from) - (vals (:contacts/contacts db))) + (contact.db/active (:contacts/contacts db))) (some #(= (:chat-id %) from) (vals (:chats db))))) @@ -318,10 +320,10 @@ (create-notification-channel)) (handle-initial-push-notification))) -(fx/defn process-stored-event [cofx address stored-pns] +(fx/defn process-stored-event [{:keys [db] :as cofx} address stored-pns] (when-not platform/desktop? (if (accounts.db/logged-in? cofx) - (let [current-account (get-in cofx [:db :account/account]) + (let [current-account (:account/account db) current-address (:address current-account) current-account-pubkey (:public-key current-account) stored-pn-val-json (or (get stored-pns current-account-pubkey) @@ -333,6 +335,7 @@ from (lookup-contact-pubkey-from-hash cofx (:from stored-pn-payload)) to (lookup-contact-pubkey-from-hash cofx (:to stored-pn-payload))] (when (and from + (not (contact.db/blocked? db from)) (= address current-address)) (log/debug "process-stored-event" "address" address "from" from "to" to) (handle-push-notification-open cofx diff --git a/src/status_im/transport/message/core.cljs b/src/status_im/transport/message/core.cljs index 9567a35cc1..d9775e0941 100644 --- a/src/status_im/transport/message/core.cljs +++ b/src/status_im/transport/message/core.cljs @@ -12,11 +12,14 @@ (fx/defn receive-message [cofx now-in-s filter-chat-id js-message] - (let [{:keys [payload sig timestamp ttl]} (js->clj js-message :keywordize-keys true) + (let [blocked-contacts (get-in cofx [:db :contacts/blocked] #{}) + {:keys [payload sig timestamp ttl]} (js->clj js-message :keywordize-keys true) status-message (-> payload transport.utils/to-utf8 transit/deserialize)] - (when (and sig status-message) + (when (and sig + status-message + (not (blocked-contacts sig))) (try (when-let [valid-message (protocol/validate status-message)] (fx/merge (assoc cofx :js-obj js-message) diff --git a/src/status_im/ui/components/icons/vector_icons.cljs b/src/status_im/ui/components/icons/vector_icons.cljs index 7e5b12b53f..dbf8aaa5b5 100644 --- a/src/status_im/ui/components/icons/vector_icons.cljs +++ b/src/status_im/ui/components/icons/vector_icons.cljs @@ -30,8 +30,16 @@ (def icons (if platform/desktop? - {:icons/discover (js/require "./resources/icons/bottom/discover_gray.svg") - :icons/contacts (js/require "./resources/icons/bottom/contacts_gray.svg") + {:main-icons/add (js/require "./resources/icons/main/add.svg") + :main-icons/cancel (js/require "./resources/icons/main/cancel.svg") + :main-icons/group-chat (js/require "./resources/icons/main/group_chat.svg") + :main-icons/in-contacts (js/require "./resources/icons/main/in_contacts.svg") + :main-icons/message (js/require "./resources/icons/main/message.svg") + :main-icons/send (js/require "./resources/icons/main/send.svg") + :main-icons/share (js/require "./resources/icons/main/share.svg") + :tiny-icons/tiny-group (js/require "./resources/icons/tiny/tiny_group.svg") + :icons/discover (js/require "./resources/icons/bottom/discover_gray.svg") + :icons/home (js/require "./resources/icons/bottom/home_gray.svg") :icons/home-active (js/require "./resources/icons/bottom/home_blue.svg") :icons/profile (js/require "./resources/icons/bottom/profile_gray.svg") @@ -41,7 +49,6 @@ :icons/speaker (js/require "./resources/icons/speaker.svg") :icons/speaker-off (js/require "./resources/icons/speaker_off.svg") :icons/transaction-history (js/require "./resources/icons/transaction_history.svg") - :icons/add (js/require "./resources/icons/add.svg") :icons/add-contact (js/require "./resources/icons/add_contact.svg") :icons/add-wallet (js/require "./resources/icons/add_wallet.svg") :icons/address (js/require "./resources/icons/address.svg") @@ -60,12 +67,9 @@ :icons/exclamation-mark (js/require "./resources/icons/exclamation_mark.svg") :icons/filter (js/require "./resources/icons/filter.svg") :icons/fullscreen (js/require "./resources/icons/fullscreen.svg") - :icons/group-big (js/require "./resources/icons/group_big.svg") - :icons/group-chat (js/require "./resources/icons/group_chat.svg") :icons/chats (js/require "./resources/icons/chats.svg") :icons/hamburger (js/require "./resources/icons/hamburger.svg") :icons/hidden (js/require "./resources/icons/hidden.svg") - :icons/in-contacts (js/require "./resources/icons/in_contacts.svg") :icons/lock (js/require "./resources/icons/lock.svg") :icons/mic (js/require "./resources/icons/mic.svg") :icons/mobile (js/require "./resources/icons/mobile.svg") @@ -81,7 +85,6 @@ :icons/up (js/require "./resources/icons/up.svg") :icons/down (js/require "./resources/icons/down.svg") :icons/grab (js/require "./resources/icons/grab.svg") - :icons/share (js/require "./resources/icons/share.svg") :icons/tooltip-triangle (js/require "./resources/icons/tooltip-triangle.svg") :icons/open (js/require "./resources/icons/open.svg") :icons/network (js/require "./resources/icons/network.svg") @@ -106,7 +109,15 @@ :icons/indicator-middle (js/require "./resources/icons/indicator-middle.svg") :icons/indicator-small (js/require "./resources/icons/indicator-small.svg") :icons/stickers (js/require "./resources/icons/stickers.svg")} - {:icons/discover (components.svg/slurp-svg "./resources/icons/bottom/discover_gray.svg") + {:main-icons/add (components.svg/slurp-svg "./resources/icons/main/add.svg") + :main-icons/cancel (components.svg/slurp-svg "./resources/icons/main/cancel.svg") + :main-icons/group-chat (components.svg/slurp-svg "./resources/icons/main/group_chat.svg") + :main-icons/in-contacts (components.svg/slurp-svg "./resources/icons/main/in_contacts.svg") + :main-icons/message (components.svg/slurp-svg "./resources/icons/main/message.svg") + :main-icons/send (components.svg/slurp-svg "./resources/icons/main/send.svg") + :main-icons/share (components.svg/slurp-svg "./resources/icons/main/share.svg") + :tiny-icons/tiny-group (components.svg/slurp-svg "./resources/icons/tiny/tiny_group.svg") + :icons/discover (components.svg/slurp-svg "./resources/icons/bottom/discover_gray.svg") :icons/contacts (components.svg/slurp-svg "./resources/icons/bottom/contacts_gray.svg") :icons/home (components.svg/slurp-svg "./resources/icons/bottom/home_gray.svg") :icons/home-active (components.svg/slurp-svg "./resources/icons/bottom/home_blue.svg") @@ -117,7 +128,6 @@ :icons/speaker (components.svg/slurp-svg "./resources/icons/speaker.svg") :icons/speaker-off (components.svg/slurp-svg "./resources/icons/speaker_off.svg") :icons/transaction-history (components.svg/slurp-svg "./resources/icons/transaction_history.svg") - :icons/add (components.svg/slurp-svg "./resources/icons/add.svg") :icons/add-contact (components.svg/slurp-svg "./resources/icons/add_contact.svg") :icons/add-wallet (components.svg/slurp-svg "./resources/icons/add_wallet.svg") :icons/address (components.svg/slurp-svg "./resources/icons/address.svg") @@ -139,12 +149,9 @@ :icons/exclamation-mark (components.svg/slurp-svg "./resources/icons/exclamation_mark.svg") :icons/filter (components.svg/slurp-svg "./resources/icons/filter.svg") :icons/fullscreen (components.svg/slurp-svg "./resources/icons/fullscreen.svg") - :icons/group-big (components.svg/slurp-svg "./resources/icons/group_big.svg") - :icons/group-chat (components.svg/slurp-svg "./resources/icons/group_chat.svg") :icons/chats (components.svg/slurp-svg "./resources/icons/chats.svg") :icons/hamburger (components.svg/slurp-svg "./resources/icons/hamburger.svg") :icons/hidden (components.svg/slurp-svg "./resources/icons/hidden.svg") - :icons/in-contacts (components.svg/slurp-svg "./resources/icons/in_contacts.svg") :icons/lock (components.svg/slurp-svg "./resources/icons/lock.svg") :icons/lock-opened (components.svg/slurp-svg "./resources/icons/lock_opened.svg") :icons/mic (components.svg/slurp-svg "./resources/icons/mic.svg") @@ -161,7 +168,6 @@ :icons/up (components.svg/slurp-svg "./resources/icons/up.svg") :icons/down (components.svg/slurp-svg "./resources/icons/down.svg") :icons/grab (components.svg/slurp-svg "./resources/icons/grab.svg") - :icons/share (components.svg/slurp-svg "./resources/icons/share.svg") :icons/tooltip-triangle (components.svg/slurp-svg "./resources/icons/tooltip-triangle.svg") :icons/open (components.svg/slurp-svg "./resources/icons/open.svg") :icons/network (components.svg/slurp-svg "./resources/icons/network.svg") diff --git a/src/status_im/ui/components/list/styles.cljs b/src/status_im/ui/components/list/styles.cljs index d9f4e3422f..80b9692a78 100644 --- a/src/status_im/ui/components/list/styles.cljs +++ b/src/status_im/ui/components/list/styles.cljs @@ -37,8 +37,16 @@ (def image-size 40) (def item-image - {:width image-size - :height image-size}) + {:width image-size + :height image-size}) + +(def big-item-image + {:width image-size + :height image-size + :margin-right 16 + :border-radius 40 + :border-color (colors/alpha colors/gray 0.1) + :border-width 1}) (def icon-size 24) (def icon-wrapper-size (+ icon-size (* 2 8))) @@ -65,6 +73,41 @@ (def right-item-wrapper {:justify-content :center}) +(def settings-item-separator + {:margin-left 16}) + +(def settings-item + {:padding-left 16 + :padding-right 8 + :flex 1 + :flex-direction :row + :align-items :center + :background-color colors/white + :height 52}) + +(defn settings-item-icon [icon-color] + {:background-color (colors/alpha icon-color 0.1) + :width 40 + :height 40 + :border-radius 40 + :margin-right 16 + :justify-content :center + :align-items :center}) + +(defn settings-item-text + [color] + {:flex 1 + :flex-wrap :nowrap + :font-size 17 + :color color}) + +(def settings-item-value + {:flex-wrap :nowrap + :text-align :right + :padding-right 10 + :font-size 15 + :color colors/gray}) + (def base-separator {:height 1 :background-color colors/gray-light}) diff --git a/src/status_im/ui/components/list/views.cljs b/src/status_im/ui/components/list/views.cljs index a6b377b336..999ad7b5b9 100644 --- a/src/status_im/ui/components/list/views.cljs +++ b/src/status_im/ui/components/list/views.cljs @@ -20,6 +20,8 @@ " (:require-macros [status-im.utils.views :as views]) (:require [reagent.core :as reagent] + [clojure.string :as string] + [status-im.i18n :as i18n] [status-im.ui.components.animation :as animation] [status-im.ui.components.checkbox.view :as checkbox] [status-im.ui.components.colors :as colors] @@ -101,6 +103,38 @@ :style {:width 12} :icon-opts {:color colors/white}}]) +(defn big-list-item + [{:keys [text text-color value action-fn active? destructive? hide-chevron? + accessory-value text-color + accessibility-label icon icon-color image-source icon-content] + :or {icon-color colors/blue + text-color colors/black + value "" + active? true}}] + {:pre [(or icon image-source) + (and action-fn text) + (or (nil? accessibility-label) (keyword? accessibility-label))]} + [react/touchable-highlight + (cond-> {:on-press action-fn + :accessibility-label accessibility-label + :disabled (not active?)}) + [react/view styles/settings-item + (if icon + [react/view (styles/settings-item-icon icon-color) + [vector-icons/icon icon {:color icon-color}]] + [react/image {:source {:uri image-source} + :style styles/big-item-image}]) + [react/text {:style (styles/settings-item-text text-color) + :number-of-lines 1} + text] + (when accessory-value + [react/text {:style styles/settings-item-value + :number-of-lines 1 + :uppercase? true} + (str accessory-value)]) + (when-not hide-chevron? + [vector-icons/icon :icons/forward {:color (colors/alpha colors/gray 0.4)}])]]) + (defn- wrap-render-fn [f] (fn [data] (reagent/as-element (f (.-item data) (.-index data) (.-separators data))))) diff --git a/src/status_im/ui/components/toolbar/actions.cljs b/src/status_im/ui/components/toolbar/actions.cljs index 22c146bbbc..afd293af49 100644 --- a/src/status_im/ui/components/toolbar/actions.cljs +++ b/src/status_im/ui/components/toolbar/actions.cljs @@ -3,7 +3,7 @@ [status-im.ui.components.toolbar.styles :as styles])) (defn add [illuminated? handler] - {:icon :icons/add + {:icon :main-icons/add :icon-opts (if illuminated? styles/icon-add-illuminated styles/icon-add) :handler handler}) diff --git a/src/status_im/ui/screens/add_new/views.cljs b/src/status_im/ui/screens/add_new/views.cljs index c7a9b0b406..3c91649c0c 100644 --- a/src/status_im/ui/screens/add_new/views.cljs +++ b/src/status_im/ui/screens/add_new/views.cljs @@ -25,7 +25,7 @@ [action-button/action-button {:label (i18n/label :t/start-group-chat) :accessibility-label :start-group-chat-button - :icon :icons/contacts + :icon :main-icons/group-chat :icon-opts {:color colors/blue} :on-press #(re-frame/dispatch [:contact.ui/start-group-chat-pressed])}] [action-button/action-separator] @@ -46,7 +46,7 @@ [action-button/action-button {:label (i18n/label :t/invite-friends) :accessibility-label :invite-friends-button - :icon :icons/share + :icon :main-icons/share :icon-opts {:color colors/blue} :on-press #(list-selection/open-share {:message (i18n/label :t/get-status-at)})}] [action-button/action-separator] diff --git a/src/status_im/ui/screens/chat/stickers/views.cljs b/src/status_im/ui/screens/chat/stickers/views.cljs index ec4ce62c5d..e3fc503eba 100644 --- a/src/status_im/ui/screens/chat/stickers/views.cljs +++ b/src/status_im/ui/screens/chat/stickers/views.cljs @@ -76,7 +76,7 @@ (re-frame/dispatch [:stickers/load-packs]) (re-frame/dispatch [:navigate-to :stickers])) :selected? false :background-color colors/blue} - [vector-icons/icon :icons/add {:width 20 :height 20 :color colors/white}]] + [vector-icons/icon :main-icons/add {:width 20 :height 20 :color colors/white}]] [react/view {:width 4}] [pack-icon {:id :recent :selected? (or (= :recent selected-pack) (and (nil? selected-pack) (seq installed-packs)))} [vector-icons/icon :icons/clock]] diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs index e278b1fd65..35f42bf4da 100644 --- a/src/status_im/ui/screens/chat/views.cljs +++ b/src/status_im/ui/screens/chat/views.cljs @@ -40,7 +40,7 @@ {:on-press #(re-frame/dispatch [:contact.ui/add-to-contact-pressed contact-identity]) :accessibility-label :add-to-contacts-button} [react/view style/add-contact-center - [vector-icons/icon :icons/add {:color colors/blue}] + [vector-icons/icon :main-icons/add {:color colors/blue}] [react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]] [react/touchable-highlight {:on-press #(re-frame/dispatch [:contact.ui/close-contact-pressed contact-identity]) diff --git a/src/status_im/ui/screens/contacts_list/views.cljs b/src/status_im/ui/screens/contacts_list/views.cljs new file mode 100644 index 0000000000..8578478a96 --- /dev/null +++ b/src/status_im/ui/screens/contacts_list/views.cljs @@ -0,0 +1,54 @@ +(ns status-im.ui.screens.contacts-list.views + (:require [re-frame.core :as re-frame] + [status-im.ui.components.colors :as colors] + [status-im.ui.components.list.views :as list.views] + [status-im.ui.components.react :as react] + [status-im.i18n :as i18n] + [status-im.ui.components.contact.contact :as contact-view] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.toolbar.view :as toolbar.view]) + (:require-macros [status-im.utils.views :refer [defview letsubs]])) + +(defn contacts-list-item [{:keys [public-key name photo-path] :as contact}] + [list.views/big-list-item + {:text name + :image-source photo-path + :action-fn #(re-frame/dispatch [:chat.ui/show-profile public-key])}]) + +(defview contacts-list [] + (letsubs [blocked-contacts-count [:contacts/blocked-count] + contacts [:contacts/active]] + [react/view {:flex 1 + :background-color colors/white} + [status-bar/status-bar] + [toolbar.view/simple-toolbar (i18n/label :t/contacts)] + [react/scroll-view {:style {:background-color colors/white + :padding-top 16}} + [list.views/big-list-item + {:text (i18n/label :t/blocked-users) + :icon :main-icons/cancel + :icon-color colors/red + :accessibility-label :blocked-users-list-button + :accessory-value blocked-contacts-count + :action-fn #(re-frame/dispatch [:navigate-to :blocked-users-list])}] + [react/view {:height 16}] + [list.views/flat-list + {:data contacts + :key-fn :address + :render-fn contacts-list-item}]]])) + +(defview blocked-users-list [] + (letsubs [blocked-contacts [:contacts/blocked]] + [react/view {:flex 1 + :background-color colors/white} + [status-bar/status-bar] + [toolbar.view/simple-toolbar (i18n/label :t/blocked-users)] + [react/scroll-view {:style {:background-color colors/white + :padding-vertical 8}} + [list.views/flat-list + {:data blocked-contacts + :key-fn :address + :render-fn contacts-list-item + :default-separator? true + :enableEmptySections true + :keyboardShouldPersistTaps :always}]]])) diff --git a/src/status_im/ui/screens/desktop/main/chat/views.cljs b/src/status_im/ui/screens/desktop/main/chat/views.cljs index 12c3c49944..b15acc5ec8 100644 --- a/src/status_im/ui/screens/desktop/main/chat/views.cljs +++ b/src/status_im/ui/screens/desktop/main/chat/views.cljs @@ -360,12 +360,12 @@ [react/view {:style styles/chat-profile-row} [react/view {:style styles/chat-profile-icon-container :accessibility-label :add-contact-link} - [vector-icons/icon :icons/add {:style (styles/chat-profile-icon colors/blue)}]] + [vector-icons/icon :main-icons/add {:style (styles/chat-profile-icon colors/blue)}]] [react/text {:style (styles/contact-card-text colors/blue)} (i18n/label :t/add-to-contacts)]]] [react/view {:style styles/chat-profile-row} [react/view {:style styles/chat-profile-icon-container :accessibility-label :add-contact-link} - [vector-icons/icon :icons/add {:style (styles/chat-profile-icon colors/gray)}]] + [vector-icons/icon :main-icons/add {:style (styles/chat-profile-icon colors/gray)}]] [react/text {:style (styles/contact-card-text colors/gray)} (i18n/label :t/in-contacts)]]) [react/touchable-highlight {:on-press #(re-frame/dispatch 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 321f36fd74..2db80bd2a4 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 @@ -47,7 +47,7 @@ [react/view {:style styles/chat-name-last-msg-box} [react/view {:style styles/chat-name-box} (when (and group-chat (not public?)) - [icons/icon :icons/group-chat]) + [icons/icon :tiny-icons/tiny-group]) (when public? [icons/icon :icons/public-chat]) [react/text {:ellipsize-mode :tail @@ -126,7 +126,7 @@ [action-button/action-button {:label (i18n/label :t/start-group-chat) :accessibility-label :start-group-chat-button - :icon :icons/contacts + :icon :main-icons/group-chat :icon-opts {:color colors/blue} :on-press #(do (re-frame/dispatch [:set-in [:desktop :popup] nil]) @@ -157,7 +157,7 @@ [react/view {:style styles/add-new} (if logging-in? [components/activity-indicator {:animating true :color :white}] - [icons/icon :icons/add {:style {:tint-color :white}}])]]]] + [icons/icon :main-icons/add {:style {:tint-color :white}}])]]]] [react/scroll-view {:enableArrayScrollingOptimization true} [react/view (for [[index chat] (map-indexed vector filtered-home-items)] diff --git a/src/status_im/ui/screens/hardwallet/settings/views.cljs b/src/status_im/ui/screens/hardwallet/settings/views.cljs index 46658a5c53..0d83242d2c 100644 --- a/src/status_im/ui/screens/hardwallet/settings/views.cljs +++ b/src/status_im/ui/screens/hardwallet/settings/views.cljs @@ -164,7 +164,7 @@ :on-press #(.openURL react/linking "https://hardwallet.status.im")}] (when pairing [react/view - [action-row {:icon :icons/add + [action-row {:icon :main-icons/add :label :t/change-pin :on-press #(re-frame/dispatch [:keycard-settings.ui/change-pin-pressed])}] [action-row {:icon :icons/close diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index a5627e3fe7..25c6c954b9 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -51,11 +51,10 @@ [react/touchable-highlight {:accessibility-label :new-chat-button :on-press (when logged-in? #(re-frame/dispatch [:navigate-to :new]))} [react/view styles/action-button - (if-not logged-in? [components/activity-indicator {:color :white :animating true}] - [icons/icon :icons/add {:color :white}])]]]) + [icons/icon :main-icons/add {:color :white}])]]]) (defn home-list-item [[home-item-id home-item]] (let [delete-action (if (:chat-id home-item) diff --git a/src/status_im/ui/screens/home/views/inner_item.cljs b/src/status_im/ui/screens/home/views/inner_item.cljs index 534260acb4..5c501d0637 100644 --- a/src/status_im/ui/screens/home/views/inner_item.cljs +++ b/src/status_im/ui/screens/home/views/inner_item.cljs @@ -83,7 +83,7 @@ [vector-icons/icon :icons/public-chat {:color colors/gray}]]) (when private-group? [react/view styles/private-group-icon-container - [vector-icons/icon :icons/group-chat {:color colors/gray}]]) + [vector-icons/icon :tiny-icons/tiny-group {:color colors/gray}]]) [react/view {:flex-shrink 1} [react/text {:style styles/name-text :number-of-lines 1 diff --git a/src/status_im/ui/screens/pairing/views.cljs b/src/status_im/ui/screens/pairing/views.cljs index 65ee6a2f4d..6ac8e9e3e1 100644 --- a/src/status_im/ui/screens/pairing/views.cljs +++ b/src/status_im/ui/screens/pairing/views.cljs @@ -74,7 +74,7 @@ [react/view {:style styles/pair-this-device-actions} [react/view [react/view (styles/pairing-button true) - [icons/icon :icons/add (icon-style (styles/pairing-button-icon true))]]] + [icons/icon :main-icons/add (icon-style (styles/pairing-button-icon true))]]] [react/view {:style styles/pairing-actions-text} [react/view [react/text {:style styles/pair-this-device-title} (i18n/label :t/pair-this-device)]] diff --git a/src/status_im/ui/screens/profile/components/styles.cljs b/src/status_im/ui/screens/profile/components/styles.cljs index 4018551145..c769a99828 100644 --- a/src/status_im/ui/screens/profile/components/styles.cljs +++ b/src/status_im/ui/screens/profile/components/styles.cljs @@ -15,7 +15,7 @@ :justify-content :center}) (defstyle profile-name-text - {:padding-vertical 14 + {:padding-vertical 8 :font-size 15 :text-align :center :font-weight :bold @@ -24,7 +24,6 @@ (defstyle profile-three-words {:font-size 12 :text-align :center - :font-weight :bold :color colors/gray}) (defstyle profile-name-input-text @@ -59,6 +58,15 @@ :background-color colors/white :height 52}) +(def settings-item-icon + {:background-color colors/blue-light + :width 34 + :height 34 + :border-radius 34 + :margin-right 16 + :justify-content :center + :align-items :center}) + (def settings-item-text-wrapper {:flex 1 :flex-direction :row diff --git a/src/status_im/ui/screens/profile/components/views.cljs b/src/status_im/ui/screens/profile/components/views.cljs index d731597cdf..bd59fb4577 100644 --- a/src/status_im/ui/screens/profile/components/views.cljs +++ b/src/status_im/ui/screens/profile/components/views.cljs @@ -74,7 +74,7 @@ (defn settings-item [{:keys [item-text label-kw value action-fn active? destructive? hide-arrow? - accessibility-label icon-content] + accessibility-label icon icon-content] :or {value "" active? true}}] [react/touchable-highlight (cond-> {:on-press action-fn @@ -82,10 +82,17 @@ accessibility-label (assoc :accessibility-label accessibility-label)) [react/view styles/settings-item + (when icon + [react/view styles/settings-item-icon + [vector-icons/icon icon {:color colors/blue}]]) [react/view styles/settings-item-text-wrapper - [react/text {:style (merge styles/settings-item-text - (when destructive? styles/settings-item-destructive) - (when-not active? styles/settings-item-disabled)) + [react/text {:style (merge styles/settings-item-text + (when destructive? + styles/settings-item-destructive) + (when-not active? + styles/settings-item-disabled) + (when icon + {:font-size 17})) :number-of-lines 1} (or item-text (i18n/label label-kw))] (when-not (string/blank? value) @@ -98,7 +105,9 @@ (when (and active? (not hide-arrow?)) [vector-icons/icon :icons/forward {:color colors/gray}]))]]) -(defn settings-switch-item [{:keys [label-kw value action-fn active?] :or {active? true}}] +(defn settings-switch-item + [{:keys [label-kw value action-fn active?] + :or {active? true}}] [react/view styles/settings-item [react/view styles/settings-item-text-wrapper [react/i18n-text {:style styles/settings-item-text :key label-kw}]] diff --git a/src/status_im/ui/screens/profile/contact/styles.cljs b/src/status_im/ui/screens/profile/contact/styles.cljs index 13242bce1d..5f88c40a3c 100644 --- a/src/status_im/ui/screens/profile/contact/styles.cljs +++ b/src/status_im/ui/screens/profile/contact/styles.cljs @@ -29,8 +29,7 @@ :color colors/black}}) (def action-container - {:background-color colors/white - :padding-top 24}) + {:background-color colors/white}) (def action {:background-color (colors/alpha colors/blue 0.1) @@ -47,6 +46,16 @@ (def action-icon-opts {:color colors/blue}) +(def block-action + {:background-color (colors/alpha colors/red 0.1) + :border-radius 50}) + +(def block-action-label + {:color colors/red}) + +(def block-action-icon-opts + {:color colors/red}) + (def profile-setting-text-empty (merge profile-setting-text {:color colors/gray})) diff --git a/src/status_im/ui/screens/profile/contact/views.cljs b/src/status_im/ui/screens/profile/contact/views.cljs index 966c81d36a..fc1c01a7fc 100644 --- a/src/status_im/ui/screens/profile/contact/views.cljs +++ b/src/status_im/ui/screens/profile/contact/views.cljs @@ -16,27 +16,26 @@ toolbar/default-nav-back [toolbar/content-title ""]]) -(defn actions [{:keys [pending? public-key dapp?]}] +(defn actions [{:keys [pending? public-key]}] (concat (if (or (nil? pending?) pending?) [{:label (i18n/label :t/add-to-contacts) :icon :icons/add-contact :action #(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key]) :accessibility-label :add-to-contacts-button}] [{:label (i18n/label :t/in-contacts) - :icon :icons/in-contacts + :icon :main-icons/in-contacts :disabled? true :accessibility-label :in-contacts-button}]) [{:label (i18n/label :t/send-message) - :icon :icons/chats + :icon :main-icons/message :action #(re-frame/dispatch [:contact.ui/send-message-pressed {:public-key public-key}]) - :accessibility-label :start-conversation-button}] - (when-not dapp? - [{:label (i18n/label :t/send-transaction) - :icon :icons/arrow-right - :action #(re-frame/dispatch [:profile/send-transaction public-key]) - :accessibility-label :send-transaction-button}]) - [{:label (i18n/label :t/share-profile-link) - :icon :icons/share + :accessibility-label :start-conversation-button} + {:label (i18n/label :t/send-transaction) + :icon :main-icons/send + :action #(re-frame/dispatch [:profile/send-transaction public-key]) + :accessibility-label :send-transaction-button} + {:label (i18n/label :t/share-profile-link) + :icon :main-icons/share :action #(re-frame/dispatch [:profile/share-profile-link public-key]) :accessibility-label :share-profile-link}])) @@ -61,6 +60,22 @@ [react/view [profile-info-contact-code-item public-key]]) +(defn block-contact-action [{:keys [blocked? public-key]}] + [list/render-action + {:label (if blocked? + (i18n/label :t/unblock-contact) + (i18n/label :t/block-contact)) + :icon :main-icons/cancel + :action (if blocked? + #(re-frame/dispatch [:contact.ui/unblock-contact-pressed public-key]) + #(re-frame/dispatch [:contact.ui/block-contact-pressed public-key])) + :accessibility-label (if blocked? + :unblock-contact + :block-contact)} + {:action-style styles/block-action + :action-label-style styles/block-action-label + :icon-opts styles/block-action-icon-opts}]) + (defview profile [] (letsubs [identity [:contacts/current-contact-identity] maybe-contact [:contacts/current-contact]] @@ -80,5 +95,7 @@ :action-label-style styles/action-label :action-separator-style styles/action-separator :icon-opts styles/action-icon-opts}] + [react/view {:style {:height 16}}] + [block-contact-action contact] [react/view styles/contact-profile-info-container [profile-info contact]]]]))) diff --git a/src/status_im/ui/screens/profile/group_chat/views.cljs b/src/status_im/ui/screens/profile/group_chat/views.cljs index 702e37924e..14e83ac4a8 100644 --- a/src/status_im/ui/screens/profile/group_chat/views.cljs +++ b/src/status_im/ui/screens/profile/group_chat/views.cljs @@ -42,7 +42,7 @@ (concat (when allow-adding-members? [{:label (i18n/label :add-members) - :icon :icons/add + :icon :main-icons/add :action #(re-frame/dispatch [:navigate-to :add-participants-toggle-list])}]) [{:label (i18n/label :t/clear-history) :icon :icons/close diff --git a/src/status_im/ui/screens/profile/user/views.cljs b/src/status_im/ui/screens/profile/user/views.cljs index 88b6e4e45c..4c364c6579 100644 --- a/src/status_im/ui/screens/profile/user/views.cljs +++ b/src/status_im/ui/screens/profile/user/views.cljs @@ -2,6 +2,7 @@ (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [re-frame.core :as re-frame] [reagent.core :as reagent] + [status-im.ui.components.list.views :as list.views] [status-im.i18n :as i18n] [status-im.ui.components.action-button.styles :as action-button.styles] [status-im.ui.components.button.view :as button] @@ -77,7 +78,7 @@ [button/button-with-icon {:on-press #(list-selection/open-share {:message link}) :label (i18n/label :t/share-link) - :icon :icons/share + :icon :main-icons/share :accessibility-label :share-my-contact-code-button :style styles/share-link-button}])) @@ -125,6 +126,7 @@ (when show-backup-seed? [profile.components/settings-item {:label-kw :t/backup-your-recovery-phrase + :accessibility-label :back-up-recovery-phrase-button :action-fn #(re-frame/dispatch [:navigate-to :backup-seed]) :icon-content [components.common/counter {:size 22} 1]}]) [profile.components/settings-item-separator] @@ -228,13 +230,33 @@ (when advanced? [advanced-settings params on-show])])) +(defn share-profile-item + [{:keys [public-key photo-path] :as current-account}] + [list.views/big-list-item + {:text (i18n/label :t/share-my-profile) + :icon :main-icons/share + :accessibility-label :share-my-profile-button + :action-fn #(re-frame/dispatch [:navigate-to :profile-qr-viewer + {:contact current-account + :source :public-key + :value public-key}])}]) + +(defn contacts-list-item [active-contacts-count] + [list.views/big-list-item + {:text (i18n/label :t/contacts) + :icon :main-icons/in-contacts + :accessibility-label :notifications-button + :accessory-value active-contacts-count + :action-fn #(re-frame/dispatch [:navigate-to :contacts-list])}]) + (defview my-profile [] (letsubs [{:keys [public-key photo-path] :as current-account} [:account/account] editing? [:get :my-profile/editing?] changed-account [:get :my-profile/profile] currency [:wallet/currency] login-data [:get :accounts/login] - scroll (reagent/atom nil)] + scroll (reagent/atom nil) + active-contacts-count [:contacts/active-count]] (let [shown-account (merge current-account changed-account) ;; We scroll on the component once rendered. setTimeout is necessary, ;; likely to allow the animation to finish. @@ -262,15 +284,8 @@ (profile-icon-options-ext) profile-icon-options) :on-change-text-event :my-profile/update-name}]] - [react/view (merge action-button.styles/actions-list - styles/share-contact-code-container) - [button/secondary-button {:on-press #(re-frame/dispatch [:navigate-to :profile-qr-viewer - {:contact (dissoc current-account :mnemonic) - :source :public-key - :value public-key}]) - :style styles/share-contact-code-button - :accessibility-label :share-my-profile-button} - (i18n/label :t/share-my-profile)]] + [share-profile-item (dissoc current-account :mnemonic)] + [contacts-list-item active-contacts-count] [react/view styles/my-profile-info-container [my-profile-settings current-account shown-account currency (nil? login-data)]] (when (nil? login-data) diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 40b5b2c2f6..12dca21040 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -39,6 +39,7 @@ [status-im.ui.screens.wallet.transactions.views :as wallet-transactions] [status-im.ui.screens.wallet.transaction-sent.views :refer [transaction-sent transaction-sent-modal]] [status-im.ui.screens.wallet.components.views :refer [contact-code recent-recipients recipient-qr-code]] + [status-im.ui.screens.contacts-list.views :refer [contacts-list blocked-users-list]] [status-im.ui.screens.network-settings.views :refer [network-settings]] [status-im.ui.screens.network-settings.network-details.views :refer [network-details]] [status-im.ui.screens.network-settings.edit-network.views :refer [edit-network]] @@ -310,6 +311,8 @@ (nav-reagent/stack-navigator (stack-screens (cond-> {:my-profile (main-tabs/get-main-tab :my-profile) + :contacts-list contacts-list + :blocked-users-list blocked-users-list :profile-photo-capture profile-photo-capture :about-app about-app/about-app :bootnodes-settings bootnodes-settings diff --git a/src/status_im/ui/screens/wallet/request/views.cljs b/src/status_im/ui/screens/wallet/request/views.cljs index 3a1e5c727d..772e463bc7 100644 --- a/src/status_im/ui/screens/wallet/request/views.cljs +++ b/src/status_im/ui/screens/wallet/request/views.cljs @@ -80,7 +80,7 @@ [wallet.components/toolbar {} wallet.components/default-action (i18n/label :t/receive) - [toolbar/actions [{:icon :icons/share + [toolbar/actions [{:icon :main-icons/share :icon-opts {:color :white :accessibility-label :share-button} :handler #(list-selection/open-share {:message address-hex})}]]] diff --git a/test/appium/tests/atomic/chats/test_chats_management.py b/test/appium/tests/atomic/chats/test_chats_management.py index 0027948cad..e20c8ef1ea 100644 --- a/test/appium/tests/atomic/chats/test_chats_management.py +++ b/test/appium/tests/atomic/chats/test_chats_management.py @@ -175,11 +175,14 @@ class TestChatManagementMultipleDevice(MultipleDeviceTestCase): chat_element.find_element() username = chat_element.username.text chat_element.member_photo.click() - for element in [chat_1.contact_profile_picture, chat_1.add_to_contacts, chat_1.profile_send_message, - chat_1.profile_send_transaction, chat_1.profile_address_text, + for element in [chat_1.contact_profile_picture, + chat_1.add_to_contacts, + chat_1.profile_send_message, + chat_1.profile_send_transaction, + chat_1.profile_address_text, chat_1.element_by_text(username, 'text')]: - if not element.is_element_displayed(): - self.errors.append('%s is not visible' % 'user name' if 'Base' in element.name else element.name) + if not element.scroll_to_element(): + self.errors.append('%s is not visible' % element.name) chat_1.add_to_contacts.click() if not chat_1.element_by_text('In contacts').is_element_displayed(): self.errors.append("'Add to contacts' is not changed to 'In contacts'") diff --git a/test/appium/views/profile_view.py b/test/appium/views/profile_view.py index 4419be62d5..3b3f092f65 100644 --- a/test/appium/views/profile_view.py +++ b/test/appium/views/profile_view.py @@ -181,6 +181,11 @@ class BackupRecoveryPhraseButton(BaseButton): super(BackupRecoveryPhraseButton, self).__init__(driver) self.locator = self.Locator.text_selector('Backup your recovery phrase') + def click(self): + self.scroll_to_element().click() + self.driver.info('Tap on %s' % self.name) + return self.navigate() + class OkContinueButton(BaseButton): diff --git a/translations/en.json b/translations/en.json index ee598d96aa..5826b5d029 100644 --- a/translations/en.json +++ b/translations/en.json @@ -876,6 +876,12 @@ "share-chat": "Share chat", "share-link": "Share link", "share-profile-link": "Share profile link", + "add-contact": "Add contact", + "blocked-users": "Blocked users", + "block-contact": "Block contact", + "unblock-contact": "Unblock contact", + "to-block": "Block", + "block-contact-details": "Blocking will delete all of this user previous messages and stop new ones from reaching you", "share-public-chat-text": "Check out this public chat on the Status app: {{link}}", "share-dapp-text": "Check out this DApp I'm using on Status: {{link}}", "network-invalid-url": "Network URL is invalid",