Merge pull request #16 from syng-im/group-chat-2-rebased

group chat actions and events implementation

Former-commit-id: 891ac48d09
This commit is contained in:
Jarrad 2016-04-19 16:24:59 +07:00
commit c0b508a537
22 changed files with 507 additions and 109 deletions

BIN
images/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
images/leave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/trash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -13,6 +13,8 @@
[syng-im.components.sign-up-confirm :refer [sign-up-confirm-view]]
[syng-im.components.chats.chats-list :refer [chats-list]]
[syng-im.components.chats.new-group :refer [new-group]]
[syng-im.components.chat.new-participants :refer [new-participants]]
[syng-im.components.chat.remove-participants :refer [remove-participants]]
[syng-im.utils.logging :as log]
[syng-im.navigation :as nav]
[syng-im.utils.encryption]))
@ -42,6 +44,8 @@
view-id (keyword view-id)]
(init-back-button-handler! nav)
(case view-id
:add-participants (r/as-element [new-participants {:navigator nav}])
:remove-participants (r/as-element [remove-participants {:navigator nav}])
:chat-list (r/as-element [chats-list {:navigator nav}])
:new-group (r/as-element [new-group {:navigator nav}])
:contact-list (r/as-element [contact-list {:navigator nav}])

View File

@ -25,9 +25,12 @@
(into {})))
(defn add-msg-color [{:keys [from] :as msg} contact-by-identity]
(let [{:keys [text-color background-color]} (get contact-by-identity from)]
(assoc msg :text-color text-color
:background-color background-color)))
(if (= "system" from)
(assoc msg :text-color "#4A5258"
:background-color "#D3EEEF")
(let [{:keys [text-color background-color]} (get contact-by-identity from)]
(assoc msg :text-color text-color
:background-color background-color))))
(defn chat [{:keys [navigator]}]
(let [messages (subscribe [:get-chat-messages])
@ -42,18 +45,34 @@
:backgroundColor "#eef2f5"}}
(when android?
;; TODO add IOS version
[toolbar-android {:logo res/logo-icon
:title (or (@chat :name)
"Chat name")
:titleColor "#4A5258"
:subtitle "Last seen just now"
:subtitleColor "#AAB2B2"
:navIcon res/nav-back-icon
:style {:backgroundColor "white"
:height 56
:elevation 2}
:onIconClicked (fn []
(nav-pop navigator))}])
[toolbar-android {:logo res/logo-icon
:title (or (@chat :name)
"Chat name")
:titleColor "#4A5258"
:subtitle "Last seen just now"
:subtitleColor "#AAB2B2"
:navIcon res/nav-back-icon
:style {:backgroundColor "white"
:height 56
:elevation 2}
:actions (when (and (:group-chat @chat)
(:is-active @chat))
[{:title "Add Contact to chat"
:icon res/add-icon
:showWithText true}
{:title "Remove Contact from chat"
:icon res/trash-icon
:showWithText true}
{:title "Leave Chat"
:icon res/leave-icon
:showWithText true}])
:onActionSelected (fn [position]
(case position
0 (dispatch [:show-add-participants navigator])
1 (dispatch [:show-remove-participants navigator])
2 (dispatch [:leave-group-chat navigator])))
:onIconClicked (fn []
(nav-pop navigator))}])
[list-view {:dataSource datasource
:renderScrollComponent (fn [props]
(invertible-scroll-view nil))
@ -62,4 +81,5 @@
(add-msg-color contact-by-identity))]
(r/as-element [chat-message msg])))
:style {:backgroundColor "white"}}]
[chat-message-new]]))))
(when (:is-active @chat)
[chat-message-new])]))))

View File

@ -86,28 +86,27 @@
content)]]))
(defn message-content [{:keys [content-type content outgoing text-color background-color]}]
(let [_ (log/debug color)]
[view {:style (merge {:borderRadius 6}
(if (= content-type text-content-type)
{:paddingVertical 12
:paddingHorizontal 16}
{:paddingVertical 14
:paddingHorizontal 10})
(if outgoing
{:backgroundColor "#D3EEEF"}
{:backgroundColor background-color}))}
(cond
(= content-type text-content-type)
[text {:style (merge {:fontSize 14
:fontFamily "Avenir-Roman"}
(if outgoing
{:color "#4A5258"}
{:color text-color}))}
content]
(= content-type content-type-command)
[message-content-command content]
:else [message-content-audio {:content content
:content-type content-type}])]))
[view {:style (merge {:borderRadius 6}
(if (= content-type text-content-type)
{:paddingVertical 12
:paddingHorizontal 16}
{:paddingVertical 14
:paddingHorizontal 10})
(if outgoing
{:backgroundColor "#D3EEEF"}
{:backgroundColor background-color}))}
(cond
(= content-type text-content-type)
[text {:style (merge {:fontSize 14
:fontFamily "Avenir-Roman"}
(if outgoing
{:color "#4A5258"}
{:color text-color}))}
content]
(= content-type content-type-command)
[message-content-command content]
:else [message-content-audio {:content content
:content-type content-type}])])
(defn message-delivery-status [{:keys [delivery-status]}]
[view {:style {:flexDirection "row"

View File

@ -0,0 +1,36 @@
(ns syng-im.components.chat.new-participants
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.resources :as res]
[syng-im.components.react :refer [view toolbar-android android? text-input]]
[syng-im.components.realm :refer [list-view]]
[syng-im.utils.listview :refer [to-realm-datasource]]
[syng-im.components.chats.new-participant-contact :refer [new-participant-contact]]
[reagent.core :as r]
[syng-im.navigation :refer [nav-pop]]))
(defn new-participants [{:keys [navigator]}]
(let [contacts (subscribe [:all-new-contacts])]
(fn []
(let [contacts-ds (to-realm-datasource @contacts)]
[view {:style {:flex 1
:backgroundColor "white"}}
(when android?
;; TODO add IOS version
[toolbar-android {:logo res/logo-icon
:title "Add Participants"
:titleColor "#4A5258"
:style {:backgroundColor "white"
:height 56
:elevation 2}
:actions [{:title "Add"
:icon res/v
:show "always"}]
:onActionSelected (fn [position]
(dispatch [:add-new-participants navigator]))
:navIcon res/nav-back-icon
:onIconClicked (fn []
(nav-pop navigator))}])
[list-view {:dataSource contacts-ds
:renderRow (fn [row section-id row-id]
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator]))
:style {:backgroundColor "white"}}]]))))

View File

@ -0,0 +1,36 @@
(ns syng-im.components.chat.remove-participants
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.resources :as res]
[syng-im.components.react :refer [view toolbar-android android? text-input]]
[syng-im.components.realm :refer [list-view]]
[syng-im.utils.listview :refer [to-realm-datasource]]
[syng-im.components.chats.new-participant-contact :refer [new-participant-contact]]
[reagent.core :as r]
[syng-im.navigation :refer [nav-pop]]))
(defn remove-participants [{:keys [navigator]}]
(let [contacts (subscribe [:current-chat-contacts])]
(fn []
(let [contacts-ds (to-realm-datasource @contacts)]
[view {:style {:flex 1
:backgroundColor "white"}}
(when android?
;; TODO add IOS version
[toolbar-android {:logo res/logo-icon
:title "Remove Participants"
:titleColor "#4A5258"
:style {:backgroundColor "white"
:height 56
:elevation 2}
:actions [{:title "Remove"
:icon res/trash-icon
:show "always"}]
:onActionSelected (fn [position]
(dispatch [:remove-selected-participants navigator]))
:navIcon res/nav-back-icon
:onIconClicked (fn []
(nav-pop navigator))}])
[list-view {:dataSource contacts-ds
:renderRow (fn [row section-id row-id]
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator]))
:style {:backgroundColor "white"}}]]))))

View File

@ -9,7 +9,7 @@
(defn chat-list-item [chat-obj navigator]
[touchable-highlight {:on-press (fn []
(dispatch [:show-chat (aget chat-obj "chat-id") navigator]))}
(dispatch [:show-chat (aget chat-obj "chat-id") navigator :push]))}
[view {:style {:flexDirection "row"
:width 260
:marginVertical 5}}

View File

@ -0,0 +1,24 @@
(ns syng-im.components.chats.new-participant-contact
(:require [syng-im.resources :as res]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [view]]
[syng-im.components.contact-list.contact-inner :refer [contact-inner-view]]
[syng-im.components.item-checkbox :refer [item-checkbox]]
[syng-im.utils.logging :as log]
[reagent.core :as r]))
(defn new-participant-contact [{:keys [whisper-identity] :as contact} navigator]
(let [checked (r/atom false)]
(fn []
[view {:style {:flexDirection "row"
:marginTop 5
:marginBottom 5
:paddingLeft 15
:paddingRight 15
:height 75}}
[item-checkbox {:onToggle (fn [checked?]
(reset! checked checked?)
(dispatch [:select-new-participant whisper-identity checked?]))
:checked @checked
:size 30}]
[contact-inner-view contact]])))

View File

@ -9,10 +9,11 @@
:identity-password "replace-me-with-user-entered-password"
:contacts []
:chat {:current-chat-id "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"
:command nil}
:command nil}
:chats {}
:chats-updated-signal 0
:new-group #{}})
:new-group #{}
:new-participants #{}})
(def protocol-initialized-path [:protocol-initialized])
@ -28,3 +29,4 @@
(defn chat-command-content-path [chat-id]
[:chats chat-id :command-input :content])
(def new-group-path [:new-group])
(def new-participants-path [:new-participants])

View File

@ -18,18 +18,28 @@
set-chat-command-content]]
[syng-im.handlers.sign-up :as sign-up-service]
[syng-im.models.chats :refer [create-chat]]
[syng-im.models.chats :refer [create-chat
chat-add-participants
chat-remove-participants
set-chat-active]]
[syng-im.models.chat :refer [signal-chat-updated
set-current-chat-id
current-chat-id
update-new-group-selection
update-new-participants-selection
clear-new-group
clear-new-participants
new-group-selection
set-chat-input-text]]
set-chat-input-text
new-participants-selection]]
[syng-im.utils.logging :as log]
[syng-im.protocol.api :as api]
[syng-im.constants :refer [text-content-type]]
[syng-im.navigation :refer [nav-push]]
[syng-im.utils.crypt :refer [gen-random-bytes]]))
[syng-im.navigation :refer [nav-push
nav-replace
nav-pop]]
[syng-im.utils.crypt :refer [gen-random-bytes]]
[syng-im.utils.random :as random]))
;; -- Middleware ------------------------------------------------------------
;;
@ -77,9 +87,11 @@
db))
(register-handler :navigate-to
(fn [db [action navigator route]]
(fn [db [action navigator route nav-type]]
(log/debug action route)
(nav-push navigator route)
(case nav-type
:push (nav-push navigator route)
:replace (nav-replace navigator route))
db))
;; -- Protocol --------------------------------------------------------------
@ -110,14 +122,98 @@
(save-message chat-id msg)
(signal-chat-updated db chat-id)))
(defn joined-chat-msg [chat-id from msg-id]
(let [contact-name (:name (contacts/contact-by-identity from))]
(save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or contact-name from) " received chat invitation")
:content-type text-content-type})))
(defn participant-invited-to-group-msg [chat-id identity from msg-id]
(let [inviter-name (:name (contacts/contact-by-identity from))
invitee-name (:name (contacts/contact-by-identity identity))]
(save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or inviter-name from) " invited " (or invitee-name identity))
:content-type text-content-type})))
(defn participant-removed-from-group-msg [chat-id identity from msg-id]
(let [remover-name (:name (contacts/contact-by-identity from))
removed-name (:name (contacts/contact-by-identity identity))]
(save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or remover-name from) " removed " (or removed-name identity))
:content-type text-content-type})))
(defn you-removed-from-group-msg [chat-id from msg-id]
(let [remover-name (:name (contacts/contact-by-identity from))]
(save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or remover-name from) " removed you from group chat")
:content-type text-content-type})))
(defn participant-left-group-msg [chat-id from msg-id]
(let [left-name (:name (contacts/contact-by-identity from))]
(save-message chat-id {:from "system"
:msg-id msg-id
:content (str (or left-name from) " left")
:content-type text-content-type})))
(defn removed-participant-msg [chat-id identity]
(let [contact-name (:name (contacts/contact-by-identity identity))]
(save-message chat-id {:from "system"
:msg-id (random/id)
:content (str "You've removed " (or contact-name identity))
:content-type text-content-type})))
(defn left-chat-msg [chat-id]
(save-message chat-id {:from "system"
:msg-id (random/id)
:content "You left this chat"
:content-type text-content-type}))
(register-handler :group-chat-invite-acked
(fn [db [action from group-id ack-msg-id]]
(log/debug action from group-id ack-msg-id)
(joined-chat-msg group-id from ack-msg-id)
(signal-chat-updated db group-id)))
(register-handler :participant-removed-from-group
(fn [db [action from group-id identity msg-id]]
(log/debug action msg-id from group-id identity)
(chat-remove-participants group-id [identity])
(participant-removed-from-group-msg group-id identity from msg-id)
(signal-chat-updated db group-id)))
(register-handler :you-removed-from-group
(fn [db [action from group-id msg-id]]
(log/debug action msg-id from group-id)
(you-removed-from-group-msg group-id from msg-id)
(set-chat-active group-id false)
(signal-chat-updated db group-id)))
(register-handler :participant-left-group
(fn [db [action from group-id msg-id]]
(log/debug action msg-id from group-id)
(participant-left-group-msg group-id from msg-id)
(signal-chat-updated db group-id)))
(register-handler :participant-invited-to-group
(fn [db [action from group-id identity msg-id]]
(log/debug action msg-id from group-id identity)
(participant-invited-to-group-msg group-id identity from msg-id)
(signal-chat-updated db group-id)))
(register-handler :acked-msg
(fn [db [_ from msg-id]]
(fn [db [action from msg-id]]
(log/debug action from msg-id)
(update-message! {:msg-id msg-id
:delivery-status :delivered})
(signal-chat-updated db from)))
(register-handler :msg-delivery-failed
(fn [db [_ msg-id]]
(fn [db [action msg-id]]
(log/debug action msg-id)
(update-message! {:msg-id msg-id
:delivery-status :failed})
(let [{:keys [chat-id]} (message-by-id msg-id)]
@ -128,7 +224,7 @@
(log/debug action "chat-id" chat-id "text" text)
(let [msg (if (= chat-id "console")
(sign-up-service/send-console-msg text)
(let [{msg-id :msg-id
(let [{msg-id :msg-id
{from :from
to :to} :msg} (api/send-user-msg {:to chat-id
:content text})]
@ -141,13 +237,22 @@
(save-message chat-id msg)
(signal-chat-updated db chat-id))))
(register-handler :leave-group-chat
(fn [db [action navigator]]
(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)
(signal-chat-updated db chat-id))))
(register-handler :send-chat-command
(fn [db [action chat-id command content]]
(log/debug action "chat-id" chat-id "command" command "content" content)
(let [msg (if (= chat-id "console")
(sign-up-service/send-console-command command content)
;; TODO handle command, now sends as plain message
(let [{msg-id :msg-id
(let [{msg-id :msg-id
{from :from
to :to} :msg} (api/send-user-msg {:to chat-id
:content content})]
@ -216,10 +321,10 @@
;; -- Chats --------------------------------------------------------------
(register-handler :show-chat
(fn [db [action chat-id navigator]]
(fn [db [action chat-id navigator nav-type]]
(log/debug action "chat-id" chat-id)
(let [db (set-current-chat-id db chat-id)]
(dispatch [:navigate-to navigator {:view-id :chat}])
(dispatch [:navigate-to navigator {:view-id :chat} nav-type])
db)))
(register-handler :set-sign-up-chat
@ -248,6 +353,48 @@
(nav-push navigator {:view-id :contact-list})
db))
(register-handler :select-new-participant
(fn [db [action identity add?]]
(log/debug action identity add?)
(update-new-participants-selection db identity add?)))
(register-handler :show-remove-participants
(fn [db [action navigator]]
(log/debug action)
(nav-push navigator {:view-id :remove-participants})
(clear-new-participants db)))
(register-handler :remove-selected-participants
(fn [db [action navigator]]
(log/debug action)
(let [identities (-> (new-participants-selection db)
(vec))
chat-id (current-chat-id db)]
(chat-remove-participants chat-id identities)
(nav-pop navigator)
(doseq [ident identities]
(api/group-remove-participant chat-id ident)
(removed-participant-msg chat-id ident))
(signal-chat-updated db chat-id))))
(register-handler :show-add-participants
(fn [db [action navigator]]
(log/debug action)
(nav-push navigator {:view-id :add-participants})
(clear-new-participants db)))
(register-handler :add-new-participants
(fn [db [action navigator]]
(log/debug action)
(let [identities (-> (new-participants-selection db)
(vec))
chat-id (current-chat-id db)]
(chat-add-participants chat-id identities)
(nav-pop navigator)
(doseq [ident identities]
(api/group-add-participant chat-id ident))
db)))
(register-handler :show-group-new
(fn [db [action navigator]]
(log/debug action)
@ -266,7 +413,7 @@
(vec))
group-id (api/start-group-chat identities group-name)
db (create-chat db group-id identities true group-name)]
(dispatch [:show-chat group-id navigator])
(dispatch [:show-chat group-id navigator :replace])
db)))
(register-handler :group-chat-invite-received

View File

@ -19,9 +19,15 @@
(defn update-new-group-selection [db identity add?]
(update-in db db/new-group-path (fn [new-group]
(if add?
(conj new-group identity)
(disj new-group identity)))))
(if add?
(conj new-group identity)
(disj new-group identity)))))
(defn update-new-participants-selection [db identity add?]
(update-in db db/new-participants-path (fn [new-participants]
(if add?
(conj new-participants identity)
(disj new-participants identity)))))
(defn new-group-selection [db]
(get-in db db/new-group-path))
@ -29,6 +35,12 @@
(defn clear-new-group [db]
(assoc-in db db/new-group-path #{}))
(defn new-participants-selection [db]
(get-in db db/new-participants-path))
(defn clear-new-participants [db]
(assoc-in db db/new-participants-path #{}))
(defn set-chat-input-text [db text]
(assoc-in db (db/chat-input-text-path (current-chat-id db)) text))
@ -37,5 +49,5 @@
(swap! re-frame.db/app-db (fn [db]
(signal-chat-updated db "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd")))
(current-chat-id @re-frame.db/app-db)
(current-chat-id @re-frame.db/app-db)
)

View File

@ -4,7 +4,8 @@
[clojure.string :refer [join blank?]]
[syng-im.db :as db]
[syng-im.utils.logging :as log]
[syng-im.constants :refer [group-chat-colors]]))
[syng-im.constants :refer [group-chat-colors]]
[syng-im.persistence.realm-queries :refer [include-query]]))
(defn signal-chats-updated [db]
(update-in db db/updated-chats-signal-path (fn [current]
@ -46,6 +47,7 @@
:background-color background
:text-color text}) identities group-chat-colors)]
(r/create :chats {:chat-id chat-id
:is-active true
:name chat-name
:group-chat group-chat?
:timestamp (timestamp)
@ -61,8 +63,52 @@
(r/single-cljs)
(r/list-to-array :contacts)))
(comment
(defn chat-add-participants [chat-id identities]
(r/write
(fn []
(let [contacts (-> (r/get-by-field :chats :chat-id chat-id)
(r/single)
(aget "contacts"))
colors-in-use (->> (.map contacts (fn [object index collection]
{:text-color (aget object "text-color")
:background-color (aget object "background-color")}))
(set))
colors (->> group-chat-colors
(filter (fn [color]
(not (contains? colors-in-use color)))))
new-contacts (mapv (fn [ident {:keys [background text]}]
{:identity ident
:background-color background
:text-color text}) identities colors)]
(doseq [contact new-contacts]
(.push contacts (clj->js contact)))))))
(defn chat-remove-participants [chat-id identities]
(r/write
(fn []
(let [query (include-query :identity identities)
chat (-> (r/get-by-field :chats :chat-id chat-id)
(r/single))]
(-> (aget chat "contacts")
(r/filtered query)
(r/delete))))))
(defn active-group-chats []
(let [results (-> (r/get-all :chats)
(r/filtered "group-chat = true && is-active = true"))]
(->> (.map results (fn [object index collection]
(aget object "chat-id")))
(js->clj))))
(defn set-chat-active [chat-id active?]
(r/write (fn []
(-> (r/get-by-field :chats :chat-id chat-id)
(r/single)
(aset "is-active" active?)))))
(comment
(active-group-chats)
(-> (r/get-by-field :chats :chat-id "0x04ed4c3797026cddeb7d64a54ca58142e57ea03cda21072358d67455b506db90c56d95033e3d221992f70d01922c3d90bf0697c49e4be118443d03ae4a1cd3c15c")

View File

@ -3,7 +3,10 @@
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.utils.utils :refer [log toast]]
[syng-im.persistence.realm :as realm]
[syng-im.persistence.realm :as r]))
[syng-im.persistence.realm :as r]
[syng-im.persistence.realm-queries :refer [include-query
exclude-query]]
[clojure.string :as s]))
;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
(def fake-phone-contacts? true)
@ -91,18 +94,44 @@
(-> (r/get-all :contacts)
(r/sorted :name :asc)))
(defn contacts-list-exclude [exclude-idents]
(let [query (exclude-query :whisper-identity exclude-idents)]
(-> (r/get-all :contacts)
(r/filtered query)
(r/sorted :name :asc))))
(defn contacts-list-include [include-indents]
(let [query (include-query :whisper-identity include-indents)]
(-> (r/get-all :contacts)
(r/filtered query)
(r/sorted :name :asc))))
(defn contact-by-identity [identity]
(-> (r/get-by-field :contacts :whisper-identity identity)
(r/single-cljs)))
(comment
(r/write #(create-contact {:phone-number "0543072333"
:whisper-identity "0x04ed4c3797026cddeb7d64a54ca58142e57ea03cda21072358d67455b506db90c56d95033e3d221992f70d01922c3d90bf0697c49e4be118443d03ae4a1cd3c15c"
:whisper-identity "0x043e3a8344049fb48fef030084212a9d41577a5dea18aeb4c8f285c16f783aa84e43f84c32eb8601e22827b12d5f93f14e545f9023034a0521dc18484bbbc44704"
:name "Mr. Bean"
:photo-path ""}))
(r/write #(create-contact {:phone-number "0544828649"
:whisper-identity "0x0498bcce41dbe05c6d4776ef50d12c2ef1a00d9d7f7144d174ece3dce85ca3428bf0900352abcccdc463bd2cfa4ec319cda46c2079152c4cb14d1cad9a00dd7571"
:whisper-identity "0x04e9b01298dd12c4d8f0393d7890302b25762966d825158d1fdffe124703c0efcd7f23a6cf71c466ca50b2af3d54264ea5f224a19ba7775779c1ddbcb237258c5c"
:name "Mr. Batman"
:photo-path ""}))
(r/write #(create-contact {:phone-number "0522222222"
:whisper-identity "0x0487954e7fa746d8cf787403c2c491aadad540b9bb1f0f7b8184792e91c33b6a394079295f5777ec6d4af9ad5ba24794b3ff1ec8be9ff6a708c85a163733192665"
:name "Mr. Eagle"
:photo-path ""}))
(r/write #(create-contact {:phone-number "0533333333"
:whisper-identity "0x04e43e861a6dd99ad9eee7bd58af89dcaa430188ebec8698de7b7bad54573324fff4ac5cb9bb277af317efd7abfc917b91bf48cc41e40bf70062fd79400016a1f9"
:name "Mr. PiggyBear"
:photo-path ""}))
(contacts-list)
(:new-group @re-frame.db/app-db)

View File

@ -7,6 +7,7 @@
(defn save-message [chat-id {:keys [from to msg-id content content-type outgoing] :or {outgoing false
to nil} :as msg}]
(log/debug "save-message" chat-id msg)
(when-not (r/exists? :msgs :msg-id msg-id)
(r/write
(fn []
@ -28,10 +29,12 @@
(-> (r/get-by-field :msgs :msg-id msg-id)
(r/single-cljs)))
(defn update-message! [msg]
(defn update-message! [{:keys [msg-id] :as msg}]
(log/debug "update-message!" msg)
(r/write
(fn []
(r/create :msgs msg true))))
(when (r/exists? :msgs :msg-id msg-id)
(r/create :msgs msg true)))))
(comment

View File

@ -41,7 +41,9 @@
:primaryKey :chat-id
:properties {:chat-id "string"
:name "string"
:group-chat "bool"
:group-chat {:type "bool"
:indexed true}
:is-active "bool"
:timestamp "int"
:contacts {:type "list"
:objectType "chat-contact"}}}]})
@ -92,6 +94,9 @@
false
true)))
(defn filtered [results filter-query]
(.filtered results filter-query))
(defn page [results from to]
(js/Array.prototype.slice.call results from to))
@ -111,8 +116,7 @@
(read-string value))
(defn delete [obj]
(write (fn []
(.delete realm obj))))
(.delete realm obj))
(defn exists? [schema-name field value]
(> (.-length (get-by-field schema-name field value))
@ -127,22 +131,4 @@
(comment
(write #(.create realm "msgs" (clj->js {:msg-id "12"
:content "sdfd"
:from "sdfsd"
:chat-id "56"
:content-type "fg"
:timestamp 2
:outgoing true
:to "sfs"
:delivery-status "seen"}) true))
(.addListener realm "change" (fn [& args]
(log/debug args)))
;realm.addListener('change', () => {
; // Update UI
; ...
; });
)

View File

@ -0,0 +1,19 @@
(ns syng-im.persistence.realm-queries
(:require [clojure.string :as s]
[syng-im.utils.types :refer [to-string]]))
(defn include-query [field-name values]
(->> values
(map (fn [val]
(str (to-string field-name) " == " (if (string? val)
(str "'" val "'")
val))))
(s/join " || ")))
(defn exclude-query [field-name values]
(->> values
(map (fn [val]
(str (to-string field-name) " != " (if (string? val)
(str "'" val "'")
val))))
(s/join " && ")))

View File

@ -17,8 +17,9 @@
(contains-key? [_ key]
(r/exists? :kv-store :key key))
(delete [_ key]
(-> (r/get-by-field :kv-store :key key)
(r/single)
(r/delete))))
(r/write (fn []
(-> (r/get-by-field :kv-store :key key)
(r/single)
(r/delete))))))
(def kv-store (->SimpleKvStore))

View File

@ -3,12 +3,14 @@
[syng-im.constants :refer [ethereum-rpc-url]]
[re-frame.core :refer [dispatch]]
[syng-im.models.protocol :refer [stored-identity]]
[syng-im.persistence.simple-kv-store :as kv]))
[syng-im.persistence.simple-kv-store :as kv]
[syng-im.models.chats :refer [active-group-chats]]))
(defn make-handler [db]
{:ethereum-rpc-url ethereum-rpc-url
:identity (stored-identity db)
:active-group-ids (active-group-chats)
:storage kv/kv-store
:handler (fn [{:keys [event-type] :as event}]
(log/info "Event:" (clj->js event))
@ -28,18 +30,14 @@
payload :payload} event]
(dispatch [:group-received-msg (assoc payload :from from
:group-id group-id)]))
;:group-chat-invite-acked (let [{:keys [from group-id]} event]
; (add-to-chat "group-chat" ":" (str "Received ACK for group chat invitation from " from " for group-id: " group-id)))
;:group-new-participant (let [{:keys [group-id identity from]} event]
; (add-to-chat "group-chat" ":" (str (shorten from) " added " (shorten identity) " to group chat"))
; (add-identity-to-group-list identity))
;:group-removed-participant (let [{:keys [group-id identity from]} event]
; (add-to-chat "group-chat" ":" (str (shorten from) " removed " (shorten identity) " from group chat"))
; (remove-identity-from-group-list identity))
;:removed-from-group (let [{:keys [group-id from]} event]
; (add-to-chat "group-chat" ":" (str (shorten from) " removed you from group chat")))
;:participant-left-group (let [{:keys [group-id from]} event]
; (add-to-chat "group-chat" ":" (str (shorten from) " left group chat")))
;(add-to-chat "chat" ":" (str "Don't know how to handle " event-type))
(log/info "Don't know how to handle" event-type)
))})
:group-chat-invite-acked (let [{:keys [from group-id ack-msg-id]} event]
(dispatch [:group-chat-invite-acked from group-id ack-msg-id]))
:group-new-participant (let [{:keys [group-id identity from msg-id]} event]
(dispatch [:participant-invited-to-group from group-id identity msg-id]))
:group-removed-participant (let [{:keys [group-id identity from msg-id]} event]
(dispatch [:participant-removed-from-group from group-id identity msg-id]))
:removed-from-group (let [{:keys [group-id from msg-id]} event]
(dispatch [:you-removed-from-group from group-id msg-id]))
:participant-left-group (let [{:keys [group-id from msg-id]} event]
(dispatch [:participant-left-group from group-id msg-id]))
(log/info "Don't know how to handle" event-type)))})

View File

@ -13,3 +13,6 @@
(def smile (js/require "./images/smile.png"))
(def att (js/require "./images/att.png"))
(def v (js/require "./images/v.png"))
(def add-icon (js/require "./images/add.png"))
(def trash-icon (js/require "./images/trash.png"))
(def leave-icon (js/require "./images/leave.png"))

View File

@ -8,7 +8,9 @@
chats-updated?
chat-by-id]]
[syng-im.models.messages :refer [get-messages]]
[syng-im.models.contacts :refer [contacts-list]]
[syng-im.models.contacts :refer [contacts-list
contacts-list-exclude
contacts-list-include]]
[syng-im.handlers.suggestions :refer [get-suggestions]]))
;; -- Chat --------------------------------------------------------------
@ -58,10 +60,13 @@
(register-sub :get-current-chat
(fn [db _]
(let [current-chat-id (-> (current-chat-id @db)
(reaction))
chat-updated (-> (chat-updated? @db @current-chat-id)
(reaction))]
(-> (when-let [chat-id @current-chat-id]
(chat-by-id chat-id))
(reaction)))))
(reaction
(let [_ @chat-updated]
(when-let [chat-id @current-chat-id]
(chat-by-id chat-id)))))))
;; -- User data --------------------------------------------------------------
@ -99,3 +104,31 @@
(fn [db _]
(reaction
(contacts-list))))
(register-sub :all-new-contacts
(fn [db _]
(let [current-chat-id (-> (current-chat-id @db)
(reaction))
chat (-> (when-let [chat-id @current-chat-id]
(chat-by-id chat-id))
(reaction))]
(reaction
(when @chat
(let [current-participants (->> @chat
:contacts
(map :identity))]
(contacts-list-exclude current-participants)))))))
(register-sub :current-chat-contacts
(fn [db _]
(let [current-chat-id (-> (current-chat-id @db)
(reaction))
chat (-> (when-let [chat-id @current-chat-id]
(chat-by-id chat-id))
(reaction))]
(reaction
(when @chat
(let [current-participants (->> @chat
:contacts
(map :identity))]
(contacts-list-include current-participants)))))))