refactor contact models

- move models.contact and models.contacts to contact.core
- add tags field to contact and chat

Signed-off-by: yenda <eric@status.im>
This commit is contained in:
yenda 2018-10-11 10:38:23 +02:00
parent aaa8530f5a
commit 1a2fcdfe3a
No known key found for this signature in database
GPG Key ID: 0095623C0069DCE6
31 changed files with 290 additions and 510 deletions

View File

@ -1,10 +1,29 @@
(ns status-im.models.contact
(ns status-im.contact.core
(:require [status-im.data-store.contacts :as contacts-store]
[status-im.transport.message.protocol :as protocol]
[status-im.transport.message.contact :as message.contact]
[status-im.utils.contacts :as utils.contacts]
[status-im.utils.fx :as fx]
[re-frame.core :as re-frame]
[status-im.chat.models :as chat.models]
[status-im.i18n :as i18n]
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.js-resources :as js-res]
[status-im.utils.utils :as utils]
[status-im.utils.fx :as fx]))
(re-frame/reg-cofx
:get-default-contacts
(fn [coeffects _]
(assoc coeffects :default-contacts js-res/default-contacts)))
(fx/defn load-contacts
[{:keys [db all-contacts]}]
(let [contacts-list (map #(vector (:whisper-identity %) %) all-contacts)
contacts (into {} contacts-list)]
{:db (update db :contacts/contacts #(merge contacts %))}))
(defn can-add-to-contacts? [{:keys [pending? dapp?]}]
(and (not dapp?)
(or pending?
@ -48,6 +67,20 @@
(add-new-contact contact)
(send-contact-request contact))))
(fx/defn add-contact-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)]
{: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
"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)]
{:db (assoc-in db [:contacts/contacts whisper-id :tags] tags)
:data-store/tx [(contacts-store/remove-contact-tag-tx whisper-id tag)]}))
(defn handle-contact-update
[public-key
timestamp
@ -92,3 +125,40 @@
(def receive-contact-request handle-contact-update)
(def receive-contact-request-confirmation handle-contact-update)
(def receive-contact-update handle-contact-update)
(fx/defn add-contact-and-open-chat
[cofx whisper-id]
(fx/merge cofx
(add-contact whisper-id)
(chat.models/start-chat whisper-id {:navigation-reset? true})))
(fx/defn hide-contact
[{:keys [db]} whisper-id]
(when (get-in db [:contacts/contacts whisper-id])
{:db (assoc-in db [:contacts/contacts whisper-id :hide-contact?] true)}))
(fx/defn handle-qr-code
[{:keys [db] :as cofx} contact-identity]
(let [current-account (:account/account db)
fx {:db (assoc db :contacts/new-identity contact-identity)}
validation-result (new-chat.db/validate-pub-key db contact-identity)]
(if (some? validation-result)
{:utils/show-popup {:title (i18n/label :t/unable-to-read-this-code)
:content validation-result
:on-dismiss #(re-frame/dispatch [:navigate-to-clean :home])}}
(fx/merge cofx
fx
(add-contact-and-open-chat contact-identity)))))
(fx/defn open-contact-toggle-list
[{:keys [db :as cofx]}]
(fx/merge cofx
{:db (assoc db
:group/selected-contacts #{}
:new-chat-name "")}
(navigation/navigate-to-cofx :contact-toggle-list nil)))
(fx/defn add-new-identity-to-contacts
[{{:contacts/keys [new-identity]} :db :as cofx}]
(when (seq new-identity)
(add-contact-and-open-chat cofx new-identity)))

View File

@ -1,4 +1,4 @@
(ns status-im.ui.screens.contacts.db
(ns status-im.contact.db
(:require-macros [status-im.utils.db :refer [allowed-keys]])
(:require [cljs.spec.alpha :as spec]
status-im.utils.db))
@ -7,7 +7,7 @@
;;Contact
;we can't validate public key, because for dapps whisper-identity is just string
;;we can't validate public key, because for dapps whisper-identity is just string
(spec/def :contact/whisper-identity :global/not-empty-string)
(spec/def :contact/name :global/not-empty-string)
(spec/def :contact/address (spec/nilable :global/address))
@ -32,8 +32,9 @@
(spec/def :contact/jail-loaded? (spec/nilable boolean?))
(spec/def :contact/jail-loaded-events (spec/nilable seq?))
(spec/def :contact/subscriptions (spec/nilable map?))
;true when contact added using status-dev-cli
;;true when contact added using status-dev-cli
(spec/def :contact/debug? boolean?)
(spec/def :contact/tags (spec/coll-of string? :kind set?))
(spec/def :contact/contact
(allowed-keys
@ -59,7 +60,8 @@
:contact/debug?
:contact/subscriptions
:contact/fcm-token
:contact/description]))
:contact/description
:contact/tags]))
;;Contact list ui props
(spec/def :contact-list-ui/edit? boolean?)
@ -68,16 +70,16 @@
(spec/def :contacts-ui/edit? boolean?)
(spec/def :contacts/contacts (spec/nilable (spec/map-of :global/not-empty-string :contact/contact)))
;public key of new contact during adding this new contact
;;public key of new contact during adding this new contact
(spec/def :contacts/new-identity (spec/nilable string?))
(spec/def :contacts/new-identity-error (spec/nilable string?))
;on showing this contact's profile (andrey: better to move into profile ns)
;;on showing this contact's profile (andrey: better to move into profile ns)
(spec/def :contacts/identity (spec/nilable :global/not-empty-string))
(spec/def :contacts/list-ui-props (spec/nilable (allowed-keys :opt-un [:contact-list-ui/edit?])))
(spec/def :contacts/ui-props (spec/nilable (allowed-keys :opt-un [:contacts-ui/edit?])))
;used in modal list (for example for wallet)
;;used in modal list (for example for wallet)
(spec/def :contacts/click-handler (spec/nilable fn?))
;used in modal list (for example for wallet)
;;used in modal list (for example for wallet)
(spec/def :contacts/click-action (spec/nilable #{:send :request}))
;used in modal list (for example for wallet)
;;used in modal list (for example for wallet)
(spec/def :contacts/click-params (spec/nilable map?))

View File

@ -1,4 +1,4 @@
(ns status-im.ui.screens.contacts.subs
(ns status-im.contact.subs
(:require [re-frame.core :refer [reg-sub subscribe]]
[status-im.utils.contacts :as utils.contacts]
[status-im.utils.ethereum.core :as ethereum]

View File

@ -57,6 +57,7 @@
(-> chat
(update :admins #(into #{} %))
(update :contacts #(into #{} %))
(update :tags #(into #{} %))
(update :membership-updates (partial unmarshal-membership-updates chat-id))
;; We cap the clock value to a safe value in case the db has been polluted
(assoc :last-clock-value (get-last-clock-value chat-id))))
@ -126,3 +127,23 @@
(aset chat "contacts"
(clj->js (remove (into #{} contacts)
(core/list->clj existing-contacts)))))))
(defn add-chat-tag-tx
"Returns tx function for adding chat contacts"
[chat-id tag]
(fn [realm]
(let [chat (get-chat-by-id chat-id realm)
existing-tags (object/get chat "tags")]
(aset chat "tags"
(clj->js (into #{} (concat tag
(core/list->clj existing-tags))))))))
(defn remove-chat-tag-tx
"Returns tx function for removing chat contacts"
[chat-id tag]
(fn [realm]
(let [chat (get-chat-by-id chat-id realm)
existing-tags (object/get chat "tags")]
(aset chat "tags"
(clj->js (remove (into #{} tag)
(core/list->clj existing-tags)))))))

View File

@ -1,13 +1,19 @@
(ns status-im.data-store.contacts
(:require [re-frame.core :as re-frame]
(:require [goog.object :as object]
[re-frame.core :as re-frame]
[status-im.data-store.realm.core :as core]))
(defn- normalize-contact [contact]
(-> contact
(update :tags #(into #{} %))))
(re-frame/reg-cofx
:data-store/get-all-contacts
(fn [coeffects _]
(assoc coeffects :all-contacts (-> @core/account-realm
(core/get-all :contact)
(core/all-clj :contact)))))
(assoc coeffects :all-contacts (map normalize-contact
(-> @core/account-realm
(core/get-all :contact)
(core/all-clj :contact))))))
(defn save-contact-tx
"Returns tx function for saving contact"
@ -25,8 +31,31 @@
(doseq [contact contacts]
((save-contact-tx contact) realm))))
(defn- get-contact-by-id [whisper-identity realm]
(core/single (core/get-by-field realm :contact :whisper-identity whisper-identity)))
(defn delete-contact-tx
"Returns tx function for deleting contact"
[whisper-identity]
(fn [realm]
(core/delete realm (core/single (core/get-by-field realm :contact :whisper-identity whisper-identity)))))
(core/delete realm (get-contact-by-id whisper-identity realm))))
(defn add-contact-tag-tx
"Returns tx function for adding chat contacts"
[whisper-identity tag]
(fn [realm]
(let [contact (get-contact-by-id whisper-identity realm)
existing-tags (object/get contact "tags")]
(aset contact "tags"
(clj->js (into #{} (concat tag
(core/list->clj existing-tags))))))))
(defn remove-contact-tag-tx
"Returns tx function for removing chat contacts"
[whisper-identity tag]
(fn [realm]
(let [contact (get-contact-by-id whisper-identity realm)
existing-tags (object/get contact "tags")]
(aset contact "tags"
(clj->js (remove (into #{} tag)
(core/list->clj existing-tags)))))))

View File

@ -157,3 +157,35 @@
:default false}
:public? {:type :bool
:default false}}})
(def v8 {:name :chat
:primaryKey :chat-id
:properties {:chat-id :string
:name :string
:color {:type :string
:default colors/default-chat-color}
:group-chat {:type :bool
:indexed true}
:is-active :bool
:timestamp :int
:contacts {:type "string[]"}
:admins {:type "string[]"}
:membership-updates {:type :list
:objectType :membership-update}
:removed-at {:type :int
:optional true}
:removed-from-at {:type :int
:optional true}
:deleted-at-clock-value {:type :int
:optional true}
:added-to-at {:type :int
:optional true}
:updated-at {:type :int
:optional true}
:message-overhead {:type :int
:default 0}
:debug? {:type :bool
:default false}
:public? {:type :bool
:default false}
:tags {:type "string[]"}}})

View File

@ -25,3 +25,30 @@
:optional true}
:debug? {:type :bool
:default false}}})
(def v2 {:name :contact
:primaryKey :whisper-identity
:properties {:address {:type :string :optional true}
:whisper-identity :string
:name {:type :string :optional true}
:photo-path {:type :string :optional true}
:last-updated {:type :int :default 0}
:last-online {:type :int :default 0}
:pending? {:type :bool :default false}
:hide-contact? {:type :bool :default false}
:status {:type :string :optional true}
:fcm-token {:type :string :optional true}
:description {:type :string :optional true}
:public-key {:type :string
:optional true}
:dapp? {:type :bool
:default false}
:dapp-url {:type :string
:optional true}
:bot-url {:type :string
:optional true}
:dapp-hash {:type :int
:optional true}
:debug? {:type :bool
:default false}
:tags {:type "string[]"}}})

View File

@ -169,6 +169,18 @@
browser/v8
dapp-permissions/v9])
(def v17 [chat/v8
transport/v7
transport-inbox-topic/v1
contact/v2
message/v7
mailserver/v11
user-status/v1
membership-update/v1
local-storage/v1
browser/v8
dapp-permissions/v9])
;; put schemas ordered by version
(def schemas [{:schema v1
:schemaVersion 1
@ -217,4 +229,7 @@
:migration migrations/v15}
{:schema v16
:schemaVersion 16
:migration migrations/v16}])
:migration migrations/v16}
{:schema v17
:schemaVersion 17
:migration migrations/v17}])

View File

@ -100,3 +100,6 @@
(defn v16 [old-realm new-realm]
(log/debug "migrating v16 account database"))
(defn v17 [old-realm new-realm]
(log/debug "migrating v17 account database"))

View File

@ -14,6 +14,7 @@
[status-im.chat.models.input :as chat.input]
[status-im.chat.models.loading :as chat.loading]
[status-im.chat.models.message :as chat.message]
[status-im.contact.core :as contact]
[status-im.data-store.core :as data-store]
[status-im.fleet.core :as fleet]
[status-im.group-chats.core :as group-chats]
@ -1003,3 +1004,39 @@
:transport/contact-message-sent
(fn [cofx [_ chat-id envelope-hash]]
(transport.message/set-contact-message-envelope-hash cofx chat-id envelope-hash)))
;; contact module
(handlers/register-handler-fx
:contact.ui/add-to-contact-pressed
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx [_ whisper-id]]
(contact/add-contact cofx whisper-id)))
(handlers/register-handler-fx
:contact.ui/close-contact-pressed
(fn [cofx [_ whisper-id]]
(contact/hide-contact cofx whisper-id)))
(handlers/register-handler-fx
:contact/qr-code-scanned
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx [_ _ contact-identity]]
(contact/handle-qr-code cofx contact-identity)))
(handlers/register-handler-fx
:contact.ui/start-group-chat-pressed
(fn [{:keys [db] :as cofx} _]
(contact/open-contact-toggle-list cofx)))
(handlers/register-handler-fx
:contact.ui/send-message-pressed
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx [_ {:keys [whisper-identity]}]]
(contact/add-contact-and-open-chat cofx whisper-identity)))
(handlers/register-handler-fx
:contact.ui/contact-code-submitted
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx _]
(contact/add-new-identity-to-contacts cofx)))

View File

@ -8,7 +8,7 @@
[status-im.data-store.realm.core :as realm]
[status-im.i18n :as i18n]
[status-im.browser.core :as browser]
[status-im.models.contacts :as models.contacts]
[status-im.contact.core :as contact]
[status-im.models.dev-server :as models.dev-server]
[status-im.protocol.core :as protocol]
[status-im.models.transactions :as transactions]
@ -16,7 +16,6 @@
[status-im.native-module.core :as status]
[status-im.node.core :as node]
[status-im.notifications.core :as notifications]
[status-im.ui.screens.contacts.events :as contacts]
[status-im.ui.screens.db :refer [app-db]]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.config :as config]
@ -198,7 +197,7 @@
:notifications/get-fcm-token nil}
(initialize-account-db address)
(protocol/initialize-protocol address)
(models.contacts/load-contacts)
(contact/load-contacts)
#(when (dev-mode? %)
(models.dev-server/start))
(chat-loading/initialize-chats)

View File

@ -1,8 +0,0 @@
(ns status-im.models.contacts
(:require [status-im.utils.fx :as fx]))
(fx/defn load-contacts
[{:keys [db all-contacts]}]
(let [contacts-list (map #(vector (:whisper-identity %) %) all-contacts)
contacts (into {} contacts-list)]
{:db (update db :contacts/contacts #(merge contacts %))}))

View File

@ -2,7 +2,7 @@
status-im.transport.db
(:require [cljs.spec.alpha :as spec]
[clojure.string :as s]
status-im.ui.screens.contacts.db
status-im.contact.db
[status-im.utils.clocks :as utils.clocks])
(:require-macros [status-im.utils.db :refer [allowed-keys]]))

View File

@ -1,6 +1,6 @@
(ns status-im.transport.impl.receive
(:require [status-im.group-chats.core :as group-chats]
[status-im.models.contact :as models.contact]
[status-im.contact.core :as contact]
[status-im.transport.message.contact :as transport.contact]
[status-im.transport.message.group-chat :as transport.group-chat]
[status-im.transport.message.protocol :as protocol]))
@ -13,14 +13,14 @@
(extend-type transport.contact/ContactRequest
protocol/StatusMessage
(receive [this _ signature timestamp cofx]
(models.contact/receive-contact-request signature timestamp this cofx)))
(contact/receive-contact-request signature timestamp this cofx)))
(extend-type transport.contact/ContactRequestConfirmed
protocol/StatusMessage
(receive [this _ signature timestamp cofx]
(models.contact/receive-contact-request-confirmation signature timestamp this cofx)))
(contact/receive-contact-request-confirmation signature timestamp this cofx)))
(extend-type transport.contact/ContactUpdate
protocol/StatusMessage
(receive [this _ signature timestamp cofx]
(models.contact/receive-contact-update signature timestamp this cofx)))
(contact/receive-contact-update signature timestamp this cofx)))

View File

@ -1,5 +1,5 @@
(ns status-im.ui.screens.add-new.db
(:require [cljs.spec.alpha :as spec]
status-im.ui.screens.contacts.db))
status-im.contact.db))
(spec/def :new/open-dapp (spec/nilable :contact/contact))
(spec/def :new/open-dapp (spec/nilable :contact/contact))

View File

@ -28,14 +28,14 @@
[react/view add-new.styles/new-chat-input-container
[react/text-input {:on-change-text #(re-frame/dispatch [:new-chat/set-new-identity %])
:on-submit-editing #(when-not error-message
(re-frame/dispatch [:add-contact-handler]))
(re-frame/dispatch [:contact.ui/contact-code-submitted]))
:placeholder (i18n/label :t/enter-contact-code)
:style add-new.styles/input
:accessibility-label :enter-contact-code-input
:return-key-type :go}]]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:qr-scanner.ui/scan-qr-code-pressed
{:toolbar-title (i18n/label :t/new-contact)}
:set-contact-identity-from-qr])
:contact/qr-code-scanned])
:style add-new.styles/button-container
:accessibility-label :scan-contact-code-button}
[react/view

View File

@ -29,7 +29,7 @@
:accessibility-label :start-group-chat-button
:icon :icons/contacts
:icon-opts {:color colors/blue}
:on-press #(re-frame/dispatch [:open-contact-toggle-list])}])
:on-press #(re-frame/dispatch [:contact.ui/start-group-chat-pressed])}])
(when config/group-chats-enabled?
[action-button/action-separator])
[action-button/action-button

View File

@ -1,5 +1,6 @@
(ns status-im.ui.screens.browser.default-dapps
(:require [status-im.i18n :as i18n]))
(:require [re-frame.core :as re-frame]
[status-im.i18n :as i18n]))
(def all
[{:title (i18n/label :t/default-dapps-exchanges)
@ -140,3 +141,8 @@
:dapp-url "https://status-im.github.io/dapp/"
:description "Request test assets and test basic web3 functionality."
:developer? true}]}])
(re-frame/reg-cofx
:get-default-dapps
(fn [coeffects _]
(assoc coeffects :default-dapps all)))

View File

@ -3,7 +3,7 @@
(:require [clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.i18n :as i18n]
[status-im.models.contact :as models.contact]
[status-im.contact.core :as models.contact]
[status-im.ui.screens.chat.styles.main :as style]
[status-im.utils.platform :as platform]
[status-im.ui.screens.chat.input.input :as input]
@ -32,13 +32,13 @@
[react/view style/add-contact
[react/view style/add-contact-left]
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:add-contact contact-identity])
{: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}]
[react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]]
[react/touchable-highlight
{:on-press #(re-frame/dispatch [:hide-contact contact-identity])
{:on-press #(re-frame/dispatch [:contacts.ui/close-contact-pressed contact-identity])
:accessibility-label :add-to-contacts-close-button}
[vector-icons/icon :icons/close {:color colors/black
:container-style style/add-contact-close-icon}]]])))

View File

@ -1,75 +0,0 @@
(ns status-im.ui.screens.contacts.events
(:require [re-frame.core :as re-frame]
[status-im.chat.models :as chat.models]
[status-im.i18n :as i18n]
[status-im.models.contact :as models.contact]
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
[status-im.ui.screens.browser.default-dapps :as default-dapps]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.handlers :as handlers]
[status-im.utils.js-resources :as js-res]
[status-im.utils.utils :as utils]
[status-im.utils.fx :as fx]))
(fx/defn add-contact-and-open-chat
[cofx whisper-id]
(fx/merge cofx
(models.contact/add-contact whisper-id)
(chat.models/start-chat whisper-id {:navigation-reset? true})))
(re-frame/reg-cofx
:get-default-contacts
(fn [coeffects _]
(assoc coeffects :default-contacts js-res/default-contacts)))
(re-frame/reg-cofx
:get-default-dapps
(fn [coeffects _]
(assoc coeffects :default-dapps default-dapps/all)))
(handlers/register-handler-fx
:add-contact
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx [_ whisper-id]]
(models.contact/add-contact cofx whisper-id)))
(handlers/register-handler-fx
:hide-contact
(fn [{:keys [db]} [_ whisper-id]]
(when (get-in db [:contacts/contacts whisper-id])
{:db (assoc-in db [:contacts/contacts whisper-id :hide-contact?] true)})))
(handlers/register-handler-fx
:set-contact-identity-from-qr
[(re-frame/inject-cofx :random-id-generator)]
(fn [{:keys [db] :as cofx} [_ _ contact-identity]]
(let [current-account (:account/account db)
fx {:db (assoc db :contacts/new-identity contact-identity)}
validation-result (new-chat.db/validate-pub-key db contact-identity)]
(if (some? validation-result)
(utils/show-popup (i18n/label :t/unable-to-read-this-code) validation-result #(re-frame/dispatch [:navigate-to-clean :home]))
(fx/merge cofx
fx
(add-contact-and-open-chat contact-identity))))))
(handlers/register-handler-fx
:open-contact-toggle-list
(fn [{:keys [db] :as cofx} _]
(fx/merge cofx
{:db (assoc db
:group/selected-contacts #{}
:new-chat-name "")}
(navigation/navigate-to-cofx :contact-toggle-list nil))))
(handlers/register-handler-fx
:open-chat-with-contact
[(re-frame/inject-cofx :random-id-generator)]
(fn [cofx [_ {:keys [whisper-identity]}]]
(add-contact-and-open-chat cofx whisper-identity)))
(handlers/register-handler-fx
:add-contact-handler
[(re-frame/inject-cofx :random-id-generator)]
(fn [{{:contacts/keys [new-identity]} :db :as cofx} _]
(when (seq new-identity)
(add-contact-and-open-chat cofx new-identity))))

View File

@ -8,7 +8,7 @@
pluto.registry
status-im.transport.db
status-im.accounts.db
status-im.ui.screens.contacts.db
status-im.contact.db
status-im.ui.screens.qr-scanner.db
status-im.ui.screens.group.db
status-im.chat.specs

View File

@ -20,7 +20,7 @@
[react/text {:style styles/new-contact-title-text
:font :medium}
(i18n/label :new-group-chat)]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:open-contact-toggle-list])}
[react/touchable-highlight {:on-press #(re-frame/dispatch [:contact.ui/start-group-chat-pressed])}
[react/view
{:style (styles/add-contact-button nil)}
[react/text
@ -60,7 +60,7 @@
(string/blank? new-contact-identity))
show-error-tooltip? (and chat-error
(not (string/blank? new-contact-identity)))
create-1to1-chat #(re-frame/dispatch [:add-contact-handler new-contact-identity])]
create-1to1-chat #(re-frame/dispatch [:contact.ui/contact-code-submitted new-contact-identity])]
[react/view {:style styles/add-contact-edit-view}
[react/view {:flex 1
:style (styles/add-contact-input show-error-tooltip?)}
@ -90,7 +90,7 @@
^{:key (:whisper-identity c)}
[react/touchable-highlight {:on-press #(do
(re-frame/dispatch [:set :contacts/new-identity (:whisper-identity c)])
(re-frame/dispatch [:add-contact-handler (:whisper-identity c)]))}
(re-frame/dispatch [:contact.ui/contact-code-submitted (:whisper-identity c)]))}
[react/view {:style styles/suggested-contact-view}
[react/image {:style styles/suggested-contact-image
:source {:uri (:photo-path c)}}]

View File

@ -45,7 +45,7 @@
chat-name]
(cond pending?
[react/text {:style styles/add-contact-text
:on-press #(re-frame/dispatch [:add-contact whisper-identity])}
:on-press #(re-frame/dispatch [:contact.ui/add-to-contact-pressed whisper-identity])}
(i18n/label :t/add-to-contacts)]
public?
[react/text {:style styles/public-chat-text}
@ -357,10 +357,10 @@
{:keys [pending? whisper-identity public-key]} contact]
[react/view {:style styles/chat-profile-body}
[profile.views/profile-badge contact]
;; for private chat, public key will be chat-id
;; for private chat, public key will be chat-id
[react/view
(if (or (nil? pending?) pending?)
[react/touchable-highlight {:on-press #(re-frame/dispatch [:add-contact whisper-identity])}
[react/touchable-highlight {:on-press #(re-frame/dispatch [:contact.ui/add-to-contact-pressed whisper-identity])}
[react/view {:style styles/chat-profile-row}
[react/view {:style styles/chat-profile-icon-container
:accessibility-label :add-contact-link}
@ -373,7 +373,7 @@
[react/text {:style (styles/contact-card-text colors/gray)} (i18n/label :t/in-contacts)]])
[react/touchable-highlight
{:on-press #(re-frame/dispatch
[:open-chat-with-contact {:whisper-identity whisper-identity}])}
[:contact.ui/send-message-pressed {:whisper-identity whisper-identity}])}
[react/view {:style styles/chat-profile-row}
[react/view {:style styles/chat-profile-icon-container
:accessibility-label :send-message-link}

View File

@ -20,7 +20,7 @@
(concat (if (or (nil? pending?) pending?)
[{:label (i18n/label :t/add-to-contacts)
:icon :icons/add-contact
:action #(re-frame/dispatch [:add-contact whisper-identity])
:action #(re-frame/dispatch [:contact.ui/add-to-contact-pressed whisper-identity])
:accessibility-label :add-to-contacts-button}]
[{:label (i18n/label :t/in-contacts)
:icon :icons/in-contacts
@ -28,7 +28,7 @@
:accessibility-label :in-contacts-button}])
[{:label (i18n/label :t/send-message)
:icon :icons/chats
:action #(re-frame/dispatch [:open-chat-with-contact {:whisper-identity whisper-identity}])
:action #(re-frame/dispatch [:contact.ui/send-message-pressed {:whisper-identity whisper-identity}])
:accessibility-label :start-conversation-button}]
(when-not dapp?
[{:label (i18n/label :t/send-transaction)

View File

@ -2,10 +2,10 @@
(:require [re-frame.core :refer [reg-sub subscribe]]
[status-im.utils.ethereum.core :as ethereum]
status-im.chat.subs
status-im.contact.subs
status-im.ui.screens.accounts.subs
status-im.ui.screens.extensions.subs
status-im.ui.screens.home.subs
status-im.ui.screens.contacts.subs
status-im.ui.screens.group.subs
status-im.ui.screens.wallet.subs
status-im.ui.screens.wallet.collectibles.subs

View File

@ -4,7 +4,6 @@
[re-frame.core :as rf]
[day8.re-frame.test :refer-macros [run-test-sync]]
status-im.ui.screens.db
[status-im.ui.screens.contacts.events :as contacts-events]
status-im.ui.screens.subs
[status-im.ui.screens.events :as events]
[status-im.utils.js-resources :as js-res]))
@ -58,379 +57,3 @@
:bot-url "local://console-bot"
:status "intro-status"
:pending? false})
(defn test-fixtures []
(rf/reg-fx ::events/init-store #())
(rf/reg-fx :data-store/save-all-contacts #())
(rf/reg-fx ::contacts-events/save-contact #())
(rf/reg-fx ::contacts-events/watch-contact #())
(rf/reg-fx ::contacts-events/stop-watching-contact #())
(rf/reg-fx ::contacts-events/send-contact-request-fx #())
(rf/reg-fx :data-store/save-chat #())
(rf/reg-cofx
:data-store/get-all-contacts
(fn [coeffects _]
(assoc coeffects :all-contacts [])))
(rf/reg-cofx
:data-store/get-local-storage-data
(fn [cofx]
(assoc cofx :get-local-storage-data (constantly nil))))
;;TODO implement tests later for :add-chat? and :bot-url
(rf/reg-cofx
::contacts-events/get-default-contacts-and-groups
(fn [coeffects _]
(assoc coeffects :default-contacts (select-keys js-res/default-contacts [:demo-bot])))))
#_(deftest contacts-events
"load-contacts
load-contact-groups
load-default-contacts (add-contact-groups, add-contacts, add-contacts-to-group ;TODO add-chat, load-commands!)
add-contact-handler (add-new-contact-and-open-chat, status-im.contacts.events/add-new-contact,
status-im.contacts.events/send-contact-request ;TODO start-chat)
contact-request-received (update-contact, watch-contact ;TODO :update-chat!)
contact-update-received (update-contact ;TODO :update-chat!)
hide-contact (update-contact ;TODO :account-update-keys)
add-contact-handler (add-contact, status-im.contacts.events/add-new-contact
status-im.contacts.events/send-contact-request ;TODO :discoveries-send-portions)
create-new-contact-group
set-contact-group-name
save-contact-group-order
add-selected-contacts-to-group
remove-contact-from-group
add-contacts-to-group
delete-contact-group"
(testing "watch-contact"
(let [contact {:public-key "public-key"
:whisper-identity "whisper-identity"}
actual-fx (-> {:db {:web3 "web3"}}
(contacts-events/watch-contact contact)
::contacts-events/watch-contact)]
(testing "it adds a ::watch-contact effect"
(is (not (nil? actual-fx))))
(testing "it adds web3"
(is (= "web3" (:web3 actual-fx))))
(testing "it adds the watched-contact whisper-identity"
(is (= "whisper-identity" (:whisper-identity actual-fx))))
(testing "it adds the public key"
(is (= "public-key" (:public-key actual-fx))))))
(testing "send-contact-request"
(let [contact {:whisper-identity "contact-whisper-identity"}
account {:name "name"
:photo-path "photo-path"
:status "status"}
accounts {"current-account-id" account}
db {:accounts/accounts accounts
:accounts/current-account-id "current-account-id"
:web3 "web3"
:current-public-key "current-public-key"
:notifications {:fcm-token "fcm-token"}}
actual-fx (-> {:db db}
(contacts-events/send-contact-request contact)
::contacts-events/send-contact-request-fx)]
(testing "it adds a ::send-contact-request-fx effect"
(is (not (nil? actual-fx))))
(testing "it adds the current-public-key"
(is (= "current-public-key" (:current-public-key actual-fx))))
(testing "it adds web3"
(is (= "web3" (:web3 actual-fx))))
(testing "it adds the current-account-id"
(is (= "current-account-id" (:current-account-id actual-fx))))
(testing "it adds the fcm-token"
(is (= "fcm-token" (:fcm-token actual-fx))))
(testing "it adds the whisper-identity of the contact"
(is (= "contact-whisper-identity" (:whisper-identity actual-fx))))
(testing "it adds the current-account information"
(is (= account (select-keys actual-fx [:name
:photo-path
:status]))))))
(run-test-sync
(test-fixtures)
(rf/dispatch [:initialize-db])
(def contacts (rf/subscribe [:get-contacts]))
(def contact-groups (rf/subscribe [:get-contact-groups]))
(def view-id (rf/subscribe [:get :view-id]))
(testing ":load-contacts event"
;;Assert the initial state
(is (and (map? @contacts) (empty? @contacts)))
(rf/dispatch [:load-contacts]))
(testing ":load-contact-groups event"
;;Assert the initial state
(is (and (map? @contact-groups) (empty? @contact-groups)))
(rf/dispatch [:load-contact-groups])
(is (= {(:group-id test-contact-group) test-contact-group}
@contact-groups)))
(testing ":load-default-contacts! event"
;; :load-default-contacts! event dispatches next 5 events
;;
;; :add-contact-groups
;; :add-contacts
;; :add-contacts-to-group
;;TODO :add-chat
;;TODO :load-commands!
(rf/dispatch [:load-default-contacts!])
(rf/dispatch [:set-in [:group/contact-groups "dapps" :timestamp] 0])
(is (= {"dapps" dapps-contact-group
(:group-id test-contact-group) test-contact-group}
@contact-groups))
(testing "it adds a default contact"
(is (= demo-bot-contact (get @contacts "demo-bot"))))
(testing "it adds the console bot"
(is (= console-contact (get @contacts "console"))))
(testing "it does not add any other contact"
(is (= 2 (count (keys @contacts))))))
(def new-contact-public-key "0x048f7d5d4bda298447bbb5b021a34832509bd1a8dbe4e06f9b7223d00a59b6dc14f6e142b21d3220ceb3155a6d8f40ec115cd96394d3cc7c55055b433a1758dc74")
(def new-contact-address "5392ccb49f2e9fef8b8068b3e3b5ba6c020a9aca")
(def new-contact {:name ""
:photo-path ""
:whisper-identity new-contact-public-key
:address new-contact-address
:pending? false})
(def contact (rf/subscribe [:contact-by-identity new-contact-public-key]))
(def current-chat-id (rf/subscribe [:get-current-chat-id]))
(testing ":add-contact-handler event - new contact"
(rf/dispatch [:set :view-id nil])
(rf/dispatch [:set :current-chat-id nil])
;; :add-contact-handler event dispatches next 4 events for new contact
;;
;; :add-new-contact-and-open-chat
;; :status-im.contacts.events/add-new-contact
;; :status-im.contacts.events/send-contact-request
;;TODO :start-chat
(rf/dispatch [:set :contacts/new-identity new-contact-public-key])
(rf/dispatch [:add-contact-handler])
(testing "it returns the new contact from the contact-by-identity sub"
(is (= new-contact (assoc @contact :photo-path "" :name ""))))
(testing "it adds the new contact to the list of contacts"
(is (= new-contact
(-> @contacts
(get new-contact-public-key)
(assoc :photo-path "" :name "")))))
(testing "it loads the 1-1 chat"
(is (= :chat @view-id)))
(testing "it adds the new contact to the chat"
(is (= new-contact-public-key @current-chat-id))))
(testing ":contact-request-received event"
;; :contact-request-received event dispatches next 3 events
;;
;; :update-contact!
;; :watch-contact
;;TODO :update-chat!
(rf/reg-event-db :update-chat! (fn [db _] db))
(def received-contact {:name "test"
:profile-image ""
:address new-contact-address
:status "test status"
:fcm-token "0xwhatever"})
(def received-contact1 (merge new-contact
(dissoc received-contact :profile-image)
{:public-key new-contact-public-key}))
(rf/dispatch [:contact-request-received {:from new-contact-public-key
:payload {:contact received-contact}}])
(testing "it adds the new contact to the list of contacts"
(is (= received-contact1
(get @contacts new-contact-public-key)))))
(testing ":contact-update-received event"
;; :contact-update-received event dispatches next 2 events
;;
;; :update-contact!
;;TODO :update-chat!
(let [timestamp (datetime/timestamp)]
(def received-contact2 (assoc received-contact1
:last-updated timestamp
:status "new status"
:name "new name"))
(rf/dispatch [:contact-update-received {:from new-contact-public-key
:payload {:content {:profile {:profile-image ""
:status "new status"
:name "new name"}}
:timestamp timestamp}}]))
(testing "it updates the contact and set the :last-updated key"
(is (= received-contact2
(get @contacts new-contact-public-key)))))
(testing ":hide-contact event"
;; :hide-contact event dispatches next 2 events
;;
;; :update-contact!
;;TODO :account-update-keys
(rf/reg-event-db :account-update-keys (fn [db _] db))
(rf/dispatch [:hide-contact @contact])
(testing "it sets the pending? flag to true"
(is (= (assoc received-contact2 :pending? true)
(get @contacts new-contact-public-key)))))
(testing ":add-contact-handler event - :add-contact"
;; :add-contact-handler event dispatches next 4 events
;;
;; :add-contact
;; :status-im.contacts.events/add-new-contact
;; :status-im.contacts.events/send-contact-request
;;TODO :discoveries-send-portions
(rf/reg-event-db :discoveries-send-portions (fn [db _] db))
(rf/dispatch [:set :view-id nil])
(rf/dispatch [:set :current-chat-id nil])
(rf/dispatch [:set :contacts/new-identity new-contact-public-key])
(rf/dispatch [:add-contact-handler])
(testing "it sets the pending? flag to false"
(is (= (assoc received-contact2 :pending? false)
(get @contacts new-contact-public-key))))
(testing "it loads the 1-1 chat"
(is (= :chat @view-id)))
(testing "it adds the new contact to the chat"
(is (= new-contact-public-key @current-chat-id))))
(testing ":create-new-contact-group event"
(def new-group-name "new group")
(rf/dispatch [:select-contact new-contact-public-key])
(rf/dispatch [:select-contact "demo-bot"])
(rf/dispatch [:select-contact "browse"])
(rf/dispatch [:deselect-contact "browse"])
(rf/dispatch [:create-new-contact-group new-group-name])
(rf/dispatch [:deselect-contact "demo-bot"])
(rf/dispatch [:deselect-contact new-contact-public-key])
(def new-group-id (->> @contact-groups
(vals)
(filter #(= (:name %) new-group-name))
(first)
(:group-id)))
(def new-group {:group-id new-group-id
:name new-group-name
:order 2
:timestamp 0
:contacts [{:identity new-contact-public-key}
{:identity "demo-bot"}]})
(def groups-with-new-group {new-group-id new-group
"dapps" dapps-contact-group
(:group-id test-contact-group) test-contact-group})
(def groups-with-new-group1 (update groups-with-new-group new-group-id assoc :name "new group name"))
(def groups-with-new-group2 (-> groups-with-new-group1
(update new-group-id assoc :order 1)
(update "dapps" assoc :order 2)))
(rf/dispatch [:set-in [:group/contact-groups new-group-id :timestamp] 0])
(is (= groups-with-new-group @contact-groups)))
(testing ":set-contact-group-name event"
(rf/reg-event-db ::prepare-group-name
(fn [db _] (assoc db
:new-chat-name "new group name"
:group/contact-group-id new-group-id)))
(rf/dispatch [::prepare-group-name])
(rf/dispatch [:set-contact-group-name])
(is (= groups-with-new-group1 @contact-groups)))
(testing ":save-contact-group-order event"
(rf/reg-event-db ::prepare-groups-order
(fn [db _]
(assoc db :group/groups-order
(->> (vals (:group/contact-groups db))
(remove :pending?)
(sort-by :order >)
(map :group-id)))))
(rf/dispatch [::prepare-groups-order])
(rf/dispatch [:change-contact-group-order 1 0])
(rf/dispatch [:save-contact-group-order])
(is (= groups-with-new-group2 @contact-groups)))
(testing ":add-selected-contacts-to-group event"
(rf/dispatch [:select-contact "browse"])
(rf/dispatch [:add-selected-contacts-to-group])
(rf/dispatch [:deselect-contact "browse"])
(is (= (update groups-with-new-group2 new-group-id assoc :contacts [{:identity new-contact-public-key}
{:identity "demo-bot"}
{:identity "browse"}])
@contact-groups)))
(testing ":remove-contact-from-group event"
(rf/dispatch [:remove-contact-from-group "browse" new-group-id])
(is (= groups-with-new-group2 @contact-groups)))
(testing ":add-contacts-to-group event"
(rf/dispatch [:add-contacts-to-group new-group-id ["browse"]])
(is (= (update groups-with-new-group2 new-group-id assoc :contacts [{:identity new-contact-public-key}
{:identity "demo-bot"}
{:identity "browse"}])
@contact-groups))
(rf/dispatch [:remove-contact-from-group "browse" new-group-id]))
(testing ":delete-contact-group event"
(rf/dispatch [:delete-contact-group])
(is (= (update groups-with-new-group2 new-group-id assoc :pending? true)
@contact-groups)))))

View File

@ -1,7 +1,7 @@
(ns status-im.test.contacts.subs
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.identicon :as identicon]
[status-im.ui.screens.contacts.subs :as contacts-subs]))
[status-im.contact.subs :as contacts-subs]))
(deftest contacts-subs
(testing "get-all-contacts-in-group-chat"

View File

@ -9,6 +9,7 @@
(is (= {:last-clock-value 42
:admins #{4}
:contacts #{2}
:tags #{}
:membership-updates []}
(chats/normalize-chat {:admins [4]
:contacts [2]})))))

View File

@ -1,6 +1,6 @@
(ns status-im.test.models.contact
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.models.contact :as model]))
[status-im.contact.core :as model]))
(def public-key "0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917")
(def address "71adb0644e2b590e37dafdfea8bd58f0c7668c7f")

View File

@ -41,7 +41,7 @@
(rf/reg-fx :data-store.transport/save (constantly nil))
(rf/reg-fx :data-store/update-message (constantly nil))
(rf/dispatch [:open-chat-with-contact {:whisper-identity contact-whisper-identity}])
(rf/dispatch [:contact.ui/send-message-pressed {:whisper-identity contact-whisper-identity}])
(rf-test/wait-for [::transport.contact/send-new-sym-key]
(rf/dispatch [:set-chat-input-text "test message"])
(rf/dispatch [:send-current-message])

View File

@ -1,6 +1,5 @@
(ns status-im.test.runner
(:require [doo.runner :refer-macros [doo-tests]]
[status-im.test.contacts.events]
[status-im.test.contacts.subs]
[status-im.test.data-store.chats]
[status-im.test.data-store.realm.core]
@ -69,7 +68,6 @@
'status-im.test.utils.async
'status-im.test.chat.subs
'status-im.test.chat.models
'status-im.test.contacts.events
'status-im.test.contacts.subs
'status-im.test.init.core
'status-im.test.data-store.chats