BIN
android/app/src/main/res/drawable-hdpi/icon_menu_group.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
android/app/src/main/res/drawable-hdpi/icon_muted.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
android/app/src/main/res/drawable-hdpi/icon_search_gray_copy.png
Normal file
After Width: | Height: | Size: 684 B |
BIN
android/app/src/main/res/drawable-hdpi/icon_settings.png
Normal file
After Width: | Height: | Size: 945 B |
BIN
android/app/src/main/res/drawable-hdpi/icon_up.png
Normal file
After Width: | Height: | Size: 315 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_menu_group.png
Normal file
After Width: | Height: | Size: 868 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_muted.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_search_gray_copy.png
Normal file
After Width: | Height: | Size: 474 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_settings.png
Normal file
After Width: | Height: | Size: 520 B |
BIN
android/app/src/main/res/drawable-mdpi/icon_up.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
android/app/src/main/res/drawable-xhdpi/icon_menu_group.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
android/app/src/main/res/drawable-xhdpi/icon_muted.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 881 B |
BIN
android/app/src/main/res/drawable-xhdpi/icon_settings.png
Normal file
After Width: | Height: | Size: 969 B |
BIN
android/app/src/main/res/drawable-xhdpi/icon_up.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_menu_group.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_muted.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.3 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_settings.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
android/app/src/main/res/drawable-xxhdpi/icon_up.png
Normal file
After Width: | Height: | Size: 518 B |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_menu_group.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_muted.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.7 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_settings.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/icon_up.png
Normal file
After Width: | Height: | Size: 679 B |
@ -1,12 +1,11 @@
|
|||||||
(ns syng-im.components.chat
|
(ns syng-im.components.chat
|
||||||
(:require [clojure.string :as s]
|
(:require [clojure.string :as s]
|
||||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.components.react :refer [android?
|
[syng-im.components.react :refer [view
|
||||||
view
|
|
||||||
text
|
text
|
||||||
image
|
image
|
||||||
navigator
|
navigator
|
||||||
toolbar-android]]
|
touchable-highlight]]
|
||||||
[syng-im.components.realm :refer [list-view]]
|
[syng-im.components.realm :refer [list-view]]
|
||||||
[syng-im.components.styles :refer [font
|
[syng-im.components.styles :refer [font
|
||||||
title-font
|
title-font
|
||||||
@ -14,12 +13,13 @@
|
|||||||
chat-background
|
chat-background
|
||||||
online-color
|
online-color
|
||||||
selected-message-color
|
selected-message-color
|
||||||
|
separator-color
|
||||||
text1-color
|
text1-color
|
||||||
text2-color]]
|
text2-color
|
||||||
|
toolbar-background1]]
|
||||||
[syng-im.utils.logging :as log]
|
[syng-im.utils.logging :as log]
|
||||||
[syng-im.navigation :refer [nav-pop]]
|
[syng-im.navigation :refer [nav-pop]]
|
||||||
[syng-im.resources :as res]
|
[syng-im.resources :as res]
|
||||||
[syng-im.constants :refer [content-type-status]]
|
|
||||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
[syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
[syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
@ -42,7 +42,8 @@
|
|||||||
:background-color background-color))))
|
:background-color background-color))))
|
||||||
|
|
||||||
(defn chat-photo [{:keys [photo-path]}]
|
(defn chat-photo [{:keys [photo-path]}]
|
||||||
[view {:borderRadius 50}
|
[view {:margin 10
|
||||||
|
:borderRadius 50}
|
||||||
[image {:source (if (s/blank? photo-path)
|
[image {:source (if (s/blank? photo-path)
|
||||||
res/user-no-photo
|
res/user-no-photo
|
||||||
{:uri photo-path})
|
{:uri photo-path})
|
||||||
@ -53,8 +54,8 @@
|
|||||||
(defn contact-online [{:keys [online]}]
|
(defn contact-online [{:keys [online]}]
|
||||||
(when online
|
(when online
|
||||||
[view {:position "absolute"
|
[view {:position "absolute"
|
||||||
:top 20
|
:top 30
|
||||||
:left 20
|
:left 30
|
||||||
:width 20
|
:width 20
|
||||||
:height 20
|
:height 20
|
||||||
:borderRadius 50
|
:borderRadius 50
|
||||||
@ -78,8 +79,7 @@
|
|||||||
|
|
||||||
(defn typing [member]
|
(defn typing [member]
|
||||||
[view {:style {:width 260
|
[view {:style {:width 260
|
||||||
:paddingTop 2
|
:marginTop 10
|
||||||
:paddingBottom 8
|
|
||||||
:paddingLeft 8
|
:paddingLeft 8
|
||||||
:paddingRight 8
|
:paddingRight 8
|
||||||
:alignItems "flex-start"
|
:alignItems "flex-start"
|
||||||
@ -95,139 +95,188 @@
|
|||||||
(str member " is typing")]]])
|
(str member " is typing")]]])
|
||||||
|
|
||||||
(defn typing-all []
|
(defn typing-all []
|
||||||
[view {:style {:marginBottom 12}}
|
[view {:style {:marginBottom 20}}
|
||||||
(for [member ["Geoff" "Justas"]]
|
(for [member ["Geoff" "Justas"]]
|
||||||
^{:key member} [typing member])])
|
^{:key member} [typing member])])
|
||||||
|
|
||||||
(defn toolbar-content-chat [chat]
|
(defn action-view [action]
|
||||||
(let [group? (:group-chat chat)]
|
[touchable-highlight {:on-press (fn []
|
||||||
|
(dispatch [:set-show-actions false])
|
||||||
|
((:handler action)))
|
||||||
|
:underlay-color :transparent}
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:height 56}}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}
|
||||||
|
[image {:source {:uri (:icon action)}
|
||||||
|
:style (:icon-style action)}]]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:flexDirection "row"
|
:alignItems "flex-start"
|
||||||
:backgroundColor "transparent"}}
|
:justifyContent "center"}}
|
||||||
[view {:style {:flex 1
|
[text {:style {:marginTop -2.5
|
||||||
:alignItems "flex-start"
|
:color text1-color
|
||||||
:justifyContent "center"
|
:fontSize 14
|
||||||
:marginRight 112}}
|
:fontFamily font}}
|
||||||
[text {:style {:marginTop -2.5
|
(:title action)]
|
||||||
:color text1-color
|
(when-let [subtitle (:subtitle action)]
|
||||||
:fontSize 16
|
[text {:style {:marginTop 1
|
||||||
|
:color text2-color
|
||||||
|
:fontSize 12
|
||||||
|
:fontFamily font}}
|
||||||
|
subtitle])]]])
|
||||||
|
|
||||||
|
(defn actions-list-view [navigator chat]
|
||||||
|
(when-let [actions (when (and (:group-chat chat)
|
||||||
|
(:is-active chat))
|
||||||
|
[{:title "Add Contact to chat"
|
||||||
|
:icon "icon_menu_group"
|
||||||
|
:icon-style {:width 25
|
||||||
|
:height 19}
|
||||||
|
:handler #(dispatch [:show-add-participants navigator])}
|
||||||
|
{:title "Remove Contact from chat"
|
||||||
|
:subtitle "Alex, John"
|
||||||
|
:icon "icon_search_gray_copy"
|
||||||
|
:icon-style {:width 17
|
||||||
|
:height 17}
|
||||||
|
:handler #(dispatch [:show-remove-participants navigator])}
|
||||||
|
{:title "Leave Chat"
|
||||||
|
:icon "icon_muted"
|
||||||
|
:icon-style {:width 18
|
||||||
|
:height 21}
|
||||||
|
:handler #(dispatch [:leave-group-chat navigator])}
|
||||||
|
{:title "Settings"
|
||||||
|
:subtitle "Not implemented"
|
||||||
|
:icon "icon_settings"
|
||||||
|
:icon-style {:width 20
|
||||||
|
:height 13}
|
||||||
|
:handler (fn [] )}])]
|
||||||
|
[view {:style {:backgroundColor toolbar-background1
|
||||||
|
:elevation 2
|
||||||
|
:position "absolute"
|
||||||
|
:top 56
|
||||||
|
:left 0
|
||||||
|
:right 0}}
|
||||||
|
[view {:style {:marginLeft 16
|
||||||
|
:height 1.5
|
||||||
|
:backgroundColor separator-color}}]
|
||||||
|
[view {:style {:marginVertical 10}}
|
||||||
|
(for [action actions]
|
||||||
|
^{:key action} [action-view action])]]))
|
||||||
|
|
||||||
|
(defn overlay [{:keys [on-click-outside]} items]
|
||||||
|
[view {:position "absolute"
|
||||||
|
:top 0
|
||||||
|
:bottom 0
|
||||||
|
:left 0
|
||||||
|
:right 0}
|
||||||
|
[touchable-highlight {:on-press on-click-outside
|
||||||
|
:underlay-color :transparent
|
||||||
|
:style {:flex 1}}
|
||||||
|
[view nil]]
|
||||||
|
items])
|
||||||
|
|
||||||
|
(defn actions-view [navigator chat]
|
||||||
|
[overlay {:on-click-outside (fn []
|
||||||
|
(dispatch [:set-show-actions false]))}
|
||||||
|
[actions-list-view navigator chat]])
|
||||||
|
|
||||||
|
(defn toolbar [navigator chat show-actions]
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:height 56
|
||||||
|
:backgroundColor toolbar-background1
|
||||||
|
:elevation 2}}
|
||||||
|
(when (not show-actions)
|
||||||
|
[touchable-highlight {:on-press (fn []
|
||||||
|
(nav-pop navigator))
|
||||||
|
:underlay-color :transparent}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56}
|
||||||
|
[image {:source {:uri "icon_back"}
|
||||||
|
:style {:marginTop 21
|
||||||
|
:marginLeft 23
|
||||||
|
:width 8
|
||||||
|
:height 14}}]]])
|
||||||
|
[view {:style {:flex 1
|
||||||
|
:marginLeft (if show-actions 16 0)
|
||||||
|
:alignItems "flex-start"
|
||||||
|
:justifyContent "center"}}
|
||||||
|
[text {:style {:marginTop -2.5
|
||||||
|
:color text1-color
|
||||||
|
:fontSize 16
|
||||||
|
:fontFamily font}}
|
||||||
|
(or (chat :name)
|
||||||
|
"Chat name")]
|
||||||
|
(if (:group-chat chat)
|
||||||
|
[view {:style {:flexDirection "row"}}
|
||||||
|
[image {:source {:uri "icon_group"}
|
||||||
|
:style {:marginTop 4
|
||||||
|
:width 14
|
||||||
|
:height 9}}]
|
||||||
|
[text {:style {:marginTop -0.5
|
||||||
|
:marginLeft 4
|
||||||
|
:fontFamily font
|
||||||
|
:fontSize 12
|
||||||
|
:color text2-color}}
|
||||||
|
(str (count (:contacts chat))
|
||||||
|
(if (< 1 (count (:contacts chat)))
|
||||||
|
" members"
|
||||||
|
" member")
|
||||||
|
", " (count (:contacts chat)) " active")]]
|
||||||
|
[text {:style {:marginTop 1
|
||||||
|
:color text2-color
|
||||||
|
:fontSize 12
|
||||||
:fontFamily font}}
|
:fontFamily font}}
|
||||||
(or (chat :name)
|
"Active a minute ago"])]
|
||||||
"Chat name")]
|
(if show-actions
|
||||||
(if group?
|
[touchable-highlight {:on-press (fn []
|
||||||
[view {:style {:flexDirection "row"}}
|
(dispatch [:set-show-actions false]))
|
||||||
[image {:source {:uri "icon_group"}
|
:underlay-color :transparent}
|
||||||
:style {:marginTop 4
|
[view {:style {:width 56
|
||||||
:width 14
|
:height 56}}
|
||||||
:height 9}}]
|
[image {:source {:uri "icon_up"}
|
||||||
[text {:style {:marginTop -0.5
|
:style {:marginTop 23
|
||||||
:marginLeft 4
|
:marginLeft 21
|
||||||
:fontFamily font
|
:width 14
|
||||||
:fontSize 12
|
:height 8}}]]]
|
||||||
:color text2-color}}
|
[touchable-highlight {:on-press (fn []
|
||||||
(str (count (:contacts chat))
|
(dispatch [:set-show-actions true]))
|
||||||
(if (< 1 (count (:contacts chat)))
|
:underlay-color :transparent}
|
||||||
" members"
|
[view {:style {:width 56
|
||||||
" member")
|
:height 56}}
|
||||||
", " (count (:contacts chat)) " active")]]
|
[chat-photo {}]
|
||||||
[text {:style {:marginTop 1
|
[contact-online {:online true}]]])])
|
||||||
:color text2-color
|
|
||||||
:fontSize 12
|
|
||||||
:fontFamily font}}
|
|
||||||
"Active a minute ago"])]
|
|
||||||
(when-not group?
|
|
||||||
[view {:style {:position "absolute"
|
|
||||||
:top 10
|
|
||||||
:right 66}}
|
|
||||||
[chat-photo {}]
|
|
||||||
[contact-online {:online true}]])]))
|
|
||||||
|
|
||||||
(defn chat [{:keys [navigator]}]
|
(defn chat [{:keys [navigator]}]
|
||||||
(let [messages (subscribe [:get-chat-messages])
|
(let [messages (subscribe [:get-chat-messages])
|
||||||
chat (subscribe [:get-current-chat])]
|
chat (subscribe [:get-current-chat])
|
||||||
|
show-actions-atom (subscribe [:show-actions])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [msgs @messages
|
(let [msgs @messages
|
||||||
;_ (log/debug "messages=" msgs)
|
;_ (log/debug "messages=" msgs)
|
||||||
;; temp to show first status
|
;; temp
|
||||||
msgs-clj (as-> (js->clj msgs) ms
|
typing (:group-chat @chat)
|
||||||
(assoc ms "-1"
|
|
||||||
{:msg-id "-1"
|
|
||||||
:content (str "The brash businessman’s braggadocio "
|
|
||||||
"and public exchange with candidates "
|
|
||||||
"in the US presidential election")
|
|
||||||
:delivery-status "seen"
|
|
||||||
:from "Status"
|
|
||||||
:chat-id "-"
|
|
||||||
:content-type content-type-status
|
|
||||||
:timestamp 1
|
|
||||||
"outgoing" false
|
|
||||||
:to nil})
|
|
||||||
(reduce (fn [items [n m]]
|
|
||||||
(assoc items (.parseInt js/window n) m
|
|
||||||
;; (assoc m "from" (if (< 0.5 (rand))
|
|
||||||
;; "Status"
|
|
||||||
;; "abc"))
|
|
||||||
))
|
|
||||||
{} ms)
|
|
||||||
(into (sorted-map) ms)
|
|
||||||
(map (fn [[n current] [_ next]]
|
|
||||||
[n (-> current
|
|
||||||
(assoc :same-author
|
|
||||||
(if next
|
|
||||||
(= (get current "from") (get next "from"))
|
|
||||||
true))
|
|
||||||
(assoc :same-direction
|
|
||||||
(if next
|
|
||||||
(= (get current "outgoing") (get next "outgoing"))
|
|
||||||
true))
|
|
||||||
(assoc :last-msg (= 0 n)))
|
|
||||||
current])
|
|
||||||
ms (conj (vec (rest ms)) nil))
|
|
||||||
(reduce (fn [items [n m]]
|
|
||||||
(assoc items n m))
|
|
||||||
{} ms))
|
|
||||||
msgs (clj->js msgs-clj)
|
|
||||||
;; end temp
|
;; end temp
|
||||||
datasource (to-realm-datasource msgs)
|
datasource (to-realm-datasource msgs)
|
||||||
contacts (:contacts @chat)
|
contacts (:contacts @chat)
|
||||||
contact-by-identity (contacts-by-identity contacts)]
|
contact-by-identity (contacts-by-identity contacts)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor chat-background}}
|
:backgroundColor chat-background}}
|
||||||
(when android?
|
[toolbar navigator @chat @show-actions-atom]
|
||||||
;; TODO add IOS version
|
(let [last-msg-id (:last-msg-id @chat)]
|
||||||
[toolbar-android {:navIcon {:uri "icon_back"}
|
[list-view {:dataSource datasource
|
||||||
:style {:backgroundColor color-white
|
:renderScrollComponent (fn [props]
|
||||||
:height 56
|
(invertible-scroll-view (js->clj props)))
|
||||||
:elevation 2}
|
:renderRow (fn [row section-id row-id]
|
||||||
:actions (when (and (:group-chat @chat)
|
(let [msg (-> (js->clj row :keywordize-keys true)
|
||||||
(:is-active @chat))
|
(add-msg-color contact-by-identity)
|
||||||
[{:title "Add Contact to chat"
|
(assoc :group-chat (:group-chat @chat))
|
||||||
:icon res/add-icon
|
(assoc :typing typing))]
|
||||||
:showWithText true}
|
(r/as-element [chat-message msg last-msg-id])))}])
|
||||||
{: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))}
|
|
||||||
[toolbar-content-chat @chat]])
|
|
||||||
[list-view {:dataSource datasource
|
|
||||||
:renderScrollComponent (fn [props]
|
|
||||||
(invertible-scroll-view (js->clj props)))
|
|
||||||
:renderRow (fn [row section-id row-id]
|
|
||||||
(let [msg (-> (js->clj row :keywordize-keys true)
|
|
||||||
(add-msg-color contact-by-identity)
|
|
||||||
(assoc :group-chat (:group-chat @chat)))]
|
|
||||||
(r/as-element [chat-message msg])))
|
|
||||||
:style {:backgroundColor "white"}}]
|
|
||||||
(when (:group-chat @chat)
|
(when (:group-chat @chat)
|
||||||
[typing-all])
|
[typing-all])
|
||||||
(when (:is-active @chat)
|
(when (:is-active @chat)
|
||||||
[chat-message-new])]))))
|
[chat-message-new])
|
||||||
|
(when @show-actions-atom
|
||||||
|
[actions-view navigator @chat])]))))
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
text
|
text
|
||||||
image
|
image
|
||||||
touchable-highlight
|
touchable-highlight
|
||||||
navigator
|
navigator]]
|
||||||
toolbar-android]]
|
|
||||||
[syng-im.components.styles :refer [font
|
[syng-im.components.styles :refer [font
|
||||||
color-light-blue-transparent
|
color-light-blue-transparent
|
||||||
color-white
|
color-white
|
||||||
@ -287,7 +286,7 @@
|
|||||||
|
|
||||||
(defn incoming-group-message-body [{:keys [msg-id from content content-type outgoing
|
(defn incoming-group-message-body [{:keys [msg-id from content content-type outgoing
|
||||||
delivery-status selected new-day same-author
|
delivery-status selected new-day same-author
|
||||||
same-direction last-msg]}]
|
same-direction last-msg typing]}]
|
||||||
(let [delivery-status :seen-by-everyone]
|
(let [delivery-status :seen-by-everyone]
|
||||||
[view {:style {:flexDirection "column"}}
|
[view {:style {:flexDirection "column"}}
|
||||||
(when selected
|
(when selected
|
||||||
@ -306,7 +305,7 @@
|
|||||||
:else 10)
|
:else 10)
|
||||||
:paddingRight 8
|
:paddingRight 8
|
||||||
:paddingLeft 8}
|
:paddingLeft 8}
|
||||||
(when last-msg
|
(when (and last-msg (not typing))
|
||||||
{:paddingBottom 20}))}
|
{:paddingBottom 20}))}
|
||||||
[view {:style {:width 24}}
|
[view {:style {:width 24}}
|
||||||
(when (not same-author)
|
(when (not same-author)
|
||||||
@ -327,7 +326,7 @@
|
|||||||
[message-delivery-status {:delivery-status delivery-status}])]]]))
|
[message-delivery-status {:delivery-status delivery-status}])]]]))
|
||||||
|
|
||||||
(defn message-body [{:keys [msg-id content content-type outgoing delivery-status
|
(defn message-body [{:keys [msg-id content content-type outgoing delivery-status
|
||||||
group-chat new-day same-author same-direction last-msg]}]
|
group-chat new-day same-author same-direction last-msg typing]}]
|
||||||
(let [delivery-status :seen]
|
(let [delivery-status :seen]
|
||||||
[view {:style (merge {:flexDirection "column"
|
[view {:style (merge {:flexDirection "column"
|
||||||
:width 260
|
:width 260
|
||||||
@ -343,7 +342,7 @@
|
|||||||
:alignItems "flex-end"}
|
:alignItems "flex-end"}
|
||||||
{:alignItems "flex-start"
|
{:alignItems "flex-start"
|
||||||
:alignSelf "flex-start"})
|
:alignSelf "flex-start"})
|
||||||
(when last-msg
|
(when (and last-msg (not typing))
|
||||||
{:paddingBottom 20}))}
|
{:paddingBottom 20}))}
|
||||||
[message-content {:msg-id msg-id
|
[message-content {:msg-id msg-id
|
||||||
:content-type content-type
|
:content-type content-type
|
||||||
@ -353,22 +352,26 @@
|
|||||||
(when (and outgoing delivery-status)
|
(when (and outgoing delivery-status)
|
||||||
[message-delivery-status {:delivery-status delivery-status}])]))
|
[message-delivery-status {:delivery-status delivery-status}])]))
|
||||||
|
|
||||||
(defn chat-message [{:keys [msg-id from content content-type outgoing delivery-status date new-day group-chat selected same-author same-direction last-msg] :as msg}]
|
(defn chat-message [{:keys [msg-id from content content-type outgoing delivery-status
|
||||||
|
date new-day group-chat selected same-author same-direction
|
||||||
|
last-msg typing] :as msg}
|
||||||
|
last-msg-id]
|
||||||
[view {}
|
[view {}
|
||||||
(when new-day
|
(when new-day
|
||||||
[message-date {:date date}])
|
[message-date {:date date}])
|
||||||
(let [msg-data {:msg-id msg-id
|
(let [msg-data {:msg-id msg-id
|
||||||
:from from
|
:from from
|
||||||
:content content
|
:content content
|
||||||
:content-type content-type
|
:content-type content-type
|
||||||
:outgoing outgoing
|
:outgoing outgoing
|
||||||
:delivery-status (keyword delivery-status)
|
:delivery-status (keyword delivery-status)
|
||||||
:group-chat group-chat
|
:group-chat group-chat
|
||||||
:selected selected
|
:selected selected
|
||||||
:new-day new-day
|
:new-day new-day
|
||||||
:same-author same-author
|
:same-author same-author
|
||||||
:same-direction same-direction
|
:same-direction same-direction
|
||||||
:last-msg last-msg}]
|
:last-msg (= last-msg-id msg-id)
|
||||||
|
:typing typing}]
|
||||||
[view {}
|
[view {}
|
||||||
(when (= content-type content-type-status)
|
(when (= content-type content-type-status)
|
||||||
[message-content-status from content])
|
[message-content-status from content])
|
||||||
|
@ -1,35 +1,39 @@
|
|||||||
(ns syng-im.components.chat.new-participants
|
(ns syng-im.components.chat.new-participants
|
||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.resources :as res]
|
[syng-im.resources :as res]
|
||||||
[syng-im.components.react :refer [view toolbar-android android? text-input]]
|
[syng-im.components.react :refer [view android? text-input text image
|
||||||
|
touchable-highlight]]
|
||||||
[syng-im.components.realm :refer [list-view]]
|
[syng-im.components.realm :refer [list-view]]
|
||||||
|
[syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
toolbar-background1]]
|
||||||
|
[syng-im.components.toolbar :refer [toolbar]]
|
||||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
[syng-im.components.chats.new-participant-contact :refer [new-participant-contact]]
|
[syng-im.components.chats.new-participant-contact :refer [new-participant-contact]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[syng-im.navigation :refer [nav-pop]]))
|
[syng-im.navigation :refer [nav-pop]]))
|
||||||
|
|
||||||
|
(defn new-participants-toolbar [navigator]
|
||||||
|
[toolbar {:navigator navigator
|
||||||
|
:title "Add Participants"
|
||||||
|
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||||
|
:style {:width 20
|
||||||
|
:height 18}}
|
||||||
|
:handler (fn []
|
||||||
|
(dispatch [:add-new-participants navigator]))}}])
|
||||||
|
|
||||||
(defn new-participants [{:keys [navigator]}]
|
(defn new-participants [{:keys [navigator]}]
|
||||||
(let [contacts (subscribe [:all-new-contacts])]
|
(let [contacts (subscribe [:all-new-contacts])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [contacts-ds (to-realm-datasource @contacts)]
|
(let [contacts-ds (to-realm-datasource @contacts)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor "white"}}
|
||||||
(when android?
|
[new-participants-toolbar navigator]
|
||||||
;; 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
|
[list-view {:dataSource contacts-ds
|
||||||
:renderRow (fn [row section-id row-id]
|
:renderRow (fn [row section-id row-id]
|
||||||
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator]))
|
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator]))
|
||||||
|
@ -1,35 +1,39 @@
|
|||||||
(ns syng-im.components.chat.remove-participants
|
(ns syng-im.components.chat.remove-participants
|
||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.resources :as res]
|
[syng-im.resources :as res]
|
||||||
[syng-im.components.react :refer [view toolbar-android android? text-input]]
|
[syng-im.components.react :refer [view text-input text image
|
||||||
|
touchable-highlight]]
|
||||||
[syng-im.components.realm :refer [list-view]]
|
[syng-im.components.realm :refer [list-view]]
|
||||||
|
[syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
toolbar-background1]]
|
||||||
|
[syng-im.components.toolbar :refer [toolbar]]
|
||||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
[syng-im.components.chats.new-participant-contact :refer [new-participant-contact]]
|
[syng-im.components.chats.new-participant-contact :refer [new-participant-contact]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[syng-im.navigation :refer [nav-pop]]))
|
[syng-im.navigation :refer [nav-pop]]))
|
||||||
|
|
||||||
|
(defn remove-participants-toolbar [navigator]
|
||||||
|
[toolbar {:navigator navigator
|
||||||
|
:title "Remove Participants"
|
||||||
|
:action {:image {:source res/trash-icon ;; {:uri "icon_search"}
|
||||||
|
:style {:width 22
|
||||||
|
:height 30}}
|
||||||
|
:handler (fn []
|
||||||
|
(dispatch [:remove-selected-participants navigator]))}}])
|
||||||
|
|
||||||
(defn remove-participants [{:keys [navigator]}]
|
(defn remove-participants [{:keys [navigator]}]
|
||||||
(let [contacts (subscribe [:current-chat-contacts])]
|
(let [contacts (subscribe [:current-chat-contacts])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [contacts-ds (to-realm-datasource @contacts)]
|
(let [contacts-ds (to-realm-datasource @contacts)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor "white"}}
|
||||||
(when android?
|
[remove-participants-toolbar navigator]
|
||||||
;; 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
|
[list-view {:dataSource contacts-ds
|
||||||
:renderRow (fn [row section-id row-id]
|
:renderRow (fn [row section-id row-id]
|
||||||
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator]))
|
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator]))
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
view
|
view
|
||||||
text
|
text
|
||||||
image
|
image
|
||||||
navigator
|
touchable-highlight
|
||||||
toolbar-android]]
|
navigator]]
|
||||||
[syng-im.components.realm :refer [list-view]]
|
[syng-im.components.realm :refer [list-view]]
|
||||||
[syng-im.utils.logging :as log]
|
[syng-im.utils.logging :as log]
|
||||||
[syng-im.navigation :refer [nav-pop]]
|
[syng-im.navigation :refer [nav-pop]]
|
||||||
@ -22,8 +22,19 @@
|
|||||||
color-blue
|
color-blue
|
||||||
text1-color
|
text1-color
|
||||||
text2-color]]
|
text2-color]]
|
||||||
|
[syng-im.components.toolbar :refer [toolbar]]
|
||||||
[syng-im.components.icons.ionicons :refer [icon]]))
|
[syng-im.components.icons.ionicons :refer [icon]]))
|
||||||
|
|
||||||
|
(defn chats-list-toolbar []
|
||||||
|
[toolbar {:nav-action {:image {:source {:uri "icon_hamburger"}
|
||||||
|
:style {:width 16
|
||||||
|
:height 12}}
|
||||||
|
:handler (fn [])}
|
||||||
|
:title "Chats"
|
||||||
|
:action {:image {:source {:uri "icon_search"}
|
||||||
|
:style {:width 17
|
||||||
|
:height 17}}
|
||||||
|
:handler (fn [])}}])
|
||||||
|
|
||||||
(defn chats-list [{:keys [navigator]}]
|
(defn chats-list [{:keys [navigator]}]
|
||||||
(let [chats (subscribe [:get-chats])]
|
(let [chats (subscribe [:get-chats])]
|
||||||
@ -33,27 +44,7 @@
|
|||||||
datasource (to-realm-datasource chats)]
|
datasource (to-realm-datasource chats)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor "white"}}
|
||||||
(when android?
|
[chats-list-toolbar]
|
||||||
;; TODO add IOS version
|
|
||||||
[toolbar-android {:navIcon {:uri "icon_hamburger"}
|
|
||||||
:style {:backgroundColor color-white
|
|
||||||
:height 56
|
|
||||||
:elevation 2}
|
|
||||||
:onIconClicked (fn []
|
|
||||||
(nav-pop navigator))
|
|
||||||
:actions [{:title "Search"
|
|
||||||
:icon {:uri "icon_search"}
|
|
||||||
:show "always"}]}
|
|
||||||
[view {:style {:flex 1
|
|
||||||
:alignItems "center"
|
|
||||||
:justifyContent "center"
|
|
||||||
:marginRight 112
|
|
||||||
:backgroundColor "transparent"}}
|
|
||||||
[text {:style {:marginTop -2.5
|
|
||||||
:color text1-color
|
|
||||||
:fontSize 16
|
|
||||||
:fontFamily font}}
|
|
||||||
"Chats"]]])
|
|
||||||
[list-view {:dataSource datasource
|
[list-view {:dataSource datasource
|
||||||
:renderRow (fn [row section-id row-id]
|
:renderRow (fn [row section-id row-id]
|
||||||
(r/as-element [chat-list-item row navigator]))
|
(r/as-element [chat-list-item row navigator]))
|
||||||
|
@ -2,55 +2,42 @@
|
|||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.resources :as res]
|
[syng-im.resources :as res]
|
||||||
[syng-im.components.react :refer [view
|
[syng-im.components.react :refer [view
|
||||||
toolbar-android
|
|
||||||
android?
|
|
||||||
text-input
|
text-input
|
||||||
text
|
text
|
||||||
image
|
image
|
||||||
touchable-highlight]]
|
touchable-highlight]]
|
||||||
[syng-im.components.styles :refer [font
|
[syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
color-purple
|
||||||
text1-color
|
text1-color
|
||||||
text2-color
|
text2-color
|
||||||
color-white
|
toolbar-background1]]
|
||||||
color-purple]]
|
[syng-im.components.toolbar :refer [toolbar]]
|
||||||
[syng-im.components.realm :refer [list-view]]
|
[syng-im.components.realm :refer [list-view]]
|
||||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
[syng-im.components.chats.new-group-contact :refer [new-group-contact]]
|
[syng-im.components.chats.new-group-contact :refer [new-group-contact]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[syng-im.navigation :refer [nav-pop]]))
|
[syng-im.navigation :refer [nav-pop]]))
|
||||||
|
|
||||||
|
(defn new-group-toolbar [navigator group-name]
|
||||||
|
[toolbar {:navigator navigator
|
||||||
|
:title "New group chat"
|
||||||
|
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||||
|
:style {:width 20
|
||||||
|
:height 18}}
|
||||||
|
:handler (fn []
|
||||||
|
(dispatch [:create-new-group group-name navigator]))}}])
|
||||||
|
|
||||||
(defn new-group [{:keys [navigator]}]
|
(defn new-group [{:keys [navigator]}]
|
||||||
(let [contacts (subscribe [:all-contacts])
|
(let [contacts (subscribe [:all-contacts])
|
||||||
group-name (atom nil)]
|
group-name (r/atom nil)]
|
||||||
(fn []
|
(fn [{:keys [navigator]}]
|
||||||
(let [contacts-ds (to-realm-datasource @contacts)]
|
(let [contacts-ds (to-realm-datasource @contacts)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:flexDirection "column"
|
:flexDirection "column"
|
||||||
:backgroundColor color-white}}
|
:backgroundColor color-white}}
|
||||||
(when android?
|
[new-group-toolbar navigator @group-name]
|
||||||
;; TODO add IOS version
|
|
||||||
[toolbar-android {:navIcon {:uri "icon_back"}
|
|
||||||
:style {:backgroundColor color-white
|
|
||||||
:height 56
|
|
||||||
:elevation 2}
|
|
||||||
:onIconClicked (fn []
|
|
||||||
(nav-pop navigator))
|
|
||||||
:actions [{:title "Create"
|
|
||||||
;; :icon res/icon-ok
|
|
||||||
:show "always"
|
|
||||||
:showWithText true}]
|
|
||||||
:onActionSelected (fn [position]
|
|
||||||
(dispatch [:create-new-group @group-name navigator]))}
|
|
||||||
[view {:style {:flex 1
|
|
||||||
:alignItems "center"
|
|
||||||
:justifyContent "center"
|
|
||||||
:marginRight 112
|
|
||||||
:backgroundColor "transparent"}}
|
|
||||||
[text {:style {:marginTop -2.5
|
|
||||||
:color text1-color
|
|
||||||
:fontSize 16
|
|
||||||
:fontFamily font}}
|
|
||||||
"New group chat"]]])
|
|
||||||
[view {:style {:marginHorizontal 16}}
|
[view {:style {:marginHorizontal 16}}
|
||||||
[text {:style {:marginTop 24
|
[text {:style {:marginTop 24
|
||||||
:marginBottom 16
|
:marginBottom 16
|
||||||
|
@ -4,9 +4,19 @@
|
|||||||
[natal-shell.core :refer [with-error-view]])
|
[natal-shell.core :refer [with-error-view]])
|
||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.components.react :refer [view text image touchable-highlight
|
[syng-im.components.react :refer [view text image touchable-highlight
|
||||||
navigator list-view toolbar-android
|
navigator list-view
|
||||||
list-item]]
|
list-item]]
|
||||||
[syng-im.components.contact-list.contact :refer [contact-view]]
|
[syng-im.components.contact-list.contact :refer [contact-view]]
|
||||||
|
[syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
toolbar-background2]]
|
||||||
|
[syng-im.components.toolbar :refer [toolbar]]
|
||||||
|
[syng-im.navigation :refer [nav-pop]]
|
||||||
[syng-im.resources :as res]
|
[syng-im.resources :as res]
|
||||||
[syng-im.utils.logging :as log]))
|
[syng-im.utils.logging :as log]))
|
||||||
|
|
||||||
@ -19,18 +29,22 @@
|
|||||||
(not= row1 row2))})
|
(not= row1 row2))})
|
||||||
contacts))
|
contacts))
|
||||||
|
|
||||||
|
(defn contact-list-toolbar [navigator]
|
||||||
|
[toolbar {:navigator navigator
|
||||||
|
:title "Contacts"
|
||||||
|
:background-color toolbar-background2
|
||||||
|
:action {:image {:source {:uri "icon_search"}
|
||||||
|
:style {:width 17
|
||||||
|
:height 17}}
|
||||||
|
:handler (fn [])}}])
|
||||||
|
|
||||||
(defn contact-list [{:keys [navigator]}]
|
(defn contact-list [{:keys [navigator]}]
|
||||||
(let [contacts (subscribe [:get-contacts])]
|
(let [contacts (subscribe [:get-contacts])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [contacts-ds (get-data-source @contacts)]
|
(let [contacts-ds (get-data-source @contacts)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor "white"}}
|
||||||
[toolbar-android {:logo res/logo-icon
|
[contact-list-toolbar navigator]
|
||||||
:title "Contacts"
|
|
||||||
:titleColor "#4A5258"
|
|
||||||
:style {:backgroundColor "white"
|
|
||||||
:height 56
|
|
||||||
:elevation 2}}]
|
|
||||||
(when contacts-ds
|
(when contacts-ds
|
||||||
[list-view {:dataSource contacts-ds
|
[list-view {:dataSource contacts-ds
|
||||||
:renderRow (partial render-row navigator)
|
:renderRow (partial render-row navigator)
|
||||||
|
@ -12,10 +12,14 @@
|
|||||||
(def color-light-blue "#bbc4cb")
|
(def color-light-blue "#bbc4cb")
|
||||||
(def color-light-blue-transparent "#bbc4cb32")
|
(def color-light-blue-transparent "#bbc4cb32")
|
||||||
(def color-dark-mint "#5fc48d")
|
(def color-dark-mint "#5fc48d")
|
||||||
|
(def color-light-gray "#EEF2F5")
|
||||||
|
|
||||||
(def text1-color color-black)
|
(def text1-color color-black)
|
||||||
(def text2-color color-gray)
|
(def text2-color color-gray)
|
||||||
(def online-color color-blue)
|
(def online-color color-blue)
|
||||||
(def new-messages-count-color "#7099e632")
|
(def new-messages-count-color "#7099e632")
|
||||||
(def chat-background "#EBF0F4")
|
(def chat-background color-light-gray)
|
||||||
(def selected-message-color "#E4E9ED")
|
(def selected-message-color "#E4E9ED")
|
||||||
|
(def separator-color "#0000001f")
|
||||||
|
(def toolbar-background1 color-white)
|
||||||
|
(def toolbar-background2 color-light-gray)
|
||||||
|
58
src/syng_im/components/toolbar.cljs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
(ns syng-im.components.toolbar
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.resources :as res]
|
||||||
|
[syng-im.components.react :refer [view
|
||||||
|
text-input
|
||||||
|
text
|
||||||
|
image
|
||||||
|
touchable-highlight]]
|
||||||
|
[syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
color-purple
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
toolbar-background1]]
|
||||||
|
[syng-im.components.realm :refer [list-view]]
|
||||||
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
|
[reagent.core :as r]
|
||||||
|
[syng-im.navigation :refer [nav-pop]]))
|
||||||
|
|
||||||
|
(defn toolbar [{:keys [navigator title nav-action action background-color]}]
|
||||||
|
[view {:style {:flexDirection "row"
|
||||||
|
:backgroundColor (or background-color toolbar-background1)
|
||||||
|
:height 56
|
||||||
|
:elevation 2}}
|
||||||
|
(if nav-action
|
||||||
|
[touchable-highlight {:on-press (:handler nav-action)
|
||||||
|
:underlay-color :transparent}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}
|
||||||
|
[image (:image nav-action)]]]
|
||||||
|
[touchable-highlight {:on-press (fn []
|
||||||
|
(nav-pop navigator))
|
||||||
|
:underlay-color :transparent}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56}
|
||||||
|
[image {:source {:uri "icon_back"}
|
||||||
|
:style {:marginTop 21
|
||||||
|
:marginLeft 23
|
||||||
|
:width 8
|
||||||
|
:height 14}}]]])
|
||||||
|
[view {:style {:flex 1
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}}
|
||||||
|
[text {:style {:marginTop -2.5
|
||||||
|
:color text1-color
|
||||||
|
:fontSize 16
|
||||||
|
:fontFamily font}}
|
||||||
|
title]]
|
||||||
|
[touchable-highlight {:on-press (:handler action)
|
||||||
|
:underlay-color :transparent}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}
|
||||||
|
[image (:image action)]]]])
|
@ -9,9 +9,11 @@
|
|||||||
:identity-password "replace-me-with-user-entered-password"
|
:identity-password "replace-me-with-user-entered-password"
|
||||||
:contacts []
|
:contacts []
|
||||||
:chat {:current-chat-id "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"
|
:chat {:current-chat-id "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd"
|
||||||
:command nil}
|
:command nil
|
||||||
|
:last-message nil}
|
||||||
:chats {}
|
:chats {}
|
||||||
:chats-updated-signal 0
|
:chats-updated-signal 0
|
||||||
|
:show-actions false
|
||||||
:new-group #{}
|
:new-group #{}
|
||||||
:new-participants #{}
|
:new-participants #{}
|
||||||
:signed-up false})
|
:signed-up false})
|
||||||
@ -37,5 +39,6 @@
|
|||||||
[:chats chat-id :command-requests])
|
[:chats chat-id :command-requests])
|
||||||
(defn chat-command-request-path [chat-id msg-id]
|
(defn chat-command-request-path [chat-id msg-id]
|
||||||
[:chats chat-id :command-requests msg-id])
|
[:chats chat-id :command-requests msg-id])
|
||||||
|
(def show-actions-path [:show-actions])
|
||||||
(def new-group-path [:new-group])
|
(def new-group-path [:new-group])
|
||||||
(def new-participants-path [:new-participants])
|
(def new-participants-path [:new-participants])
|
||||||
|
@ -119,6 +119,11 @@
|
|||||||
(log/debug action commands)
|
(log/debug action commands)
|
||||||
(set-commands db commands)))
|
(set-commands db commands)))
|
||||||
|
|
||||||
|
(register-handler :set-show-actions
|
||||||
|
(fn [db [action show-actions]]
|
||||||
|
(log/debug action)
|
||||||
|
(assoc-in db db/show-actions-path show-actions)))
|
||||||
|
|
||||||
;; -- Protocol --------------------------------------------------------------
|
;; -- Protocol --------------------------------------------------------------
|
||||||
|
|
||||||
(register-handler :initialize-protocol
|
(register-handler :initialize-protocol
|
||||||
@ -136,10 +141,9 @@
|
|||||||
(fn [db [action {chat-id :from
|
(fn [db [action {chat-id :from
|
||||||
msg-id :msg-id :as msg}]]
|
msg-id :msg-id :as msg}]]
|
||||||
(log/debug action "msg" msg)
|
(log/debug action "msg" msg)
|
||||||
(save-message chat-id msg)
|
(let [db (create-chat db chat-id [chat-id] false)]
|
||||||
(-> db
|
(save-message chat-id msg)
|
||||||
(create-chat chat-id [chat-id] false)
|
(signal-chat-updated db chat-id))))
|
||||||
(signal-chat-updated chat-id))))
|
|
||||||
|
|
||||||
(register-handler :group-received-msg
|
(register-handler :group-received-msg
|
||||||
(fn [db [action {chat-id :group-id :as msg}]]
|
(fn [db [action {chat-id :group-id :as msg}]]
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
(ns syng-im.models.chats
|
(ns syng-im.models.chats
|
||||||
(:require [clojure.set :refer [difference]]
|
(:require [clojure.set :refer [difference]]
|
||||||
[syng-im.persistence.realm :as r]
|
[syng-im.persistence.realm :as r]
|
||||||
[syng-im.utils.random :refer [timestamp]]
|
[syng-im.utils.random :as random :refer [timestamp]]
|
||||||
[clojure.string :refer [join blank?]]
|
[clojure.string :refer [join blank?]]
|
||||||
[syng-im.db :as db]
|
[syng-im.db :as db]
|
||||||
[syng-im.utils.logging :as log]
|
[syng-im.utils.logging :as log]
|
||||||
|
[syng-im.constants :refer [content-type-status]]
|
||||||
|
[syng-im.models.messages :refer [save-message]]
|
||||||
[syng-im.persistence.realm-queries :refer [include-query]]
|
[syng-im.persistence.realm-queries :refer [include-query]]
|
||||||
[syng-im.models.chat :refer [signal-chat-updated]]))
|
[syng-im.models.chat :refer [signal-chat-updated]]))
|
||||||
|
|
||||||
@ -35,6 +37,18 @@
|
|||||||
(defn chat-exists? [chat-id]
|
(defn chat-exists? [chat-id]
|
||||||
(r/exists? :chats :chat-id chat-id))
|
(r/exists? :chats :chat-id chat-id))
|
||||||
|
|
||||||
|
(defn add-status-message [chat-id]
|
||||||
|
;; TODO Get real status
|
||||||
|
(save-message chat-id
|
||||||
|
{:from "Status"
|
||||||
|
:to nil
|
||||||
|
:msg-id (random/id)
|
||||||
|
:content (str "The brash businessman’s braggadocio "
|
||||||
|
"and public exchange with candidates "
|
||||||
|
"in the US presidential election")
|
||||||
|
:content-type content-type-status
|
||||||
|
:outgoing false}))
|
||||||
|
|
||||||
(defn create-chat
|
(defn create-chat
|
||||||
([db chat-id identities group-chat?]
|
([db chat-id identities group-chat?]
|
||||||
(create-chat db chat-id identities group-chat? nil))
|
(create-chat db chat-id identities group-chat? nil))
|
||||||
@ -48,12 +62,14 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(let [contacts (mapv (fn [ident]
|
(let [contacts (mapv (fn [ident]
|
||||||
{:identity ident}) identities)]
|
{:identity ident}) identities)]
|
||||||
(r/create :chats {:chat-id chat-id
|
(r/create :chats {:chat-id chat-id
|
||||||
:is-active true
|
:is-active true
|
||||||
:name chat-name
|
:name chat-name
|
||||||
:group-chat group-chat?
|
:group-chat group-chat?
|
||||||
:timestamp (timestamp)
|
:timestamp (timestamp)
|
||||||
:contacts contacts}))))
|
:contacts contacts
|
||||||
|
:last-msg-id ""}))))
|
||||||
|
(add-status-message chat-id)
|
||||||
(signal-chats-updated db)))))
|
(signal-chats-updated db)))))
|
||||||
|
|
||||||
(defn chat-contacts [chat-id]
|
(defn chat-contacts [chat-id]
|
||||||
|
@ -5,21 +5,36 @@
|
|||||||
[syng-im.db :as db]
|
[syng-im.db :as db]
|
||||||
[syng-im.utils.logging :as log]))
|
[syng-im.utils.logging :as log]))
|
||||||
|
|
||||||
|
(defn select-chat-last-message [chat]
|
||||||
|
(when-let [last-msg-id (:last-msg-id chat)]
|
||||||
|
(r/single-cljs (r/get-by-field :msgs :msg-id last-msg-id))))
|
||||||
|
|
||||||
(defn save-message [chat-id {:keys [from to msg-id content content-type outgoing] :or {outgoing false
|
(defn save-message [chat-id {:keys [from to msg-id content content-type outgoing] :or {outgoing false
|
||||||
to nil} :as msg}]
|
to nil} :as msg}]
|
||||||
(log/debug "save-message" chat-id msg)
|
(log/debug "save-message" chat-id msg)
|
||||||
(when-not (r/exists? :msgs :msg-id msg-id)
|
(when-not (r/exists? :msgs :msg-id msg-id)
|
||||||
(r/write
|
(r/write
|
||||||
(fn []
|
(fn []
|
||||||
(r/create :msgs {:chat-id chat-id
|
(let [chat (r/single-cljs (r/get-by-field :chats :chat-id chat-id))
|
||||||
:msg-id msg-id
|
last-message (select-chat-last-message chat)]
|
||||||
:from from
|
(r/create :msgs {:chat-id chat-id
|
||||||
:to to
|
:msg-id msg-id
|
||||||
:content content
|
:from from
|
||||||
:content-type content-type
|
:to to
|
||||||
:outgoing outgoing
|
:content content
|
||||||
:timestamp (timestamp)
|
:content-type content-type
|
||||||
:delivery-status nil} true)))))
|
:outgoing outgoing
|
||||||
|
:timestamp (timestamp)
|
||||||
|
:delivery-status nil
|
||||||
|
:same-author (if last-message
|
||||||
|
(= (:from last-message) from)
|
||||||
|
true)
|
||||||
|
:same-direction (if last-message
|
||||||
|
(= (:outgoing last-message) outgoing)
|
||||||
|
true)} true)
|
||||||
|
(r/create :chats {:chat-id (:chat-id chat)
|
||||||
|
:last-msg-id msg-id}
|
||||||
|
true))))))
|
||||||
|
|
||||||
(defn get-messages [chat-id]
|
(defn get-messages [chat-id]
|
||||||
(r/sorted (r/get-by-field :msgs :chat-id chat-id) :timestamp :desc))
|
(r/sorted (r/get-by-field :msgs :chat-id chat-id) :timestamp :desc))
|
||||||
|
@ -32,21 +32,24 @@
|
|||||||
:indexed true}
|
:indexed true}
|
||||||
:outgoing "bool"
|
:outgoing "bool"
|
||||||
:delivery-status {:type "string"
|
:delivery-status {:type "string"
|
||||||
:optional true}}}
|
:optional true}
|
||||||
|
:same-author "bool"
|
||||||
|
:same-direction "bool"}}
|
||||||
{:name :chat-contact
|
{:name :chat-contact
|
||||||
:properties {:identity "string"
|
:properties {:identity "string"
|
||||||
:is-in-chat {:type "bool"
|
:is-in-chat {:type "bool"
|
||||||
:default true}}}
|
:default true}}}
|
||||||
{:name :chats
|
{:name :chats
|
||||||
:primaryKey :chat-id
|
:primaryKey :chat-id
|
||||||
:properties {:chat-id "string"
|
:properties {:chat-id "string"
|
||||||
:name "string"
|
:name "string"
|
||||||
:group-chat {:type "bool"
|
:group-chat {:type "bool"
|
||||||
:indexed true}
|
:indexed true}
|
||||||
:is-active "bool"
|
:is-active "bool"
|
||||||
:timestamp "int"
|
:timestamp "int"
|
||||||
:contacts {:type "list"
|
:contacts {:type "list"
|
||||||
:objectType "chat-contact"}}}]})
|
:objectType "chat-contact"}
|
||||||
|
:last-msg-id "string"}}]})
|
||||||
|
|
||||||
|
|
||||||
(def realm (js/Realm. (clj->js opts)))
|
(def realm (js/Realm. (clj->js opts)))
|
||||||
|
@ -109,6 +109,11 @@
|
|||||||
(reaction
|
(reaction
|
||||||
(get @db :signed-up))))
|
(get @db :signed-up))))
|
||||||
|
|
||||||
|
(register-sub
|
||||||
|
:show-actions
|
||||||
|
(fn [db _]
|
||||||
|
(reaction (get-in @db db/show-actions-path))))
|
||||||
|
|
||||||
(register-sub
|
(register-sub
|
||||||
:get-contacts
|
:get-contacts
|
||||||
(fn [db _]
|
(fn [db _]
|
||||||
|