From 07301497ea82093d0246bf910e106275c028d646 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Fri, 11 Nov 2016 14:31:36 +0200 Subject: [PATCH] fix #433 add contact to contact list only after pressing "Add to contacts" add new contact bar & badges --- src/status_im/chat/handlers.cljs | 22 ++++++---- src/status_im/chat/screen.cljs | 14 ++++++- src/status_im/chat/styles/screen.cljs | 26 ++++++++---- src/status_im/chat/views/actions.cljs | 15 ++----- .../components/chat_icon/screen.cljs | 25 +++++++++++- .../components/chat_icon/styles.cljs | 40 ++++++++++++++++++- .../components/sync_state/offline.cljs | 25 +++++++----- .../components/sync_state/styles.cljs | 6 +-- src/status_im/contacts/handlers.cljs | 36 +++++++---------- .../realm/schemas/account/core.cljs | 19 +++++---- .../realm/schemas/account/v4/chat.cljs | 38 ++++++++++++++++++ .../realm/schemas/account/v4/core.cljs | 29 ++++++++++++++ src/status_im/protocol/handlers.cljs | 32 +++++++++------ 13 files changed, 240 insertions(+), 87 deletions(-) create mode 100644 src/status_im/data_store/realm/schemas/account/v4/chat.cljs create mode 100644 src/status_im/data_store/realm/schemas/account/v4/core.cljs diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index da150c9539..360bcf5ab1 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -238,7 +238,7 @@ (after (fn [_ [_ phone-number]] (dispatch [:account-update {:phone phone-number}]))) (fn [db [_ phone-number message-id]] - (let [formatted (format-phone-number phone-number)] + (let [formatted (format-phone-number phone-number)] (-> db (assoc :user-phone-number formatted) sign-up-service/start-listening-confirmation-code-sms @@ -288,13 +288,13 @@ (defn initialize-chats [{:keys [loaded-chats account-creation? chats] :as db} _] (let [chats' (if account-creation? - chats - (->> loaded-chats - (map (fn [{:keys [chat-id] :as chat}] - (let [last-message (messages/get-last-message db chat-id)] - [chat-id (assoc chat :last-message last-message)]))) - (into {}))) - ids (set (keys chats'))] + chats + (->> loaded-chats + (map (fn [{:keys [chat-id] :as chat}] + (let [last-message (messages/get-last-message db chat-id)] + [chat-id (assoc chat :last-message last-message)]))) + (into {}))) + ids (set (keys chats'))] (-> db (assoc :chats chats') @@ -399,6 +399,12 @@ (dispatch [::start-chat! contact-id options navigation-type]))))) (register-handler :add-chat + (u/side-effect! + (fn [{:keys [chats]} [_ chat-id chat]] + (when-not (get chats chat-id) + (dispatch [::add-chat chat-id chat]))))) + +(register-handler ::add-chat (-> add-new-chat ((enrich add-chat)) ((after save-new-chat!)))) diff --git a/src/status_im/chat/screen.cljs b/src/status_im/chat/screen.cljs index a1bcd771f9..b36f52a48f 100644 --- a/src/status_im/chat/screen.cljs +++ b/src/status_im/chat/screen.cljs @@ -98,6 +98,16 @@ [view st/action [chat-icon]]])))) +(defview add-contact-bar [] + [pending-contact? [:chat :pending-contact?] + chat-id [:get :current-chat-id]] + (when pending-contact? + [touchable-highlight + {:on-press #(dispatch [:add-pending-contact chat-id])} + [view st/add-contact + [text {:style st/add-contact-text} + (label :t/add-to-contacts)]]])) + (defview chat-toolbar [] [show-actions? [:chat-ui-props :show-actions?] accounts [:get :accounts]] @@ -106,8 +116,8 @@ [toolbar {:hide-nav? (or (empty? accounts) show-actions?) :custom-content [toolbar-content-view] :custom-action [toolbar-action] - :style (get-in platform-specific [:component-styles :toolbar])}]]) - + :style (get-in platform-specific [:component-styles :toolbar])}] + [add-contact-bar]]) (defn get-intro-status-message [all-messages] (let [{:keys [timestamp content-type] :as last-message} (last all-messages)] (when (not= content-type content-type-status) diff --git a/src/status_im/chat/styles/screen.cljs b/src/status_im/chat/styles/screen.cljs index 3a97e188a5..1f92177120 100644 --- a/src/status_im/chat/styles/screen.cljs +++ b/src/status_im/chat/styles/screen.cljs @@ -139,9 +139,9 @@ :backgroundColor selected-message-color}) (def typing-text - {:marginTop -2 - :fontSize 12 - :color text2-color}) + {:marginTop -2 + :fontSize 12 + :color text2-color}) (def overlay-highlight {:flex 1}) @@ -155,7 +155,7 @@ :left -16 :right -16 :background-color "#00000055" - :elevation 8}) + :elevation 8}) (defn bottom-info-container [height] {:backgroundColor toolbar-background1 @@ -194,7 +194,17 @@ (def chat-modal {:position :absolute - :left 0 - :top 0 - :right 0 - :bottom 0}) \ No newline at end of file + :left 0 + :top 0 + :right 0 + :bottom 0}) + +(def add-contact + {:height 35 + :background-color :white + :justify-content :center}) + +(def add-contact-text + {:text-align :center + :text-align-vertical :center + :color :#7099e6}) diff --git a/src/status_im/chat/views/actions.cljs b/src/status_im/chat/views/actions.cljs index dd0e233c45..c4fefd7247 100644 --- a/src/status_im/chat/views/actions.cljs +++ b/src/status_im/chat/views/actions.cljs @@ -44,13 +44,6 @@ :height 19} :handler #(dispatch [:show-profile chat-id])}) -(defn item-add-to-contacts [contact] - {:title (label :t/add-to-contacts) - :icon :menu_group - :icon-style {:width 20 - :height 17} - :handler #(dispatch [:add-pending-contact contact])}) - (def item-search {:title (label :t/search-chat) :subtitle (label :t/not-implemented) @@ -83,9 +76,8 @@ item-notifications item-settings]) -(defn user-chat-items [chat-id {:keys [pending] :as contact}] +(defn user-chat-items [chat-id] [(item-user chat-id) - (if pending (item-add-to-contacts contact) nil) item-search item-notifications item-settings]) @@ -123,12 +115,13 @@ subtitle])]]]) (defn actions-list-view [] - (let [{:keys [group-chat chat-id]} (subscribe [:chat-properties [:group-chat :chat-id]]) + (let [{:keys [group-chat chat-id]} + (subscribe [:chat-properties [:group-chat :chat-id]]) members (subscribe [:current-chat-contacts]) status-bar-height (get-in platform-specific [:component-styles :status-bar :default :height])] (when-let [actions (if @group-chat (group-chat-items @members) - (user-chat-items @chat-id (first @members)))] + (user-chat-items @chat-id))] [view (-> (st/actions-wrapper status-bar-height) (merge (get-in platform-specific [:component-styles :actions-list-view]))) [view st/actions-separator] diff --git a/src/status_im/components/chat_icon/screen.cljs b/src/status_im/components/chat_icon/screen.cljs index 45bb47c874..43e03eb471 100644 --- a/src/status_im/components/chat_icon/screen.cljs +++ b/src/status_im/components/chat_icon/screen.cljs @@ -16,7 +16,7 @@ [text {:style (:default-chat-icon-text styles)} (first name)]]) -(defn chat-icon [photo-path {:keys [size border]}] +(defn chat-icon [photo-path {:keys [size]}] [image {:source {:uri photo-path} :style (merge st/default-image-style (st/image-style size))}]) @@ -39,6 +39,14 @@ [oct-icon {:name :pencil :style st/photo-pencil}]])])) +(defview pending-contact-badge + [chat-id {:keys [pending-wrapper pending-outer-circle pending-inner-circle]}] + [pending-contact? [:get-in [:chats chat-id :pending-contact?]]] + (when pending-contact? + [view pending-wrapper + [view pending-outer-circle + [view pending-inner-circle]]])) + (defview chat-icon-view [chat-id group-chat name online styles] [photo-path [:chat-photo chat-id] dapp? [:get-in [:contacts chat-id :dapp?]]] @@ -47,7 +55,8 @@ [chat-icon photo-path styles] [default-chat-icon name styles]) (when dapp? - [dapp-badge styles])]) + [dapp-badge styles]) + [pending-contact-badge chat-id styles]]) (defn chat-icon-view-chat-list [chat-id group-chat name color online] [chat-icon-view chat-id group-chat name online @@ -56,6 +65,9 @@ :online-view st/online-view :online-dot-left st/online-dot-left :online-dot-right st/online-dot-right + :pending-wrapper st/pending-wrapper + :pending-outer-circle st/pending-outer-circle + :pending-inner-circle st/pending-inner-circle :size 40 :chat-icon st/chat-icon-chat-list :default-chat-icon (st/default-chat-icon-chat-list color) @@ -68,6 +80,9 @@ :online-view st/online-view :online-dot-left st/online-dot-left :online-dot-right st/online-dot-right + :pending-wrapper st/pending-wrapper + :pending-outer-circle st/pending-outer-circle + :pending-inner-circle st/pending-inner-circle :size 36 :chat-icon st/chat-icon-view-action :default-chat-icon (st/default-chat-icon-view-action color) @@ -80,6 +95,9 @@ :online-view st/online-view-menu-item :online-dot-left st/online-dot-left-menu-item :online-dot-right st/online-dot-right-menu-item + :pending-wrapper st/pending-view-menu-wrapper + :pending-outer-circle st/pending-outer-circle + :pending-inner-circle st/pending-inner-circle :size 24 :chat-icon st/chat-icon-menu-item :default-chat-icon (st/default-chat-icon-view-action color) @@ -92,6 +110,9 @@ :online-view st/online-view :online-dot-left st/online-dot-left :online-dot-right st/online-dot-right + :pending-wrapper st/pending-wrapper + :pending-outer-circle st/pending-outer-circle + :pending-inner-circle st/pending-inner-circle :size 64 :chat-icon st/chat-icon-message-status :default-chat-icon (st/default-chat-icon-message-status color) diff --git a/src/status_im/components/chat_icon/styles.cljs b/src/status_im/components/chat_icon/styles.cljs index b133fc6a9b..9f30e1159d 100644 --- a/src/status_im/components/chat_icon/styles.cljs +++ b/src/status_im/components/chat_icon/styles.cljs @@ -119,8 +119,8 @@ {:width 14 :height 14 :border-radius 7 - :bottom 1 - :right 1})) + :bottom 1 + :right 1})) (def online-view-profile (merge online-view @@ -201,3 +201,39 @@ {:width image-size :height image-size :border-radius (/ image-size 2)})) + +(def pending-wrapper + {:position :absolute + :bottom 4 + :right 5 + :width 12 + :height 12 + :border-radius 6 + :background-color :white + :align-items :center + :justify-content :center}) + +(def pending-view-menu-wrapper + {:position :absolute + :bottom 2 + :right 2 + :width 12 + :height 12 + :border-radius 6 + :background-color :white + :align-items :center + :justify-content :center}) + +(def pending-outer-circle + {:background-color online-color + :width 8 + :height 8 + :border-radius 4 + :align-items :center + :justify-content :center}) + +(def pending-inner-circle + {:background-color :white + :width 4 + :height 4 + :border-radius 2}) diff --git a/src/status_im/components/sync_state/offline.cljs b/src/status_im/components/sync_state/offline.cljs index 99f51761d5..885abbb8fc 100644 --- a/src/status_im/components/sync_state/offline.cljs +++ b/src/status_im/components/sync_state/offline.cljs @@ -18,13 +18,15 @@ :duration 250}))) (defn offline-view [_] - (let [sync-state (subscribe [:get :sync-state]) - network-status (subscribe [:get :network-status]) - offline-opacity (anim/create-value 0.0) - on-update (fn [_ _] - (anim/set-value offline-opacity 0) - (when (or (= @network-status :offline) (= @sync-state :offline)) - (start-offline-animation offline-opacity)))] + (let [sync-state (subscribe [:get :sync-state]) + network-status (subscribe [:get :network-status]) + offline-opacity (anim/create-value 0.0) + on-update (fn [_ _] + (anim/set-value offline-opacity 0) + (when (or (= @network-status :offline) (= @sync-state :offline)) + (start-offline-animation offline-opacity))) + pending-contact? (subscribe [:chat :pending-contact?]) + view-id (subscribe [:get :view-id])] (r/create-class {:component-did-mount on-update @@ -33,7 +35,8 @@ :reagent-render (fn [{:keys [top]}] (when (or (= @network-status :offline) (= @sync-state :offline)) - [animated-view {:style (st/offline-wrapper top offline-opacity window-width)} - [view - [text {:style st/offline-text} - (label :t/offline)]]]))}))) + (let [pending? (and @pending-contact? (= :chat @view-id))] + [animated-view {:style (st/offline-wrapper top offline-opacity window-width pending?)} + [view + [text {:style st/offline-text} + (label :t/offline)]]])))}))) diff --git a/src/status_im/components/sync_state/styles.cljs b/src/status_im/components/sync_state/styles.cljs index 1411802d2d..b6b036597d 100644 --- a/src/status_im/components/sync_state/styles.cljs +++ b/src/status_im/components/sync_state/styles.cljs @@ -26,10 +26,10 @@ :background-color "#5fc48d" :height 2}) -(defn offline-wrapper [top opacity window-width] +(defn offline-wrapper [top opacity window-width pending?] {:opacity opacity :width window-width - :top (+ 56 top) + :top (+ (+ 56 top) (if pending? 35 0)) :position :absolute :background-color "#828b92cc" :height 35}) @@ -38,4 +38,4 @@ {:text-align :center :color :white :font-size 14 - :top 8}) \ No newline at end of file + :top 8}) diff --git a/src/status_im/contacts/handlers.cljs b/src/status_im/contacts/handlers.cljs index 485eca828e..b2bdebe551 100644 --- a/src/status_im/contacts/handlers.cljs +++ b/src/status_im/contacts/handlers.cljs @@ -11,7 +11,8 @@ [status-im.utils.utils :refer [require]] [status-im.navigation.handlers :as nav] [status-im.utils.random :as random] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [cljs.reader :refer [read-string]])) (defmethod nav/preload-data! :group-contacts @@ -55,7 +56,8 @@ (defn send-contact-request [{:keys [current-public-key web3 current-account-id accounts]} [_ contact]] (let [{:keys [whisper-identity]} contact - {:keys [name photo-path updates-public-key updates-private-key]} (get accounts current-account-id)] + {:keys [name photo-path updates-public-key updates-private-key status]} + (get accounts current-account-id)] (protocol/contact-request! {:web3 web3 :message {:from current-public-key @@ -63,7 +65,8 @@ :message-id (random/id) :payload {:contact {:name name :profile-image photo-path - :address current-account-id} + :address current-account-id + :status status} :keypair {:public updates-public-key :private updates-private-key}}}}))) @@ -132,7 +135,7 @@ (defn request-stored-contacts [contacts] (let [contacts-by-hash (get-contacts-by-hash contacts) - data (or (keys contacts-by-hash) ())] + data (or (keys contacts-by-hash) ())] (http-post "get-contacts" {:phone-number-hashes data} (fn [{:keys [contacts]}] (let [contacts' (add-identity contacts-by-hash contacts)] @@ -156,7 +159,7 @@ (defn add-new-contacts [{:keys [contacts] :as db} [_ new-contacts]] - (let [identities (set (map :whisper-identity contacts)) + (let [identities (set (map :whisper-identity contacts)) new-contacts' (->> new-contacts (map #(update-pending-status contacts %)) (remove #(identities (:whisper-identity %))) @@ -193,22 +196,13 @@ (register-handler :add-pending-contact (u/side-effect! - (fn [{:keys [current-public-key web3 current-account-id accounts]} - [_ {:keys [whisper-identity] :as contact}]] - (let [contact (assoc contact :pending false) - {:keys [name photo-path updates-public-key updates-private-key]} - (accounts current-account-id)] - (protocol/contact-request! - {:web3 web3 - :message {:from current-public-key - :to whisper-identity - :message-id (random/id) - :payload {:contact {:name name - :profile-image photo-path - :address current-account-id} - :keypair {:public updates-public-key - :private updates-private-key}}}}) - (dispatch [::update-pending-contact contact]))))) + (fn [{:keys [chats]} [_ chat-id]] + (let [contact (read-string (get-in chats [chat-id :contact-info]))] + (dispatch [::prepare-contact contact]) + (dispatch [:update-chat! {:chat-id chat-id + :contact-info nil + :pending-contact? false}]) + (dispatch [:watch-contact contact]))))) (defn set-contact-identity-from-qr [db [_ _ contact-identity]] diff --git a/src/status_im/data_store/realm/schemas/account/core.cljs b/src/status_im/data_store/realm/schemas/account/core.cljs index 1707511b7e..85a9629e22 100644 --- a/src/status_im/data_store/realm/schemas/account/core.cljs +++ b/src/status_im/data_store/realm/schemas/account/core.cljs @@ -1,15 +1,20 @@ (ns status-im.data-store.realm.schemas.account.core (:require [status-im.data-store.realm.schemas.account.v1.core :as v1] [status-im.data-store.realm.schemas.account.v2.core :as v2] - [status-im.data-store.realm.schemas.account.v3.core :as v3])) + [status-im.data-store.realm.schemas.account.v3.core :as v3] + [status-im.data-store.realm.schemas.account.v4.core :as v4] + )) ; put schemas ordered by version -(def schemas [{:schema v1/schema +(def schemas [{:schema v1/schema :schemaVersion 1 - :migration v1/migration} - {:schema v2/schema + :migration v1/migration} + {:schema v2/schema :schemaVersion 2 - :migration v2/migration} - {:schema v3/schema + :migration v2/migration} + {:schema v3/schema :schemaVersion 3 - :migration v3/migration}]) \ No newline at end of file + :migration v3/migration} + {:schema v4/schema + :schemaVersion 4 + :migration v4/migration}]) diff --git a/src/status_im/data_store/realm/schemas/account/v4/chat.cljs b/src/status_im/data_store/realm/schemas/account/v4/chat.cljs new file mode 100644 index 0000000000..1ce8a098a8 --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v4/chat.cljs @@ -0,0 +1,38 @@ +(ns status-im.data-store.realm.schemas.account.v4.chat + (:require [taoensso.timbre :as log] + [status-im.components.styles :refer [default-chat-color]])) + +(def schema {:name :chat + :primaryKey :chat-id + :properties {:chat-id :string + :name :string + :color {:type :string + :default default-chat-color} + :group-chat {:type :bool + :indexed true} + :is-active :bool + :timestamp :int + :contacts {:type :list + :objectType :chat-contact} + :dapp-url {:type :string + :optional true} + :dapp-hash {:type :int + :optional true} + :removed-at {:type :int + :optional true} + :last-message-id :string + :public-key {:type :string + :optional true} + :private-key {:type :string + :optional true} + :clock-value {:type :int + :default 0} + :pending-contact? {:type :bool + :default false} + :contact-info {:type :string + :optional true}}}) + +(defn migration [_ new-realm] + (let [new-objs (.objects new-realm "chat")] + (dotimes [i (range (.-length new-objs))] + (aset (aget new-objs i) "pending-contact?" false)))) diff --git a/src/status_im/data_store/realm/schemas/account/v4/core.cljs b/src/status_im/data_store/realm/schemas/account/v4/core.cljs new file mode 100644 index 0000000000..0bb4713be6 --- /dev/null +++ b/src/status_im/data_store/realm/schemas/account/v4/core.cljs @@ -0,0 +1,29 @@ +(ns status-im.data-store.realm.schemas.account.v4.core + (:require [taoensso.timbre :as log] + [status-im.data-store.realm.schemas.account.v4.chat :as chat] + [status-im.data-store.realm.schemas.account.v3.message :as message] + [status-im.data-store.realm.schemas.account.v2.contact :as contact] + [status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact] + [status-im.data-store.realm.schemas.account.v1.command :as command] + [status-im.data-store.realm.schemas.account.v1.discovery :as discovery] + [status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store] + [status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message] + [status-im.data-store.realm.schemas.account.v1.request :as request] + [status-im.data-store.realm.schemas.account.v1.tag :as tag] + [status-im.data-store.realm.schemas.account.v1.user-status :as user-status])) + +(def schema [chat/schema + chat-contact/schema + command/schema + contact/schema + discovery/schema + kv-store/schema + message/schema + pending-message/schema + request/schema + tag/schema + user-status/schema]) + +(defn migration [old-realm new-realm] + (log/debug "migrating v4 account database: " old-realm new-realm) + (chat/migration old-realm new-realm)) diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index 0c2d5155b0..6e48be10af 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -288,17 +288,25 @@ (register-handler :contact-request-received (u/side-effect! - (fn [_ [_ {:keys [from payload]}]] + (fn [{:keys [contacts]} [_ {:keys [from payload]}]] (when from - (let [{{:keys [name profile-image address]} :contact - {:keys [public private]} :keypair} payload + (let [{{:keys [name profile-image address status]} :contact + {:keys [public private]} :keypair} payload - contact {:whisper-identity from - :public-key public - :private-key private - :address address - :photo-path profile-image - :name name - :pending true}] - (dispatch [:watch-contact contact]) - (dispatch [:add-contacts [contact]])))))) + contact {:whisper-identity from + :public-key public + :private-key private + :address address + :status status + :photo-path profile-image + :name name} + contact-exist? (get contacts from) + chat {:name name + :chat-id from + :contact-info (prn-str contact) + :pending-contact? true}] + (if contact-exist? + (do + (dispatch [:update-contact! contact]) + (dispatch [:watch-contact contact])) + (dispatch [:add-chat from chat])))))))