Merge pull request #72 from status-im/group-chat-settings

Group chat settings
This commit is contained in:
Jarrad 2016-05-19 13:10:10 +02:00
commit 9a76ea9855
29 changed files with 687 additions and 25 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -14,6 +14,8 @@
[syng-im.new-group.screen :refer [new-group]]
[syng-im.participants.views.create :refer [new-participants]]
[syng-im.participants.views.remove :refer [remove-participants]]
[syng-im.group-settings.screen :refer [group-settings]]
[syng-im.group-settings.views.chat-name-edit :refer [chat-name-edit]]
[syng-im.profile.screen :refer [profile my-profile]]
[syng-im.utils.utils :refer [toast]]
[syng-im.utils.encryption]))
@ -40,6 +42,8 @@
:remove-participants [remove-participants]
:chat-list [chats-list]
:new-group [new-group]
:group-settings [group-settings]
:chat-name-edit [chat-name-edit]
:contact-list [contact-list]
:chat [chat]
:profile [profile]

View File

@ -132,11 +132,10 @@
:height 21}
:handler #(dispatch [:leave-group-chat])}
{:title "Settings"
:subtitle "Not implemented"
:icon :settings
:icon-style {:width 20
:height 13}
:handler (fn [])}]
:handler #(dispatch [:show-group-settings])}]
[{:title "Profile"
:custom-icon [menu-item-icon-profile]
:icon :menu_group
@ -148,15 +147,13 @@
:icon :search_gray_copy
:icon-style {:width 17
:height 17}
:handler nil #_#(dispatch
[:show-remove-participants navigator])}
:handler nil}
{:title "Notifications and sounds"
:subtitle "!not implemented"
:icon :muted
:icon-style {:width 18
:height 21}
:handler nil #_#(dispatch [:leave-group-chat
navigator])}
:handler nil}
{:title "Settings"
:subtitle "!not implemented"
:icon :settings
@ -227,12 +224,11 @@
:dataSource (to-datasource messages)}]))
(defview chat []
[is-active [:chat :is-active]
group-chat [:chat :group-chat]
[group-chat [:chat :group-chat]
show-actions-atom [:show-actions]]
[view st/chat-view
[chat-toolbar]
[messages-view group-chat]
(when group-chat [typing-all])
(when is-active [chat-message-new])
[chat-message-new]
(when show-actions-atom [actions-view])])

View File

@ -30,6 +30,9 @@
text])
(def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React)))
(def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React)))
(def modal (r/adapt-react-class (.-Modal js/React)))
(def picker (r/adapt-react-class (.-Picker js/React)))
(def picker-item (r/adapt-react-class (.-Item (.-Picker js/React))))
(defn icon [n style]

View File

@ -2,7 +2,8 @@
(def font "sans-serif")
;; (def font "Avenir-Roman")
(def title-font "sans-serif-medium")
(def font-medium "sans-serif-medium")
(def title-font font-medium)
(def color-blue "#7099e6")
(def color-blue-transparent "#7099e632")

View File

@ -0,0 +1,72 @@
(ns syng-im.group-settings.handlers
(:require [re-frame.core :refer [register-handler debug dispatch]]
[syng-im.persistence.realm :as r]
[syng-im.models.messages :refer [clear-history]]))
(defn set-chat-name [db]
(let [chat-id (:current-chat-id db)
name (:new-chat-name db)]
(r/write (fn []
(-> (r/get-by-field :chats :chat-id chat-id)
(r/single)
(aset "name" name))))
(assoc-in db [:chats chat-id :name] name)))
(defn set-chat-color [db]
(let [chat-id (:current-chat-id db)
color (:new-chat-color db)]
(r/write (fn []
(-> (r/get-by-field :chats :chat-id chat-id)
(r/single)
(aset "color" color))))
(assoc-in db [:chats chat-id :color] color)))
(defn delete-chat [chat-id]
(r/write
(fn []
(-> (r/get-by-field :chats :chat-id chat-id)
(r/single)
(r/delete))))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats]))
(register-handler :show-group-settings
(fn [db [action]]
(let [chat-id (:current-chat-id db)
chat-name (get-in db [:chats chat-id :name])
chat-color (get-in db [:chats chat-id :color])
db (assoc db
:new-chat-name chat-name
:new-chat-color chat-color
:group-settings-show-color-picker false
:group-settings-selected-member nil)]
(dispatch [:navigate-to :group-settings])
db)))
(register-handler :set-chat-name
(fn [db [action]]
(set-chat-name db)))
(register-handler :set-chat-color
(fn [db [action]]
(set-chat-color db)))
(register-handler :set-new-chat-name
(fn [db [action name]]
(assoc db :new-chat-name name)))
(register-handler :set-new-chat-color
(fn [db [action color]]
(assoc db :new-chat-color color)))
(register-handler :select-group-chat-member
(fn [db [action identity]]
(assoc db :group-settings-selected-member identity)))
(register-handler :set-group-settings-show-color-picker
(fn [db [action show?]]
(assoc db :group-settings-show-color-picker show?)))
(register-handler :clear-history
(fn [db [action]]
(clear-history (:current-chat-id db))))

View File

@ -0,0 +1,167 @@
(ns syng-im.group-settings.screen
(:require-macros [syng-im.utils.views :refer [defview]])
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.resources :as res]
[syng-im.components.react :refer [view
text-input
text
image
icon
modal
picker
picker-item
scroll-view
touchable-highlight]]
[syng-im.components.toolbar :refer [toolbar]]
[syng-im.components.realm :refer [list-view]]
[syng-im.components.styles :refer [color-purple
text2-color]]
[syng-im.group-settings.styles.group-settings :as st]
[syng-im.group-settings.views.member :refer [member-view]]
[reagent.core :as r]))
(defn remove-member [{:keys [whisper-identity]}]
(dispatch [:chat-remove-member whisper-identity]))
(defn close-member-menu []
(dispatch [:select-group-chat-member nil]))
(defview member-menu []
[member [:group-settings-selected-member]]
[modal {:animated false
:transparent false
:onRequestClose close-member-menu}
[touchable-highlight {:style st/modal-container
:on-press close-member-menu}
[view st/modal-inner-container
[text {:style st/modal-member-name}
(:name member)]
[touchable-highlight {:on-press #(remove-member member)}
[text {:style st/modal-remove-text}
"Remove"]]]]])
(defview chat-members []
[members [:current-chat-contacts]]
[view st/chat-members-container
(for [member members]
^{:key member} [member-view member])])
(defn show-chat-name-edit []
(dispatch [:navigate-to :chat-name-edit]))
(defn setting-view [{:keys [icon-style custom-icon handler title subtitle]
icon-name :icon}]
[touchable-highlight {:on-press handler}
[view st/setting-row
[view st/setting-icon-view
(or custom-icon
[icon icon-name icon-style])]
[view st/setting-view
[text {:style st/setting-title} title]
(when-let [subtitle subtitle]
[text {:style st/setting-subtitle}
subtitle])]]])
(defn close-chat-color-picker []
(dispatch [:set-group-settings-show-color-picker false]))
(defn set-chat-color []
(close-chat-color-picker)
(dispatch [:set-chat-color]))
(defview chat-color-picker []
[show-color-picker [:group-settings-show-color-picker]
new-color [:get :new-chat-color]]
[modal {:animated false
:transparent false
:onRequestClose close-chat-color-picker}
[touchable-highlight {:style st/modal-container
:on-press close-chat-color-picker}
[view st/modal-color-picker-inner-container
[picker {:selectedValue new-color
:onValueChange #(dispatch [:set-new-chat-color %])}
[picker-item {:label "Blue" :value "#7099e6"}]
[picker-item {:label "Purple" :value "#a187d5"}]
[picker-item {:label "Green" :value "green"}]
[picker-item {:label "Red" :value "red"}]]
[touchable-highlight {:on-press set-chat-color}
[text {:style st/modal-color-picker-save-btn-text}
"Save"]]]]])
(defview chat-color-icon []
[chat-color [:chat :color]]
[view {:style (st/chat-color-icon chat-color)}])
(defn show-chat-color-picker []
(dispatch [:set-group-settings-show-color-picker true]))
(defn settings-view []
;; TODO implement settings handlers
(let [settings [{:custom-icon [chat-color-icon]
:title "Change color"
:handler show-chat-color-picker}
(merge {:title "Notifications and sounds"
:subtitle "!not implemented"
:handler nil}
(if true
{:icon :notifications-on
:icon-style {:width 16
:height 21}}
{:icon :muted
:icon-style {:width 18
:height 21}}))
{:icon :close-gray
:icon-style {:width 12
:height 12}
:title "Clear history"
:handler #(dispatch [:clear-history])}
{:icon :bin
:icon-style {:width 12
:height 18}
:title "Delete and leave"
:handler #(dispatch [:leave-group-chat])}]]
[view st/settings-container
(for [setting settings]
^{:key setting} [setting-view setting])]))
(defview chat-icon []
[name [:chat :name]
color [:chat :color]]
[view (st/chat-icon color)
[text {:style st/chat-icon-text} (nth name 0)]])
(defn new-group-toolbar []
[toolbar {:title "Chat settings"
:custom-action [chat-icon]}])
(defview group-settings []
[chat-name [:chat :name]
selected-member [:group-settings-selected-member]
show-color-picker [:get :group-settings-show-color-picker]]
[view st/group-settings
[new-group-toolbar]
[scroll-view st/body
[text {:style st/chat-name-text}
"Chat name"]
[view st/chat-name-value-container
[text {:style st/chat-name-value}
chat-name]
[touchable-highlight {:style st/chat-name-btn-edit-container
:on-press show-chat-name-edit}
[text {:style st/chat-name-btn-edit-text}
"Edit"]]]
[text {:style st/members-text}
"Members"]
[touchable-highlight {:on-press #(dispatch [:show-add-participants])}
[view st/add-members-container
[icon :add-gray st/add-members-icon]
[text {:style st/add-members-text}
"Add members"]]]
[chat-members]
[text {:style st/settings-text}
"Settings"]
[settings-view]]
(when show-color-picker
[chat-color-picker])
(when selected-member
[member-menu])])

View File

@ -0,0 +1,19 @@
(ns syng-im.group-settings.styles.chat-name-edit
(:require [syng-im.components.styles :refer [font
color-white
text1-color]]))
(def save-action-icon
{:width 18
:height 14})
(def chat-name-container
{:flex 1
:flexDirection :column
:backgroundColor color-white})
(def chat-name-input
{:marginLeft 12
:fontSize 14
:fontFamily font
:color text1-color})

View File

@ -0,0 +1,185 @@
(ns syng-im.group-settings.styles.group-settings
(:require [syng-im.components.styles :refer [font
font-medium
title-font
color-white
color-purple
chat-background
online-color
selected-message-color
separator-color
text1-color
text2-color
toolbar-background1]]))
(def modal-container
{:flex 1
:justifyContent :center
:padding 20})
(def modal-inner-container
{:borderRadius 10
:alignItems :center
:padding 5
:backgroundColor color-white})
(def modal-member-name
{:color text2-color
:fontFamily font
:fontSize 14
:lineHeight 20})
(def modal-remove-text
{:margin 10
:color text1-color
:fontFamily font
:fontSize 14
:lineHeight 20})
(def modal-color-picker-inner-container
{:borderRadius 10
:padding 5
:backgroundColor color-white})
(def modal-color-picker-save-btn-text
{:margin 10
:alignSelf :center
:color text1-color
:fontFamily font
:fontSize 14
:lineHeight 20})
(def chat-members-container
{:marginBottom 10})
(defn chat-icon [color]
{:margin 10
:width 36
:height 36
:borderRadius 50
:backgroundColor color})
(def chat-icon-text
{:marginTop 7
:marginLeft 13
:color color-white
:fontFamily font
:fontSize 16
:lineHeight 20})
(def group-settings
{:flex 1
:flexDirection :column
:backgroundColor color-white})
(def body
{:flex 1
:flexDirection :column})
(def chat-name-text
{:marginTop 24
:marginLeft 16
:marginBottom 16
:color text2-color
:fontFamily font-medium
:fontSize 14
:lineHeight 20})
(def chat-name-value-container
{:flexDirection :row
:marginLeft 16
:height 56
:alignItems :center
:justifyContent :center
:borderBottomWidth 1
:borderBottomColor separator-color})
(def chat-name-value
{:flex 1
:fontSize 16
:fontFamily font
:color text1-color})
(def chat-name-btn-edit-container
{:padding 16
:justifyContent :center})
(def chat-name-btn-edit-text
{:marginTop -1
:color text2-color
:fontFamily font
:fontSize 16
:lineHeight 20})
(def members-text
{:marginTop 24
:marginLeft 16
:marginBottom 16
:color text2-color
:fontFamily font-medium
:fontSize 14
:lineHeight 20})
(def add-members-icon
{:marginVertical 19
:marginLeft 19
:marginHorizontal 3
:width 17
:height 17})
(def add-members-container
{:flexDirection :row})
(def add-members-text
{:marginTop 18
:marginLeft 32
:color text2-color
:fontFamily font
:fontSize 16
:lineHeight 20})
(def settings-text
{:marginTop 24
:marginLeft 16
:marginBottom 16
:color text2-color
:fontFamily font-medium
:fontSize 14
:lineHeight 20})
(def settings-container
{:flexDirection :column})
(def setting-row
{:flexDirection :row
:height 56})
(def setting-icon-view
{:width 56
:height 56
:alignItems :center
:justifyContent :center})
(def setting-view
{:flex 1
:marginLeft 16
:alignItems :flex-start
:justifyContent :center})
(def setting-title
{:marginTop -2.5
:color text1-color
:fontSize 16
:fontFamily font})
(def setting-subtitle
{:marginTop 1
:color text2-color
:fontSize 12
:fontFamily font})
(defn chat-color-icon [color]
{:borderRadius 50
:width 24
:height 24
:backgroundColor color})

View File

@ -0,0 +1,78 @@
(ns syng-im.group-settings.styles.member
(:require [syng-im.components.styles :refer [font
title-font
text1-color
text2-color
color-white
online-color]]))
(def contact-photo-container
{:borderRadius 50})
(def photo-image
{:borderRadius 50
:width 40
:height 40})
(def online-container
{:position :absolute
:top 24
:left 24
:width 20
:height 20
:borderRadius 50
:backgroundColor online-color
:borderWidth 2
:borderColor color-white})
(def online-dot
{:position :absolute
:top 6
:width 4
:height 4
:borderRadius 50
:backgroundColor color-white})
(def online-dot-left
(assoc online-dot :left 3))
(def online-dot-right
(assoc online-dot :left 9))
(def contact-container
{:flexDirection :row
:height 56})
(def photo-container
{:marginTop 8
:marginLeft 16
:width 44
:height 44})
(def info-container
{:flex 1
:flexDirection :column
:marginLeft 16
:justifyContent :center})
(def name-text
{:marginTop -2
:fontSize 16
:fontFamily font
:color text1-color})
(def role-text
{:marginTop 1
:fontSize 12
:fontFamily font
:color text2-color})
(def more-btn
{:width 56
:height 56
:alignItems :center
:justifyContent :center })
(def more-btn-icon
{:width 4
:height 16})

View File

@ -0,0 +1,14 @@
(ns syng-im.group-settings.subs
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub]]
[syng-im.models.contacts :refer [contact-by-identity]]))
(register-sub :group-settings-selected-member
(fn [db [_]]
(reaction
(let [identity (get @db :group-settings-selected-member)]
(contact-by-identity identity)))))
(register-sub :group-settings-show-color-picker
(fn [db [_]]
(reaction (get @db :group-settings-show-color-picker))))

View File

@ -0,0 +1,31 @@
(ns syng-im.group-settings.views.chat-name-edit
(:require-macros [syng-im.utils.views :refer [defview]])
(:require [reagent.core :as r]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [view text-input]]
[syng-im.components.toolbar :refer [toolbar]]
[syng-im.group-settings.styles.chat-name-edit :as st]
[syng-im.components.styles :refer [toolbar-background2
text2-color]]))
(defn save-group-chat-name []
(dispatch [:set-chat-name])
(dispatch [:navigate-back]))
(defn chat-name-edit-toolbar [chat-name]
[toolbar {:background-color toolbar-background2
:title "Edit chat name"
;; TODO change to dark 'ok' icon
:action {:image {:source {:uri :icon_ok}
:style st/save-action-icon}
:handler save-group-chat-name}}])
(defview chat-name-edit []
[new-chat-name [:get :new-chat-name]]
[view st/chat-name-container
[chat-name-edit-toolbar]
[text-input {:style st/chat-name-input
:autoFocus true
:placeholderTextColor text2-color
:onChangeText #(dispatch [:set-new-chat-name %])}
new-chat-name]])

View File

@ -0,0 +1,43 @@
(ns syng-im.group-settings.views.member
(:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [view
image
text
icon
touchable-highlight]]
[syng-im.resources :as res]
[syng-im.group-settings.styles.member :as st]))
(defn contact-photo [{:keys [photo-path]}]
[view st/contact-photo-container
[image {:source (if (s/blank? photo-path)
res/user-no-photo
{:uri photo-path})
:style st/photo-image}]])
(defn contact-online [{:keys [online]}]
(when online
[view st/online-container
[view st/online-dot-left]
[view st/online-dot-right]]))
(defn member-view [{:keys [whisper-identity name photo-path online role]}]
[view st/contact-container
[view st/photo-container
[contact-photo {:photo-path photo-path}]
[contact-online {:online online}]]
[view st/info-container
[text {:style st/name-text}
(if (pos? (count name))
name
;; todo is this correct behaviour?
"Noname")]
;; TODO implement :role property for group chat contact
(when role
[text {:style st/role-text}
role])]
[touchable-highlight
{:on-press #(dispatch [:select-group-chat-member whisper-identity])}
[view st/more-btn
[icon :more-vertical st/more-btn-icon]]]])

View File

@ -2,6 +2,7 @@
(:require
[re-frame.core :refer [register-handler after dispatch debug enrich]]
[schema.core :as s :include-macros true]
[syng-im.persistence.realm :as r]
[syng-im.db :refer [app-db schema]]
[syng-im.persistence.simple-kv-store :as kv]
[syng-im.protocol.state.storage :as storage]
@ -11,7 +12,9 @@
[syng-im.models.protocol :refer [update-identity
set-initialized]]
[syng-im.models.contacts :as contacts]
[syng-im.models.messages :refer [save-message update-message!]]
[syng-im.models.messages :refer [save-message
update-message!
clear-history]]
[syng-im.models.commands :refer [set-commands]]
[syng-im.handlers.server :as server]
[syng-im.chat.suggestions :refer [load-commands]]
@ -32,6 +35,7 @@
[syng-im.utils.crypt :refer [gen-random-bytes]]
[syng-im.utils.random :as random]
syng-im.chat.handlers
[syng-im.group-settings.handlers :refer [delete-chat]]
[syng-im.navigation.handlers :as nav]
syng-im.discovery.handlers
syng-im.contacts.handlers))
@ -211,12 +215,14 @@
:delivery-status :failed})))
(register-handler :leave-group-chat
(fn [db [action navigator]]
(fn [db [action]]
(log/debug action)
(let [chat-id (:current-chat-id db)]
(api/leave-group-chat chat-id)
(set-chat-active chat-id false)
(left-chat-msg chat-id))))
(left-chat-msg chat-id)
(delete-chat chat-id)
(dispatch [:navigate-back]))))
;; -- User data --------------------------------------------------------------
(register-handler :load-user-phone-number
@ -253,11 +259,36 @@
(let [identities (vec (:new-participants db))
chat-id (:current-chat-id db)]
(chat-add-participants chat-id identities)
(nav-pop navigator)
(dispatch [:navigate-back])
(doseq [ident identities]
(api/group-add-participant chat-id ident))
db)))
(defn chat-remove-member [db]
(let [chat (get-in db [:chats (:current-chat-id db)])
identity (:group-settings-selected-member db)]
(r/write
(fn []
(r/create :chats
(update chat :contacts
(fn [members]
(filter #(not= (:identity %) identity) members)))
true)))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats])
db))
(register-handler :chat-remove-member
(fn [db [action]]
(let [chat-id (:current-chat-id db)
identity (:group-settings-selected-member db)
db (chat-remove-member db)]
(dispatch [:select-group-chat-member nil])
;; TODO fix and uncomment
(api/group-remove-participant chat-id identity)
(removed-participant-msg chat-id identity)
db)))
(defn update-new-group-selection [db identity add?]
(update-in db :new-group (fn [new-group]
(if add?

View File

@ -1,5 +1,6 @@
(ns syng-im.models.chats
(:require [clojure.set :refer [difference]]
[re-frame.core :refer [dispatch]]
[syng-im.persistence.realm :as r]
[syng-im.utils.random :as random :refer [timestamp]]
[clojure.string :refer [join blank?]]
@ -113,8 +114,11 @@
(if-let [contact-exists (.find contacts (fn [object index collection]
(= contact-identity (aget object "identity"))))]
(aset contact-exists "is-in-chat" true)
(.push contacts (clj->js {:identity contact-identity}))))))))
(.push contacts (clj->js {:identity contact-identity})))))))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats]))
;; TODO deprecated? (is there need to remove multiple member at once?)
(defn chat-remove-participants [chat-id identities]
(r/write
(fn []
@ -131,7 +135,6 @@
(js->clj (.map results (fn [object _ _]
(aget object "chat-id"))))))
(defn set-chat-active [chat-id active?]
(r/write (fn []
(-> (r/get-by-field :chats :chat-id chat-id)

View File

@ -24,16 +24,20 @@
(r/sorted (r/get-all :contacts) :name :asc))
(defn contacts-list-exclude [exclude-idents]
(if (empty? exclude-idents)
(contacts-list)
(let [query (exclude-query :whisper-identity exclude-idents)]
(-> (r/get-all :contacts)
(r/filtered query)
(r/sorted :name :asc))))
(r/sorted :name :asc)))))
(defn contacts-list-include [include-indents]
(if (empty? include-indents)
()
(let [query (include-query :whisper-identity include-indents)]
(-> (r/get-all :contacts)
(r/filtered query)
(r/sorted :name :asc))))
(r/sorted :name :asc)))))
(defn contact-by-identity [identity]
(r/single-cljs (r/get-by-field :contacts :whisper-identity identity)))

View File

@ -1,5 +1,6 @@
(ns syng-im.models.messages
(:require [syng-im.persistence.realm :as r]
[re-frame.core :refer [dispatch]]
[cljs.reader :refer [read-string]]
[syng-im.utils.random :refer [timestamp]]
[syng-im.db :as db]
@ -56,3 +57,10 @@
(fn []
(when (r/exists? :msgs :msg-id msg-id)
(r/create :msgs msg true)))))
(defn clear-history [chat-id]
(r/write
(fn []
(r/delete (r/get-by-field :msgs :chat-id chat-id))))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats]))

View File

@ -58,7 +58,7 @@
(push-view db :contact-list)))
(defn clear-new-participants [db]
(assoc-in db :new-participants #{}))
(assoc db :new-participants #{}))
(register-handler :show-remove-participants
(fn [db _]

View File

@ -43,6 +43,8 @@
:primaryKey :chat-id
:properties {:chat-id "string"
:name "string"
:color {:type "string"
:default "#a187d5"}
:group-chat {:type "bool"
:indexed true}
:is-active "bool"

View File

@ -2,6 +2,7 @@
(:require-macros [reagent.ratom :refer [reaction]])
(:require [re-frame.core :refer [register-sub]]
syng-im.chat.subs
syng-im.group-settings.subs
syng-im.discovery.subs
syng-im.contacts.subs))