Merge pull request #62 from status-im/styles

Chat & chat components styles

Former-commit-id: 9e49529d12ec7fcd0cf3c95411a3ddaf8899b2ca
This commit is contained in:
Jarrad 2016-05-09 15:44:19 +02:00
commit 3db4ed389b
26 changed files with 1026 additions and 878 deletions

View File

@ -4,22 +4,14 @@
[syng-im.components.react :refer [view [syng-im.components.react :refer [view
text text
image image
icon
navigator navigator
touchable-highlight touchable-highlight
toolbar-android toolbar-android
list-view list-view
list-item list-item
android?]] android?]]
[syng-im.components.styles :refer [font [syng-im.components.chat-styles :as st]
title-font
color-white
chat-background
online-color
selected-message-color
separator-color
text1-color
text2-color
toolbar-background1]]
[syng-im.utils.logging :as log] [syng-im.utils.logging :as log]
[syng-im.resources :as res] [syng-im.resources :as res]
[syng-im.constants :refer [content-type-status]] [syng-im.constants :refer [content-type-status]]
@ -29,7 +21,6 @@
[syng-im.components.chat.chat-message :refer [chat-message]] [syng-im.components.chat.chat-message :refer [chat-message]]
[syng-im.components.chat.chat-message-new :refer [chat-message-new]])) [syng-im.components.chat.chat-message-new :refer [chat-message-new]]))
(defn contacts-by-identity [contacts] (defn contacts-by-identity [contacts]
(->> contacts (->> contacts
(map (fn [{:keys [identity] :as contact}] (map (fn [{:keys [identity] :as contact}]
@ -50,123 +41,33 @@
[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})
:style {:borderRadius 50 :style st/chat-photo}]])
:width 36
:height 36}}]])
(defn contact-online [{:keys [online]}] (defn contact-online [{:keys [online]}]
(when online (when online
[view {:position "absolute" [view st/online-view
:top 30 [view st/online-dot-left]
:left 30 [view st/online-dot-right]]))
:width 20
:height 20
:borderRadius 50
:backgroundColor online-color
:borderWidth 2
:borderColor color-white}
[view {:position "absolute"
:top 6
:left 3
:width 4
:height 4
:borderRadius 50
:backgroundColor color-white}]
[view {:position "absolute"
:top 6
:left 9
:width 4
:height 4
:borderRadius 50
:backgroundColor color-white}]]))
(defn typing [member] (defn typing [member]
[view {:style {:width 260 [view st/typing-view
:marginTop 10 [view st/typing-background
:paddingLeft 8 [text {:style st/typing-text}
:paddingRight 8
:alignItems "flex-start"
:alignSelf "flex-start"}}
[view {:style {:borderRadius 14
:padding 12
:height 38
:backgroundColor selected-message-color}}
[text {:style {:marginTop -2
:fontSize 12
:fontFamily font
:color text2-color}}
(str member " is typing")]]]) (str member " is typing")]]])
(defn typing-all [] (defn typing-all []
[view {:style {:marginBottom 20}} [view st/typing-all
(for [member ["Geoff" "Justas"]] (for [member ["Geoff" "Justas"]]
^{:key member} [typing member])]) ^{:key member} [typing member])])
(defn toolbar-content-chat [group-chat]
(let
[contacts (subscribe [:chat :contacts])
name (subscribe [:chat :name])]
(fn [group-chat]
[view {:style {:flex 1
:flexDirection "row"
:backgroundColor "transparent"}}
[view {:style {:flex 1
:alignItems "flex-start"
:justifyContent "center"
:marginRight 112}}
[text {:style {:marginTop -2.5
:color text1-color
:fontSize 16
:fontFamily font}}
(or @name "Chat name")]
(if group-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}}
(let [cnt (count @contacts)]
(str cnt
(if (< 1 cnt)
;; TODO https://github.com/r0man/inflections-clj
" members"
" member")
", " cnt " active"))]]
[text {:style {:marginTop 1
:color text2-color
:fontSize 12
:fontFamily font}}
"Active a minute ago"])]
(when-not group-chat
[view {:style {:position "absolute"
:top 10
:right 66}}
[chat-photo {}]
[contact-online {:online true}]])])))
(defn message-row [contact-by-identity group-chat] (defn message-row [contact-by-identity group-chat]
(fn [row _ _] (fn [row _ idx]
(let [msg (-> row (let [msg (-> row
(add-msg-color contact-by-identity) (add-msg-color contact-by-identity)
(assoc :group-chat group-chat))] (assoc :group-chat group-chat)
(assoc :last-msg (zero? (js/parseInt idx))))]
(list-item [chat-message msg])))) (list-item [chat-message msg]))))
(def group-caht-actions
[{: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}])
(defn on-action-selected [position] (defn on-action-selected [position]
(case position (case position
0 (dispatch [:show-add-participants #_navigator]) 0 (dispatch [:show-add-participants #_navigator])
@ -174,43 +75,24 @@
2 (dispatch [:leave-group-chat #_navigator]))) 2 (dispatch [:leave-group-chat #_navigator])))
(defn overlay [{:keys [on-click-outside]} items] (defn overlay [{:keys [on-click-outside]} items]
[view {:position :absolute [view st/actions-overlay
:top 0 [touchable-highlight {:on-press on-click-outside
:bottom 0 :style st/overlay-highlight}
:left 0
:right 0}
[touchable-highlight {:on-press on-click-outside
:underlay-color :transparent
:style {:flex 1}}
[view nil]] [view nil]]
items]) items])
(defn action-view [action] (defn action-view [{:keys [icon-style handler title subtitle]
icon-name :icon}]
[touchable-highlight {:on-press (fn [] [touchable-highlight {:on-press (fn []
(dispatch [:set-show-actions false]) (dispatch [:set-show-actions false])
((:handler action))) (handler))}
:underlay-color :transparent} [view st/action-icon-row
[view {:style {:flexDirection "row" [view st/action-icon-view
:height 56}} [icon icon-name icon-style]]
[view {:width 56 [view st/action-view
:height 56 [text {:style st/action-title} title]
:alignItems "center" (when-let [subtitle subtitle]
:justifyContent "center"} [text {:style st/action-subtitle}
[image {:source {:uri (:icon action)}
:style (:icon-style action)}]]
[view {:style {:flex 1
:alignItems "flex-start"
:justifyContent "center"}}
[text {:style {:marginTop -2.5
:color text1-color
:fontSize 14
:fontFamily font}}
(:title action)]
(when-let [subtitle (:subtitle action)]
[text {:style {:marginTop 1
:color text2-color
:fontSize 12
:fontFamily font}}
subtitle])]]]) subtitle])]]])
(defn actions-list-view [] (defn actions-list-view []
@ -218,40 +100,33 @@
(subscribe [:chat-properties [:group-chat :name :contacts :active]])] (subscribe [:chat-properties [:group-chat :name :contacts :active]])]
(when-let [actions (when (and @group-chat @active) (when-let [actions (when (and @group-chat @active)
[{:title "Add Contact to chat" [{:title "Add Contact to chat"
:icon :icon_menu_group :icon :menu_group
:icon-style {:width 25 :icon-style {:width 25
:height 19} :height 19}
:handler nil #_#(dispatch [:show-add-participants :handler nil #_#(dispatch [:show-add-participants
navigator])} navigator])}
{:title "Remove Contact from chat" {:title "Remove Contact from chat"
:subtitle "Alex, John" :subtitle "Alex, John"
:icon :icon_search_gray_copy :icon :search_gray_copy
:icon-style {:width 17 :icon-style {:width 17
:height 17} :height 17}
:handler nil #_#(dispatch :handler nil #_#(dispatch
[:show-remove-participants navigator])} [:show-remove-participants navigator])}
{:title "Leave Chat" {:title "Leave Chat"
:icon :icon_muted :icon :muted
:icon-style {:width 18 :icon-style {:width 18
:height 21} :height 21}
:handler nil #_#(dispatch [:leave-group-chat :handler nil #_#(dispatch [:leave-group-chat
navigator])} navigator])}
{:title "Settings" {:title "Settings"
:subtitle "Not implemented" :subtitle "Not implemented"
:icon :icon_settings :icon :settings
:icon-style {:width 20 :icon-style {:width 20
:height 13} :height 13}
:handler (fn [])}])] :handler (fn [])}])]
[view {:style {:backgroundColor toolbar-background1 [view st/actions-wrapper
:elevation 2 [view st/actions-separator]
:position :absolute [view st/actions-view
:top 56
:left 0
:right 0}}
[view {:style {:marginLeft 16
:height 1.5
:backgroundColor separator-color}}]
[view {:style {:marginVertical 10}}
(for [action actions] (for [action actions]
^{:key action} [action-view action])]]))) ^{:key action} [action-view action])]])))
@ -264,67 +139,33 @@
(subscribe [:chat-properties [:group-chat :name :contacts]]) (subscribe [:chat-properties [:group-chat :name :contacts]])
show-actions (subscribe [:show-actions])] show-actions (subscribe [:show-actions])]
(fn [] (fn []
[view {:style {:flexDirection "row" [view st/toolbar-view
:height 56
:backgroundColor toolbar-background1
:elevation 2}}
(when (not @show-actions) (when (not @show-actions)
[touchable-highlight {:on-press #(dispatch [:navigate-back]) [touchable-highlight {:on-press #(dispatch [:navigate-back])}
:underlay-color :transparent} [view st/icon-view
[view {:width 56 [icon :back st/back-icon]]])
:height 56} [view (st/chat-name-view @show-actions)
[image {:source {:uri "icon_back"} [text {:style st/chat-name-text}
: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 @name "Chat name")] (or @name "Chat name")]
(if @group-chat (if @group-chat
[view {:style {:flexDirection :row}} [view {:flexDirection :row}
[image {:source {:uri :icon_group} [icon :group st/group-icon]
:style {:marginTop 4 [text {:style st/members}
:width 14
:height 9}}]
[text {:style {:marginTop -0.5
:marginLeft 4
:fontFamily font
:fontSize 12
:color text2-color}}
(let [cnt (count @contacts)] (let [cnt (count @contacts)]
(str cnt (str cnt
(if (< 1 cnt) (if (< 1 cnt)
" members" " members"
" member") " member")
", " cnt " active"))]] ", " cnt " active"))]]
[text {:style {:marginTop 1 [text {:style st/last-activity} "Active a minute ago"])]
:color text2-color
:fontSize 12
:fontFamily font}}
"Active a minute ago"])]
(if @show-actions (if @show-actions
[touchable-highlight [touchable-highlight
{:on-press #(dispatch [:set-show-actions false]) {:on-press #(dispatch [:set-show-actions false])}
:underlay-color :transparent} [view st/icon-view
[view {:style {:width 56 [icon :up st/up-icon]]]
:height 56}}
[image {:source {:uri :icon_up}
:style {:marginTop 23
:marginLeft 21
:width 14
:height 8}}]]]
[touchable-highlight [touchable-highlight
{:on-press #(dispatch [:set-show-actions true]) {:on-press #(dispatch [:set-show-actions true])}
:underlay-color :transparent} [view st/icon-view
[view {:style {:width 56
:height 56}}
[chat-photo {}] [chat-photo {}]
[contact-online {:online true}]]])]))) [contact-online {:online true}]]])])))
@ -343,8 +184,7 @@
group-chat (subscribe [:chat :group-chat]) group-chat (subscribe [:chat :group-chat])
show-actions-atom (subscribe [:show-actions])] show-actions-atom (subscribe [:show-actions])]
(fn [] (fn []
[view {:style {:flex 1 [view st/chat-view
:backgroundColor chat-background}}
[toolbar] [toolbar]
[messages-view @group-chat] [messages-view @group-chat]
(when @group-chat [typing-all]) (when @group-chat [typing-all])

View File

@ -1,149 +1,54 @@
(ns syng-im.components.chat.chat-message (ns syng-im.components.chat.chat-message
(:require [clojure.string :as s] (:require [clojure.string :as s]
[re-frame.core :refer [subscribe dispatch dispatch-sync]] [re-frame.core :refer [subscribe dispatch]]
[syng-im.components.react :refer [android? [syng-im.components.react :refer [view
view
text text
image image
touchable-highlight touchable-highlight]]
navigator]] [syng-im.components.chat.chat-message-styles :as st]
[syng-im.components.styles :refer [font
color-light-blue-transparent
color-white
color-black
color-blue
selected-message-color
online-color
text1-color
text2-color]]
[syng-im.models.commands :refer [parse-command-msg-content [syng-im.models.commands :refer [parse-command-msg-content
parse-command-request-msg-content]] parse-command-request]]
[syng-im.utils.logging :as log]
[syng-im.navigation :refer [nav-pop]]
[syng-im.resources :as res] [syng-im.resources :as res]
[syng-im.constants :refer [text-content-type [syng-im.constants :refer [text-content-type
content-type-status content-type-status
content-type-command content-type-command
content-type-command-request]])) content-type-command-request]]))
(def style-message-text {:fontSize 14
:fontFamily font
:lineHeight 21
:color text1-color})
(def style-sub-text {:top -2
:fontFamily font
:fontSize 12
:color text2-color
:lineHeight 14
:height 16})
(defn message-date [{:keys [date]}] (defn message-date [{:keys [date]}]
[view {} [view {}
[view {:style {:backgroundColor color-light-blue-transparent [view st/message-date-container
:height 24 [text {:style st/message-date-text} date]]])
:borderRadius 50
:alignSelf :center
:marginTop 20
:marginBottom 20
:paddingTop 5
:paddingHorizontal 12}}
[text {:style (assoc style-sub-text :textAlign :center)}
date]]])
(defn contact-photo [{:keys [photo-path]}] (defn contact-photo [{:keys [photo-path]}]
[view {:borderRadius 50} [view st/contact-photo-container
[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})
:style {:borderRadius 50 :style st/contact-photo}]])
:width 64
:height 64}}]])
(defn contact-online [{:keys [online]}] (defn contact-online [{:keys [online]}]
(when online (when online
[view {:position :absolute [view st/online-container
:top 44 [view st/online-dot-left]
:left 44 [view st/online-dot-right]]))
:width 24
:height 24
:borderRadius 50
:backgroundColor online-color
:borderWidth 2
:borderColor color-white}
[view {:position :absolute
:top 8
:left 5
:width 4
:height 4
:borderRadius 50
:backgroundColor color-white}]
[view {:position :absolute
:top 8
:left 11
:width 4
:height 4
:borderRadius 50
:backgroundColor color-white}]]))
(defn message-content-status [{:keys [from content]}] (defn message-content-status [{:keys [from content]}]
[view {:style {:flex 1 [view st/status-container
:alignSelf :center [view st/status-image-view
:alignItems :center
:width 249}}
[view {:style {:marginTop 20}}
[contact-photo {}] [contact-photo {}]
[contact-online {:online true}]] [contact-online {:online true}]]
[text {:style {:marginTop 20 [text {:style st/status-from} from]
:fontSize 18 [text {:style st/status-text} content]])
:fontFamily font
:color text1-color}}
from]
[text {:style {:marginTop 10
:fontFamily font
:fontSize 14
:lineHeight 20
:textAlign :center
:color text2-color}}
content]])
(defn message-content-audio [_] (defn message-content-audio [_]
[view {:style {:flexDirection :row [view st/audio-container
:alignItems :center}} [view st/play-view
[view {:style {:width 33
:height 33
:borderRadius 50
:elevation 1}}
[image {:source res/play [image {:source res/play
:style {:width 33 :style st/play-image}]]
:height 33}}]] [view st/track-container
[view {:style {:marginTop 10 [view st/track]
:marginLeft 10 [view st/track-mark]
:width 120 [text {:style st/track-duration-text} "03:39"]]])
:height 26
:elevation 1}}
[view {:style {:position :absolute
:top 4
:width 120
:height 2
:backgroundColor "#EC7262"}}]
[view {:style {:position :absolute
:left 0
:top 0
:width 2
:height 10
:backgroundColor "#4A5258"}}]
[text {:style {:position :absolute
:left 1
:top 11
:fontFamily font
:fontSize 11
:color "#4A5258"
:letterSpacing 1
:lineHeight 15}}
"03:39"]]])
(defn message-content-command [content] (defn message-content-command [content]
(let [commands-atom (subscribe [:get-commands])] (let [commands-atom (subscribe [:get-commands])]
@ -151,27 +56,14 @@
(let [commands @commands-atom (let [commands @commands-atom
{:keys [command content]} {:keys [command content]}
(parse-command-msg-content commands content)] (parse-command-msg-content commands content)]
[view {:style {:flexDirection :column}} [view st/content-command-view
[view {:style {:flexDirection :row [view st/command-container
:marginRight 32}} [view (st/command-view command)
[view {:style {:backgroundColor (:color command) [text {:style st/command-name}
:height 24
:borderRadius 50
:paddingTop 3
:paddingHorizontal 12}}
[text {:style {:fontSize 12
:fontFamily font
:color color-white}}
(:text command)]]] (:text command)]]]
[image {:source (:icon command) [image {:source (:icon command)
:style {:position :absolute :style st/command-image}]
:top 4 [text {:style st/command-text}
:right 0
:width 12
:height 13}}]
[text {:style (merge style-message-text
{:marginTop 8
:marginHorizontal 0})}
;; TODO isn't smart ;; TODO isn't smart
(if (= (:command command) :keypair-password) (if (= (:command command) :keypair-password)
"******" "******"
@ -180,99 +72,33 @@
(defn set-chat-command [msg-id command] (defn set-chat-command [msg-id command]
(dispatch [:set-response-chat-command msg-id (:command command)])) (dispatch [:set-response-chat-command msg-id (:command command)]))
(defn message-content-command-request (defn message-content-command-request
[{:keys [msg-id content outgoing group-chat from]}] [{:keys [msg-id content from incoming-group]}]
(let [commands-atom (subscribe [:get-commands])] (let [commands-atom (subscribe [:get-commands])]
(fn [{:keys [msg-id content outgoing group-chat from]}] (fn [{:keys [msg-id content from incoming-group]}]
(let [commands @commands-atom (let [commands @commands-atom
{:keys [command content]} (parse-command-request-msg-content commands content)] {:keys [command content]} (parse-command-request commands content)]
[touchable-highlight {:onPress #(set-chat-command msg-id command) [touchable-highlight {:onPress #(set-chat-command msg-id command)}
:underlay-color :transparent} [view st/comand-request-view
[view {:style {:paddingRight 16}} [view st/command-request-message-view
[view {:style (merge {:borderRadius 14 (when incoming-group
:padding 12 [text {:style st/command-request-from-text}
:backgroundColor color-white})}
(when (and group-chat (not outgoing))
[text {:style (merge style-sub-text
{:marginBottom 2})}
from]) from])
[text {:style style-message-text} [text {:style st/style-message-text}
content]] content]]
[view {:style {:position :absolute [view (st/command-request-image-view command)
:top 12
:right 0
:width 32
:height 32
:borderRadius 50
:backgroundColor (:color command)}}
[image {:source (:request-icon command) [image {:source (:request-icon command)
:style {:position :absolute :style st/command-request-image}]]
:top 9
:left 10
:width 12
:height 13}}]]
(when (:request-text command) (when (:request-text command)
[view {:style {:marginTop 4 [view st/command-request-text-view
:height 14}} [text {:style st/style-sub-text}
[text {:style style-sub-text}
(:request-text command)]])]])))) (:request-text command)]])]]))))
(defn message-content-plain [content outgoing group-chat]
[text {:style (merge style-message-text
{:marginTop (if (and group-chat (not outgoing))
4
0)}
(when (and outgoing group-chat)
{:color color-white}))}
content])
#_(defn message-content [{:keys [msg-id from content-type content outgoing
group-chat selected]}]
(if (= content-type content-type-command-request)
[message-content-command-request msg-id from content outgoing group-chat]
[view {:style (merge {:borderRadius 14
:padding 12
:backgroundColor color-white}
(when (= content-type content-type-command)
{:paddingTop 10
:paddingBottom 14})
(if outgoing
(when (and group-chat (= content-type text-content-type))
{:backgroundColor color-blue})
(when selected
{:backgroundColor selected-message-color})))}
(when (and group-chat (not outgoing))
[text {:style (merge style-sub-text
{:marginBottom 2})}
from])
(cond
(or (= content-type text-content-type)
(= content-type content-type-status))
[message-content-plain content outgoing group-chat]
(= content-type content-type-command)
[message-content-command content]
:else [message-content-audio {:content content
:content-type content-type}])]))
(defn message-view (defn message-view
[{:keys [content-type outgoing background-color group-chat selected]} content] [message content]
[view {:style (merge {:borderRadius 14 [view (st/message-view message)
:padding 12 #_(when incoming-group
:backgroundColor color-white} [text {:style message-author-text}
(when (= content-type content-type-command)
{:paddingTop 10
:paddingBottom 14})
(if outgoing
(when (and group-chat (= content-type text-content-type))
{:backgroundColor color-blue})
(when selected
{:backgroundColor selected-message-color})))}
#_(when (and group-chat (not outgoing))
[text {:style {:marginTop 0
:fontSize 12
:fontFamily font}}
"Justas"]) "Justas"])
content]) content])
@ -284,14 +110,9 @@
[wrapper message [message-content-command-request message]]) [wrapper message [message-content-command-request message]])
(defn text-message (defn text-message
[{:keys [content outgoing group-chat] :as message}] [{:keys [content] :as message}]
[message-view message [message-view message
[text {:style (merge style-message-text [text {:style (st/text-message message)}
{:marginTop (if (and group-chat (not outgoing))
4
0)}
(when (and outgoing group-chat)
{:color color-white}))}
content]]) content]])
(defmethod message-content text-content-type (defmethod message-content text-content-type
@ -315,21 +136,14 @@
:content-type content-type}]]]) :content-type content-type}]]])
(defn message-delivery-status [{:keys [delivery-status]}] (defn message-delivery-status [{:keys [delivery-status]}]
[view {:style {:flexDirection :row [view st/delivery-view
:marginTop 2}}
[image {:source (case delivery-status [image {:source (case delivery-status
:delivered {:uri :icon_ok_small} :delivered {:uri :icon_ok_small}
:seen {:uri :icon_ok_small} :seen {:uri :icon_ok_small}
:seen-by-everyone {:uri :icon_ok_small} :seen-by-everyone {:uri :icon_ok_small}
:failed res/delivery-failed-icon) :failed res/delivery-failed-icon)
:style {:marginTop 6 :style st/delivery-image}]
:width 9 [text {:style st/delivery-text}
:height 7}}]
[text {:style {:fontFamily font
:fontSize 12
:color text2-color
:marginLeft 5}}
(case delivery-status (case delivery-status
:delivered "Delivered" :delivered "Delivered"
:seen "Seen" :seen "Seen"
@ -337,85 +151,46 @@
:failed "Failed")]]) :failed "Failed")]])
(defn member-photo [{:keys [photo-path]}] (defn member-photo [{:keys [photo-path]}]
[view {:borderRadius 50} [view st/photo-view
[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})
:style {:borderRadius 50 :style st/photo}]])
:width 24
:height 24}}]])
(defn incoming-group-message-body (defn incoming-group-message-body
[{:keys [selected new-day same-author same-direction last-msg typing]} [{:keys [selected same-author] :as message} content]
content]
(let [delivery-status :seen-by-everyone] (let [delivery-status :seen-by-everyone]
[view {:style {:flexDirection :column}} [view st/group-message-wrapper
(when selected (when selected
[text {:style {:marginTop 18 [text {:style st/selected-message}
:marginLeft 40
:fontFamily font
:fontSize 12
:color text2-color}}
"Mar 7th, 15:22"]) "Mar 7th, 15:22"])
[view {:style (merge {:flexDirection :row [view (st/incoming-group-message-body-st message)
:alignSelf :flex-start [view st/message-author
:marginTop (cond (when (not same-author) [member-photo {}])]
new-day 0 [view st/group-message-view
same-author 4
same-direction 20
:else 10)
:paddingRight 8
:paddingLeft 8}
(when (and last-msg (not typing))
{:paddingBottom 20}))}
[view {:style {:width 24}}
(when (not same-author)
[member-photo {}])]
[view {:style {:flexDirection :column
:width 260
:paddingLeft 8
:alignItems :flex-start}}
content content
;; TODO show for last or selected ;; TODO show for last or selected
(when (and selected delivery-status) (when (and selected delivery-status)
[message-delivery-status {:delivery-status delivery-status}])]]])) [message-delivery-status {:delivery-status delivery-status}])]]]))
(defn message-body (defn message-body
[{:keys [outgoing new-day same-author same-direction last-msg typing]} [{:keys [outgoing] :as message} content]
content] (let [delivery-status :seen]
(let [delivery-status :seen [view (st/message-body message)
align (if outgoing :flex-end :flex-start)]
[view {:style (merge {:flexDirection :column
:width 260
:paddingTop (cond
new-day 0
same-author 4
same-direction 20
:else 10)
:paddingRight 8
:paddingLeft 8
:alignSelf align
:alignItems align}
(when (and last-msg (not typing))
{:paddingBottom 20}))}
content content
(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 (defn chat-message
[{:keys [msg-id outgoing delivery-status date new-day group-chat] [{:keys [outgoing delivery-status date new-day group-chat]
:as message} :as message}]
last-msg-id]
[view {} [view {}
(when new-day (when new-day [message-date {:date date}])
[message-date {:date date}]) [view {}
(let [msg-data (let [incoming-group (and group-chat (not outgoing))]
(merge message {:delivery-status (keyword delivery-status)
:last-msg (= last-msg-id msg-id)})]
[view {}
[message-content [message-content
(if (and group-chat (not outgoing)) (if incoming-group
incoming-group-message-body incoming-group-message-body
message-body) message-body)
msg-data]])]) (merge message {:delivery-status (keyword delivery-status)
:incoming-group incoming-group})])]])

View File

@ -1,23 +1,15 @@
(ns syng-im.components.chat.chat-message-new (ns syng-im.components.chat.chat-message-new
(:require (:require
[re-frame.core :refer [subscribe dispatch dispatch-sync]] [re-frame.core :refer [subscribe]]
[syng-im.components.react :refer [android? [syng-im.components.react :refer [view]]
view [syng-im.components.chat.plain-message-input :refer [plain-message-input-view]]
image [syng-im.components.chat.input.simple-command :refer [simple-command-input-view]]
text [syng-im.components.chat.input.phone :refer [phone-input-view]]
text-input]] [syng-im.components.chat.input.password :refer [password-input-view]]
[syng-im.components.styles :refer [color-white]] [syng-im.components.chat.input.confirmation-code :refer [confirmation-code-input-view]]
[syng-im.components.chat.plain-message-input :refer [plain-message-input-view]] [syng-im.components.chat.input.money :refer [money-input-view]]
[syng-im.components.chat.input.simple-command :refer [simple-command-input-view]] [syng-im.components.chat.input.simple-command-staged :refer [simple-command-staged-view]]
[syng-im.components.chat.input.phone :refer [phone-input-view]] [syng-im.components.chat.chat-message-styles :as st]))
[syng-im.components.chat.input.password :refer [password-input-view]]
[syng-im.components.chat.input.confirmation-code :refer [confirmation-code-input-view]]
[syng-im.components.chat.input.money :refer [money-input-view]]
[syng-im.components.chat.input.simple-command-staged :refer [simple-command-staged-view]]
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.utils.logging :as log]
[syng-im.resources :as res]
[reagent.core :as r]))
(defn staged-command-view [stage-command] (defn staged-command-view [stage-command]
[simple-command-staged-view stage-command]) [simple-command-staged-view stage-command])
@ -40,13 +32,12 @@
[default-command-input-view command])) [default-command-input-view command]))
(defn chat-message-new [] (defn chat-message-new []
(let [command-atom (subscribe [:get-chat-command]) (let [command-atom (subscribe [:get-chat-command])
staged-commands-atom (subscribe [:get-chat-staged-commands])] staged-commands-atom (subscribe [:get-chat-staged-commands])]
(fn [] (fn []
(let [command @command-atom (let [command @command-atom
staged-commands @staged-commands-atom] staged-commands @staged-commands-atom]
[view {:style {:backgroundColor color-white [view st/new-message-container
:elevation 4}}
(when (and staged-commands (pos? (count staged-commands))) (when (and staged-commands (pos? (count staged-commands)))
[staged-commands-view staged-commands]) [staged-commands-view staged-commands])
(if command (if command

View File

@ -0,0 +1,329 @@
(ns syng-im.components.chat.chat-message-styles
(:require [syng-im.components.styles :refer [font
color-light-blue-transparent
color-white
color-black
color-blue
selected-message-color
online-color
text1-color
text2-color]]
[syng-im.constants :refer [text-content-type
content-type-command]]))
(def style-message-text
{:fontSize 14
:fontFamily font
:lineHeight 21
:color text1-color})
(def style-sub-text
{:top -2
:fontFamily font
:fontSize 12
:color text2-color
:lineHeight 14
:height 16})
(defn message-padding-top
[{:keys [new-day same-author same-direction]}]
(cond
new-day 0
same-author 4
same-direction 20
:else 10))
(defn last-message-padding
[{:keys [last-msg typing]}]
(when (and last-msg (not typing))
{:paddingBottom 20}))
(def message-body-base
{:paddingRight 8
:paddingLeft 8})
(defn message-body
[{:keys [outgoing] :as message}]
(let [align (if outgoing :flex-end :flex-start)]
(merge message-body-base
{:flexDirection :column
:width 260
:paddingTop (message-padding-top message)
:alignSelf align
:alignItems align}
(last-message-padding message))))
(defn incoming-group-message-body-st
[message]
(merge message-body-base
{:flexDirection :row
:alignSelf :flex-start
:marginTop (message-padding-top message)
:paddingRight 8
:paddingLeft 8}
(last-message-padding message)))
(def selected-message
{:marginTop 18
:marginLeft 40
:fontFamily font
:fontSize 12
:color text2-color})
(def group-message-wrapper
{:flexDirection :column})
(def group-message-view
{:flexDirection :column
:width 260
:paddingLeft 8
:alignItems :flex-start})
(def message-author {:width 24})
(def photo-view {:borderRadius 50})
(def photo
{:borderRadius 50
:width 24
:height 24})
(def delivery-view
{:flexDirection :row
:marginTop 2})
(def delivery-image
{:marginTop 6
:width 9
:height 7})
(def delivery-text
{:fontFamily font
:fontSize 12
:color text2-color
:marginLeft 5})
(defn text-message
[{:keys [outgoing group-chat incoming-group]}]
(merge style-message-text
{:marginTop (if incoming-group
4
0)}
(when (and outgoing group-chat)
{:color color-white})))
(defn message-view
[{:keys [content-type outgoing group-chat selected]}]
(merge {:borderRadius 14
:padding 12
:backgroundColor color-white}
(when (= content-type content-type-command)
{:paddingTop 10
:paddingBottom 14})
(if outgoing
(when (and group-chat (= content-type text-content-type))
{:backgroundColor color-blue})
(when selected
{:backgroundColor selected-message-color}))))
(def comand-request-view
{:paddingRight 16})
(def command-request-message-view
{:borderRadius 14
:padding 12
:backgroundColor color-white})
(def command-request-from-text
(merge style-sub-text {:marginBottom 2}))
(defn command-request-image-view
[command]
{:position :absolute
:top 12
:right 0
:width 32
:height 32
:borderRadius 50
:backgroundColor (:color command)})
(def command-request-image
{:position :absolute
:top 9
:left 10
:width 12
:height 13})
(def command-request-text-view
{:marginTop 4
:height 14})
(def content-command-view
{:flexDirection :column})
(def command-container
{:flexDirection :row
:marginRight 32})
(defn command-view [command]
{:backgroundColor (:color command)
:height 24
:borderRadius 50
:paddingTop 3
:paddingHorizontal 12})
(def command-name
{:fontSize 12
:fontFamily font
:color color-white})
(def command-image
{:position :absolute
:top 4
:right 0
:width 12
:height 13})
(def command-text
(merge style-message-text
{:marginTop 8
:marginHorizontal 0}))
(def message-author-text
{:marginTop 0
:fontSize 12
:fontFamily font})
(def audio-container
{:flexDirection :row
:alignItems :center})
(def play-view
{:width 33
:height 33
:borderRadius 50
:elevation 1})
(def play-image
{:width 33
:height 33})
(def track-container
{:marginTop 10
:marginLeft 10
:width 120
:height 26
:elevation 1})
(def track
{:position :absolute
:top 4
:width 120
:height 2
:backgroundColor :#EC7262})
(def track-mark
{:position :absolute
:left 0
:top 0
:width 2
:height 10
:backgroundColor :#4A5258})
(def track-duration-text
{:position :absolute
:left 1
:top 11
:fontFamily font
:fontSize 11
:color :#4A5258
:letterSpacing 1
:lineHeight 15})
(def status-container
{:flex 1
:alignSelf :center
:alignItems :center
:width 249})
(def status-image-view
{:marginTop 20})
(def status-from
{:marginTop 20
:fontSize 18
:fontFamily font
:color text1-color})
(def status-text
{:marginTop 10
:fontFamily font
:fontSize 14
:lineHeight 20
:textAlign :center
:color text2-color})
(def online-container
{:position :absolute
:top 44
:left 44
:width 24
:height 24
:borderRadius 50
:backgroundColor online-color
:borderWidth 2
:borderColor color-white})
(def online-dot
{:position :absolute
:top 8
:width 4
:height 4
:borderRadius 50
:backgroundColor color-white})
(def online-dot-left
(assoc online-dot :left 5))
(def online-dot-right
(assoc online-dot :left 11))
(def contact-photo-container
{:borderRadius 50})
(def contact-photo
{:borderRadius 50
:width 64
:height 64})
(def message-date-container
{:backgroundColor color-light-blue-transparent
:height 24
:borderRadius 50
:alignSelf :center
:marginTop 20
:marginBottom 20
:paddingTop 5
:paddingHorizontal 12})
(def message-date-text
(assoc style-sub-text :textAlign :center))
(def new-message-container
{:backgroundColor color-white
:elevation 4})
(def participants-container
{:flex 1
:backgroundColor :white})
(def participants-list
{:backgroundColor :white})
(def new-participant-image
{:width 20
:height 18})
(def remove-participants-image
{:width 22
:height 30})

View File

@ -1,9 +1,7 @@
(ns syng-im.components.chat.input.confirmation-code (ns syng-im.components.chat.input.confirmation-code
(:require (:require
[re-frame.core :refer [subscribe dispatch dispatch-sync]] [syng-im.components.chat.input.simple-command
[syng-im.components.chat.input.simple-command :refer [simple-command-input-view]] :refer [simple-command-input-view]]))
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.utils.logging :as log]))
(defn confirmation-code-input-view [command] (defn confirmation-code-input-view [command]
[simple-command-input-view command {:keyboardType "numeric"}]) [simple-command-input-view command {:keyboardType :numeric}])

View File

@ -0,0 +1,120 @@
(ns syng-im.components.chat.input.input-styles
(:require [syng-im.components.styles :refer [font
color-white
color-blue
text1-color
text2-color
chat-background
color-black]]))
(def money-input
{:flex 1
:marginLeft 8
:lineHeight 42
:fontSize 32
:fontFamily font
:color :black})
(def command-input-container
{:flexDirection :row
:height 56
:backgroundColor color-white
:elevation 4})
(defn command-text-container
[{:keys [color]}]
{:flexDirection :column
:marginTop 16
:marginBottom 16
:marginLeft 16
:marginRight 0
:backgroundColor color
:height 24
:borderRadius 50})
(def command-text
{:marginTop 3
:marginHorizontal 12
:fontSize 12
:fontFamily font
:color color-white})
(def command-input
{:flex 1
:marginLeft 8
:marginTop 7
:fontSize 14
:fontFamily font
:color text1-color})
(def send-container
{:marginTop 10
:marginRight 10
:width 36
:height 36
:borderRadius 50
:backgroundColor color-blue})
(def send-icon
{:marginTop 10.5
:marginLeft 12
:width 15
:height 15})
(def cancel-container
{:marginTop 10
:marginRight 10
:width 36
:height 36})
(def cancel-icon
{:marginTop 10.5
:marginLeft 12
:width 12
:height 12})
(def staged-command-container
{:flex 1
:alignItems :flex-start
:flexDirection :column
:backgroundColor color-white})
(def staged-command-background
{:flexDirection :column
:margin 16
:padding 12
:backgroundColor chat-background
:borderRadius 14})
(def staged-command-info-container
{:flexDirection :row})
(defn staged-command-text-container
[{:keys [color]}]
{:backgroundColor color
:height 24
:borderRadius 50
:marginRight 32
:paddingTop 3
:paddingHorizontal 12})
(def staged-command-text
{:fontSize 12
:fontFamily font
:color color-white})
(def staged-command-cancel
{:position :absolute
:top 7
:right 4})
(def staged-command-cancel-icon
{:width 10
:height 10})
(def staged-command-content
{:marginTop 5
:marginHorizontal 0
:fontSize 14
:fontFamily font
:color color-black})

View File

@ -1,16 +1,10 @@
(ns syng-im.components.chat.input.money (ns syng-im.components.chat.input.money
(:require (:require
[re-frame.core :refer [subscribe dispatch dispatch-sync]] [syng-im.components.chat.input.simple-command
[syng-im.components.styles :refer [font]] :refer [simple-command-input-view]]
[syng-im.components.chat.input.simple-command :refer [simple-command-input-view]] [syng-im.components.chat.input.input-styles :as st]))
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.utils.logging :as log]))
(defn money-input-view [command] (defn money-input-view [command]
[simple-command-input-view command {:keyboardType "numeric" [simple-command-input-view command
:style {:flex 1 {:keyboardType :numeric
:marginLeft 8 :style st/money-input}])
:lineHeight 42
:fontSize 32
:fontFamily font
:color "black"}}])

View File

@ -1,9 +1,7 @@
(ns syng-im.components.chat.input.password (ns syng-im.components.chat.input.password
(:require (:require
[re-frame.core :refer [subscribe dispatch dispatch-sync]] [syng-im.components.chat.input.simple-command
[syng-im.components.chat.input.simple-command :refer [simple-command-input-view]] :refer [simple-command-input-view]]))
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.utils.logging :as log]))
(defn password-input-view [command] (defn password-input-view [command]
[simple-command-input-view command {:secureTextEntry true}]) [simple-command-input-view command {:secureTextEntry true}])

View File

@ -1,9 +1,7 @@
(ns syng-im.components.chat.input.phone (ns syng-im.components.chat.input.phone
(:require (:require
[re-frame.core :refer [subscribe dispatch dispatch-sync]] [syng-im.components.chat.input.simple-command
[syng-im.components.chat.input.simple-command :refer [simple-command-input-view]] :refer [simple-command-input-view]]))
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.utils.logging :as log]))
(defn phone-input-view [command] (defn phone-input-view [command]
[simple-command-input-view command {:keyboardType "phone-pad"}]) [simple-command-input-view command {:keyboardType :phone-pad}])

View File

@ -1,18 +1,13 @@
(ns syng-im.components.chat.input.simple-command (ns syng-im.components.chat.input.simple-command
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [android? [syng-im.components.react :refer [view
view
image image
icon
text text
text-input text-input
touchable-highlight]] touchable-highlight]]
[syng-im.components.styles :refer [font [syng-im.resources :as res]
color-white [syng-im.components.chat.input.input-styles :as st]))
color-blue
text1-color
text2-color]]
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.resources :as res]))
(defn cancel-command-input [] (defn cancel-command-input []
(dispatch [:cancel-command])) (dispatch [:cancel-command]))
@ -28,61 +23,19 @@
(let [message-atom (subscribe [:get-chat-command-content])] (let [message-atom (subscribe [:get-chat-command-content])]
(fn [command input-options] (fn [command input-options]
(let [message @message-atom] (let [message @message-atom]
[view {:style {:flexDirection :row [view st/command-input-container
:height 56 [view (st/command-text-container command)
:backgroundColor color-white [text {:style st/command-text} (:text command)]]
:elevation 4}} [text-input (merge {:style st/command-input
[view {:style {:flexDirection :column :autoFocus true
:marginTop 16 :onChangeText set-input-message
:marginBottom 16 :onSubmitEditing send-command}
:marginLeft 16
:marginRight 0
:backgroundColor (:color command)
:height 24
:borderRadius 50}}
[text {:style {:marginTop 3
:marginHorizontal 12
:fontSize 12
:fontFamily font
:color color-white}}
(:text command)]]
[text-input (merge {:underlineColorAndroid :transparent
:style {:flex 1
:marginLeft 8
:marginTop 7
:fontSize 14
:fontFamily font
:color text1-color}
:autoFocus true
:placeholder "Type"
:placeholderTextColor text2-color
:onChangeText set-input-message
:onSubmitEditing send-command}
input-options) input-options)
message] message]
(if (pos? (count message)) (if (pos? (count message))
[touchable-highlight [touchable-highlight {:on-press send-command}
{:on-press send-command [view st/send-container [icon :send st/send-icon]]]
:underlay-color :transparent} [touchable-highlight {:on-press cancel-command-input}
[view {:style {:marginTop 10 [view st/cancel-container
:marginRight 10
:width 36
:height 36
:borderRadius 50
:backgroundColor color-blue}}
[image {:source {:uri :icon_send}
:style {:marginTop 10.5
:marginLeft 12
:width 15
:height 15}}]]]
[touchable-highlight {:on-press cancel-command-input
:underlay-color :transparent}
[view {:style {:marginTop 10
:marginRight 10
:width 36
:height 36}}
[image {:source res/icon-close-gray [image {:source res/icon-close-gray
:style {:marginTop 10.5 :style st/cancel-icon}]]])]))))
:marginLeft 12
:width 12
:height 12}}]]])]))))

View File

@ -1,63 +1,28 @@
(ns syng-im.components.chat.input.simple-command-staged (ns syng-im.components.chat.input.simple-command-staged
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch]]
[syng-im.components.react :refer [android? [syng-im.components.react :refer [view
view
image image
text text
text-input
touchable-highlight]] touchable-highlight]]
[syng-im.components.styles :refer [font
color-black
color-white
chat-background]]
[syng-im.utils.utils :refer [log toast http-post]]
[syng-im.utils.logging :as log]
[syng-im.resources :as res] [syng-im.resources :as res]
[reagent.core :as r])) [syng-im.components.chat.input.input-styles :as st]))
(defn cancel-command-input [staged-command] (defn cancel-command-input [staged-command]
(dispatch [:unstage-command staged-command])) (dispatch [:unstage-command staged-command]))
(defn simple-command-staged-view [staged-command] (defn simple-command-staged-view [staged-command]
(let [chat-id-atom (subscribe [:get-current-chat-id])] (let [command (:command staged-command)]
(fn [staged-command] [view st/staged-command-container
(let [chat-id @chat-id-atom [view st/staged-command-background
command (:command staged-command)] [view st/staged-command-info-container
[view {:style {:flex 1 [view (st/staged-command-text-container command)
:alignItems "flex-start" [text {:style st/staged-command-text} (:text command)]]
:flexDirection "column" [touchable-highlight {:style st/staged-command-cancel
:backgroundColor color-white}} :onPress #(cancel-command-input staged-command)}
[view {:style {:flexDirection "column" [image {:source res/icon-close-gray
:margin 16 :style st/staged-command-cancel-icon}]]]
:padding 12 [text {:style st/staged-command-content}
:backgroundColor chat-background ;; TODO isn't smart
:borderRadius 14}} (if (= (:command command) :keypair-password)
[view {:style {:flexDirection "row"}} "******"
[view {:style {:backgroundColor (:color command) (:content staged-command))]]]))
:height 24
:borderRadius 50
:marginRight 32
:paddingTop 3
:paddingHorizontal 12}}
[text {:style {:fontSize 12
:fontFamily font
:color color-white}}
(:text command)]]
[touchable-highlight {:style {:position "absolute"
:top 7
:right 4}
:onPress #(cancel-command-input
staged-command)
:underlay-color :transparent}
[image {:source res/icon-close-gray
:style {:width 10
:height 10}}]]]
[text {:style {:marginTop 5
:marginHorizontal 0
:fontSize 14
:fontFamily font
:color color-black}}
;; TODO isn't smart
(if (= (:command command) :keypair-password)
"******"
(:content staged-command))]]]))))

View File

@ -1,41 +1,35 @@
(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]]
[syng-im.resources :as res] [syng-im.resources :as res]
[syng-im.components.react :refer [view android? text-input text image [syng-im.components.react :refer [view]]
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.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.components.chat.chat-message-styles :as st]))
(defn new-participants-toolbar [navigator] (defn new-participants-toolbar [navigator]
[toolbar {:navigator navigator [toolbar
:title "Add Participants" {:navigator navigator
:action {:image {:source res/v ;; {:uri "icon_search"} :title "Add Participants"
:style {:width 20 :action {:image {:source res/v ;; {:uri "icon_search"}
:height 18}} :style st/new-participant-image}
:handler (fn [] :handler #(dispatch [:add-new-participants navigator])}}])
(dispatch [:add-new-participants navigator]))}}])
(defn new-participants-row [navigator]
(fn [row _ _]
(r/as-element
[new-participant-contact (js->clj row :keywordize-keys true) 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 st/participants-container
:backgroundColor "white"}}
[new-participants-toolbar navigator] [new-participants-toolbar navigator]
[list-view {:dataSource contacts-ds [list-view {:dataSource contacts-ds
:enableEmptySections true :enableEmptySections true
:renderRow (fn [row section-id row-id] :renderRow (new-participants-row navigator)
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator])) :style st/participants-list}]]))))
:style {:backgroundColor "white"}}]]))))

View File

@ -1,16 +1,11 @@
(ns syng-im.components.chat.plain-message-input (ns syng-im.components.chat.plain-message-input
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]] (:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [android? [syng-im.components.react :refer [view
view icon
image
touchable-highlight touchable-highlight
text-input]] text-input]]
[syng-im.components.styles :refer [font
text2-color
color-white
color-blue]]
[syng-im.components.chat.suggestions :refer [suggestions-view]] [syng-im.components.chat.suggestions :refer [suggestions-view]]
[syng-im.utils.utils :refer [log toast http-post]])) [syng-im.components.chat.plain-message-input-styles :as st]))
(defn set-input-message [message] (defn set-input-message [message]
(dispatch [:set-chat-input-text message])) (dispatch [:set-chat-input-text message]))
@ -29,49 +24,18 @@
staged-commands-atom (subscribe [:get-chat-staged-commands])] staged-commands-atom (subscribe [:get-chat-staged-commands])]
(fn [] (fn []
(let [input-message @input-message-atom] (let [input-message @input-message-atom]
[view {:style {:flexDirection :column}} [view st/input-container
[suggestions-view] [suggestions-view]
[view {:style {:flexDirection :row [view st/input-view
:height 56 [icon :list st/list-icon]
:backgroundColor color-white}} [text-input {:style st/message-input
[image {:source {:uri :icon_list} :autoFocus (pos? (count @staged-commands-atom))
:style {:marginTop 22 :onChangeText set-input-message
:marginRight 6 :onSubmitEditing #(send @chat input-message)}
:marginBottom 6
:marginLeft 21
:width 13
:height 12}}]
[text-input {:underlineColorAndroid :transparent
:style {:flex 1
:marginLeft 16
:marginTop -2
:padding 0
:fontSize 14
:fontFamily font
:color text2-color}
:autoFocus (pos? (count @staged-commands-atom))
:placeholder "Type"
:placeholderTextColor text2-color
:onChangeText set-input-message
:onSubmitEditing #(send @chat input-message)}
input-message] input-message]
[image {:source {:uri :icon_smile} [icon :smile st/smile-icon]
:style {:marginTop 18
:marginRight 18
:width 20
:height 20}}]
(when (or (pos? (count input-message)) (when (or (pos? (count input-message))
(pos? (count @staged-commands-atom))) (pos? (count @staged-commands-atom)))
[touchable-highlight {:on-press #(send @chat input-message) [touchable-highlight {:on-press #(send @chat input-message)}
:underlay-color :transparent} [view st/send-container
[view {:style {:marginTop 10 [icon :send st/send-icon]]])]]))))
:marginRight 10
:width 36
:height 36
:borderRadius 50
:backgroundColor color-blue}}
[image {:source {:uri :icon_send}
:style {:marginTop 10.5
:marginLeft 12
:width 15
:height 15}}]]])]]))))

View File

@ -0,0 +1,50 @@
(ns syng-im.components.chat.plain-message-input-styles
(:require [syng-im.components.styles :refer [font
text2-color
color-white
color-blue]]))
(def input-container
{:flexDirection :column})
(def input-view
{:flexDirection :row
:height 56
:backgroundColor color-white})
(def list-icon
{:marginTop 22
:marginRight 6
:marginBottom 6
:marginLeft 21
:width 13
:height 12})
(def message-input
{:flex 1
:marginLeft 16
:marginTop -2
:padding 0
:fontSize 14
:fontFamily font
:color text2-color})
(def smile-icon
{:marginTop 18
:marginRight 18
:width 20
:height 20})
(def send-icon
{:marginTop 10.5
:marginLeft 12
:width 15
:height 15})
(def send-container
{:marginTop 10
:marginRight 10
:width 36
:height 36
:borderRadius 50
:backgroundColor color-blue})

View File

@ -1,41 +1,36 @@
(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]]
[syng-im.resources :as res] [syng-im.resources :as res]
[syng-im.components.react :refer [view text-input text image [syng-im.components.react :refer [view text-input text image
touchable-highlight]] 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.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.components.chat.chat-message-styles :as st]))
(defn remove-participants-toolbar [navigator] (defn remove-participants-toolbar [navigator]
[toolbar {:navigator navigator [toolbar
:title "Remove Participants" {:navigator navigator
:action {:image {:source res/trash-icon ;; {:uri "icon_search"} :title "Remove Participants"
:style {:width 22 :action {:handler #(dispatch [:remove-selected-participants navigator])
:height 30}} :image {:source res/trash-icon ;; {:uri "icon_search"}
:handler (fn [] :style st/remove-participants-image}}}])
(dispatch [:remove-selected-participants navigator]))}}])
(defn remove-participants-row [navigator]
(fn [row _ _]
(r/as-element
[new-participant-contact (js->clj row :keywordize-keys true) 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 st/participants-container
:backgroundColor "white"}}
[remove-participants-toolbar navigator] [remove-participants-toolbar navigator]
[list-view {:dataSource contacts-ds [list-view {:dataSource contacts-ds
:enableEmptySections true :enableEmptySections true
:renderRow (fn [row section-id row-id] :renderRow (remove-participants-row navigator)
(r/as-element [new-participant-contact (js->clj row :keywordize-keys true) navigator])) :style st/participants-list}]]))))
:style {:backgroundColor "white"}}]]))))

View File

@ -1,56 +1,29 @@
(ns syng-im.components.chat.suggestions (ns syng-im.components.chat.suggestions
(:require-macros (:require-macros
[natal-shell.core :refer [with-error-view]]) [natal-shell.core :refer [with-error-view]])
(:require [clojure.string :as cstr] (:require [re-frame.core :refer [subscribe dispatch]]
[reagent.core :as r]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[syng-im.components.react :refer [view [syng-im.components.react :refer [view
image
text text
touchable-highlight touchable-highlight
list-view list-view
list-item]] list-item]]
[syng-im.components.styles :refer [font
color-white]]
[syng-im.utils.listview :refer [to-datasource]] [syng-im.utils.listview :refer [to-datasource]]
[syng-im.utils.utils :refer [log toast http-post]] [syng-im.components.chat.suggestions-styles :as st]))
[syng-im.utils.logging :as log]))
(defn set-command-input [command] (defn set-command-input [command]
(dispatch [:set-chat-command command])) (dispatch [:set-chat-command command]))
(defn suggestion-list-item [suggestion] (defn suggestion-list-item [suggestion]
[touchable-highlight {:onPress (fn [] [touchable-highlight
(set-command-input (keyword (:command suggestion)))) {:onPress #(set-command-input (keyword (:command suggestion)))}
:underlay-color :transparent} [view st/suggestion-item-container
[view {:style {:flexDirection "row" [view (st/suggestion-background suggestion)
:marginVertical 1 [text {:style st/suggestion-text}
:marginHorizontal 0
:height 40
:backgroundColor color-white}}
[view {:style {:flexDirection "column"
:position "absolute"
:top 10
:left 60
:backgroundColor (:color suggestion)
:borderRadius 10}}
[text {:style {:marginTop -2
:marginHorizontal 10
:fontSize 14
:fontFamily font
:color color-white}}
(:text suggestion)]] (:text suggestion)]]
[text {:style {:flex 1 [text {:style st/suggestion-description}
:position "absolute"
:top 7
:left 190
:lineHeight 18
:fontSize 14
:fontFamily font
:color "black"}}
(:description suggestion)]]]) (:description suggestion)]]])
(defn render-row [row section-id row-id] (defn render-row [row _ _]
(list-item [suggestion-list-item (js->clj row :keywordize-keys true)])) (list-item [suggestion-list-item (js->clj row :keywordize-keys true)]))
(defn suggestions-view [] (defn suggestions-view []
@ -58,12 +31,7 @@
(fn [] (fn []
(let [suggestions @suggestions-atom] (let [suggestions @suggestions-atom]
(when (seq suggestions) (when (seq suggestions)
[view {:style {:flexDirection "row" [view (st/suggestions-container suggestions)
:marginVertical 1
:marginHorizontal 0
:height (min 105 (* 42 (count suggestions)))
:backgroundColor color-white
:borderRadius 5}}
[list-view {:dataSource (to-datasource suggestions) [list-view {:dataSource (to-datasource suggestions)
:enableEmptySections true :enableEmptySections true
:renderRow render-row :renderRow render-row

View File

@ -0,0 +1,44 @@
(ns syng-im.components.chat.suggestions-styles
(:require [syng-im.components.styles :refer [font color-white]]))
(def suggestion-item-container
{:flexDirection :row
:marginVertical 1
:marginHorizontal 0
:height 40
:backgroundColor color-white})
(defn suggestion-background
[{:keys [color]}]
{:flexDirection :column
:position :absolute
:top 10
:left 60
:backgroundColor color
:borderRadius 10})
(def suggestion-text
{:marginTop -2
:marginHorizontal 10
:fontSize 14
:fontFamily font
:color color-white})
(def suggestion-description
{:flex 1
:position :absolute
:top 7
:left 190
:lineHeight 18
:fontSize 14
:fontFamily font
:color :black})
(defn suggestions-container
[suggestions]
{:flexDirection :row
:marginVertical 1
:marginHorizontal 0
:height (min 105 (* 42 (count suggestions)))
:backgroundColor color-white
:borderRadius 5})

View File

@ -0,0 +1,169 @@
(ns syng-im.components.chat-styles
(:require [syng-im.components.styles :refer [font
title-font
color-white
chat-background
online-color
selected-message-color
separator-color
text1-color
text2-color
toolbar-background1]]))
(def chat-view
{:flex 1
:backgroundColor chat-background})
(def toolbar-view
{:flexDirection :row
:height 56
:backgroundColor toolbar-background1
:elevation 2})
(def icon-view
{:width 56
:height 56})
(def back-icon
{:marginTop 21
:marginLeft 23
:width 8
:height 14})
(defn chat-name-view [show-actions]
{:flex 1
:marginLeft (if show-actions 16 0)
:alignItems :flex-start
:justifyContent :center})
(def chat-name-text
{:marginTop -2.5
:color text1-color
:fontSize 16
:fontFamily font})
(def group-icon
{:marginTop 4
:width 14
:height 9})
(def up-icon
{:marginTop 23
:marginLeft 21
:width 14
:height 8})
(def members
{:marginTop -0.5
:marginLeft 4
:fontFamily font
:fontSize 12
:color text2-color})
(def last-activity
{:marginTop 1
:color text2-color
:fontSize 12
:fontFamily font})
(def actions-wrapper
{:backgroundColor toolbar-background1
:elevation 2
:position :absolute
:top 56
:left 0
:right 0})
(def actions-separator
{:marginLeft 16
:height 1.5
:backgroundColor separator-color})
(def actions-view
{:marginVertical 10})
(def action-icon-row
{:flexDirection :row
:height 56})
(def action-icon-view
(merge icon-view
{:alignItems :center
:justifyContent :center}))
(def action-view
{:flex 1
:alignItems :flex-start
:justifyContent :center})
(def action-title
{:marginTop -2.5
:color text1-color
:fontSize 14
:fontFamily font})
(def action-subtitle
{:marginTop 1
:color text2-color
:fontSize 12
:fontFamily font})
(def online-view
{:position :absolute
:top 30
:left 30
: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 (merge online-dot {:left 3}))
(def online-dot-right (merge online-dot {:left 9}))
(def typing-all
{:marginBottom 20})
(def typing-view
{:width 260
:marginTop 10
:paddingLeft 8
:paddingRight 8
:alignItems :flex-start
:alignSelf :flex-start})
(def typing-background
{:borderRadius 14
:padding 12
:height 38
:backgroundColor selected-message-color})
(def typing-text
{:marginTop -2
:fontSize 12
:fontFamily font
:color text2-color})
(def chat-photo
{:borderRadius 50
:width 36
:height 36})
(def actions-overlay
{:position :absolute
:top 0
:bottom 0
:left 0
:right 0})
(def overlay-highlight
{:flex 1})

View File

@ -10,9 +10,8 @@
[syng-im.resources :as res])) [syng-im.resources :as res]))
(defn chat-list-item [chat-obj navigator] (defn chat-list-item [chat-obj navigator]
[touchable-highlight {:on-press (fn [] [touchable-highlight
(dispatch [:show-chat (aget chat-obj "chat-id") navigator :push])) {:on-press #(dispatch [:show-chat (aget chat-obj "chat-id") navigator :push])}
:underlay-color :transparent}
;; TODO add [photo-path delivery-status new-messages-count online] values to chat-obj ;; TODO add [photo-path delivery-status new-messages-count online] values to chat-obj
;; TODO should chat-obj be clj-map? ;; TODO should chat-obj be clj-map?
[view {} [chat-list-item-inner-view (merge (js->clj chat-obj :keywordize-keys true) [view {} [chat-list-item-inner-view (merge (js->clj chat-obj :keywordize-keys true)

View File

@ -68,8 +68,7 @@
:fontSize 14 :fontSize 14
:lineHeight 20}} :lineHeight 20}}
"Members"] "Members"]
[touchable-highlight {:on-press (fn []) [touchable-highlight {:on-press (fn [])}
:underlay-color :transparent}
[view {:style {:flexDirection "row" [view {:style {:flexDirection "row"
:marginBottom 16}} :marginBottom 16}}
[image {:source {:uri "icon_add_gray"} [image {:source {:uri "icon_add_gray"}

View File

@ -9,7 +9,5 @@
(defn contact-view [{:keys [navigator contact]}] (defn contact-view [{:keys [navigator contact]}]
(let [{:keys [whisper-identity]} contact] (let [{:keys [whisper-identity]} contact]
[touchable-highlight {:onPress (fn [] [touchable-highlight {:onPress #(show-chat navigator whisper-identity)}
(show-chat navigator whisper-identity))
:underlay-color :transparent}
[view {} [contact-inner-view contact]]])) [view {} [contact-inner-view contact]]]))

View File

@ -1,5 +1,6 @@
(ns syng-im.components.react (ns syng-im.components.react
(:require [reagent.core :as r])) (:require [reagent.core :as r]
[syng-im.components.styles :as st]))
(set! js/window.React (js/require "react-native")) (set! js/window.React (js/require "react-native"))
@ -8,10 +9,26 @@
(def text (r/adapt-react-class (.-Text js/React))) (def text (r/adapt-react-class (.-Text js/React)))
(def view (r/adapt-react-class (.-View js/React))) (def view (r/adapt-react-class (.-View js/React)))
(def image (r/adapt-react-class (.-Image js/React))) (def image (r/adapt-react-class (.-Image js/React)))
(def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React))) (def touchable-highlight-class (r/adapt-react-class (.-TouchableHighlight js/React)))
(defn touchable-highlight [props content]
[touchable-highlight-class
(merge {:underlay-color :transparent} props)
content])
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React))) (def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
(def list-view (r/adapt-react-class (.-ListView js/React))) (def list-view (r/adapt-react-class (.-ListView js/React)))
(def text-input (r/adapt-react-class (.-TextInput js/React))) (def text-input-class (r/adapt-react-class (.-TextInput js/React)))
(defn text-input [props text]
[text-input-class (merge
{:underlineColorAndroid :transparent
:placeholderTextColor st/text2-color
:placeholder "Type"}
props)
text])
(defn icon [n style]
[image {:source {:uri (keyword (str "icon_" (name n)))}
:style style}])
(def platform (.. js/React -Platform -OS)) (def platform (.. js/React -Platform -OS))

View File

@ -24,16 +24,13 @@
:height 56 :height 56
:elevation 2}} :elevation 2}}
(if nav-action (if nav-action
[touchable-highlight {:on-press (:handler nav-action) [touchable-highlight {:on-press (:handler nav-action)}
:underlay-color :transparent}
[view {:width 56 [view {:width 56
:height 56 :height 56
:alignItems "center" :alignItems "center"
:justifyContent "center"} :justifyContent "center"}
[image (:image nav-action)]]] [image (:image nav-action)]]]
[touchable-highlight {:on-press (fn [] [touchable-highlight {:on-press #(nav-pop navigator)}
(nav-pop navigator))
:underlay-color :transparent}
[view {:width 56 [view {:width 56
:height 56} :height 56}
[image {:source {:uri "icon_back"} [image {:source {:uri "icon_back"}
@ -41,16 +38,15 @@
:marginLeft 23 :marginLeft 23
:width 8 :width 8
:height 14}}]]]) :height 14}}]]])
[view {:style {:flex 1 [view {:style {:flex 1
:alignItems "center" :alignItems "center"
:justifyContent "center"}} :justifyContent "center"}}
[text {:style {:marginTop -2.5 [text {:style {:marginTop -2.5
:color text1-color :color text1-color
:fontSize 16 :fontSize 16
:fontFamily font}} :fontFamily font}}
title]] title]]
[touchable-highlight {:on-press (:handler action) [touchable-highlight {:on-press (:handler action)}
:underlay-color :transparent}
[view {:width 56 [view {:width 56
:height 56 :height 56
:alignItems "center" :alignItems "center"

View File

@ -144,35 +144,31 @@
:to "me"})) (range n))) :to "me"})) (range n)))
(defn store-message! (defn store-message!
[db [_ {chat-id :from [{:keys [new-message]} [_ {chat-id :from}]]
outgoing :outgoing (save-message chat-id new-message))
:as msg}]]
(let [previous-message (first (get-in db [:chats chat-id :messages]))
msg (merge msg
{:same-author (if previous-message
(= (:from previous-message) outgoing)
true)
:same-direction (if previous-message
(= (:outgoing previous-message) outgoing)
true)})]
(save-message chat-id msg)))
(defn add-message-to-db (defn add-message-to-db
[db chat-id {:keys [from outgoing] :as message}] [db chat-id message]
(let [messages [:chats chat-id :messages] (let [messages [:chats chat-id :messages]]
previous-message (first (get-in db [:chats chat-id :messages]))
message (merge message
{:same-author (if previous-message
(= (:from previous-message) from)
true)
:same-direction (if previous-message
(= (:outgoing previous-message) outgoing)
true)})]
(update-in db messages conj message))) (update-in db messages conj message)))
(defn check-author-direction
[db chat-id {:keys [from outgoing] :as message}]
(let [previous-message (first (get-in db [:chats chat-id :messages]))]
(merge message
{:same-author (if previous-message
(= (:from previous-message) from)
true)
:same-direction (if previous-message
(= (:outgoing previous-message) outgoing)
true)})))
(defn receive-message (defn receive-message
[db [_ {chat-id :from :as msg}]] [db [_ {chat-id :from :as message}]]
(add-message-to-db db chat-id msg)) (let [message' (check-author-direction db chat-id message)]
(-> db
(add-message-to-db chat-id message')
(assoc :new-message message'))))
(register-handler :received-msg (register-handler :received-msg
(-> receive-message (-> receive-message
@ -295,41 +291,40 @@
(defn prepare-message (defn prepare-message
[{:keys [identity current-chat-id] :as db} _] [{:keys [identity current-chat-id] :as db} _]
(let [text (get-in db [:chats current-chat-id :input-text]) (let [text (get-in db [:chats current-chat-id :input-text])
{:keys [command]} (check-suggestion db (str text " "))] {:keys [command]} (check-suggestion db (str text " "))
message (check-author-direction
db current-chat-id
{:msg-id (random/id)
:chat-id current-chat-id
:content text
:to current-chat-id
:from identity
:content-type text-content-type
:outgoing true})]
(if command (if command
(set-chat-command db command) (set-chat-command db command)
(assoc db :new-message (when-not (str/blank? text) (assoc db :new-message (when-not (str/blank? text) message)))))
{:msg-id (random/id)
:chat-id current-chat-id
:content text
:to current-chat-id
:from identity
:content-type text-content-type
:outgoing true
;; todo should be refactored
:same-author false
:same-direction false})))))
(defn prepare-command [identity chat-id staged-command] (defn prepare-command [identity chat-id staged-command]
(let [command-key (get-in staged-command [:command :command]) (let [command-key (get-in staged-command [:command :command])
content {:command (name command-key) content {:command (name command-key)
:content (:content staged-command)}] :content (:content staged-command)}]
{:msg-id (random/id) {:msg-id (random/id)
:from identity :from identity
:to chat-id :to chat-id
:content content :content content
:content-type content-type-command :content-type content-type-command
:outgoing true :outgoing true
:handler (:handler staged-command) :handler (:handler staged-command)}))
:same-author false
:same-direction false}))
(defn prepare-staged-commans (defn prepare-staged-commans
[{:keys [current-chat-id identity] :as db} _] [{:keys [current-chat-id identity] :as db} _]
(let [staged-commands (get-in db [:chats current-chat-id :staged-commands])] (let [staged-commands (get-in db [:chats current-chat-id :staged-commands])]
(->> staged-commands (->> staged-commands
(map #(prepare-command identity current-chat-id %)) (map #(prepare-command identity current-chat-id %))
;todo this is wrong :(
(map #(check-author-direction db current-chat-id %))
(assoc db :new-commands)))) (assoc db :new-commands))))
(defn add-message (defn add-message
@ -373,7 +368,6 @@
(defn handle-commands (defn handle-commands
[{:keys [new-commands]}] [{:keys [new-commands]}]
(println new-commands)
(doseq [{{content :content} :content (doseq [{{content :content} :content
handler :handler} new-commands] handler :handler} new-commands]
(when handler (when handler

View File

@ -130,5 +130,5 @@
(defn parse-command-msg-content [commands content] (defn parse-command-msg-content [commands content]
(update content :command #(find-command commands (keyword %)))) (update content :command #(find-command commands (keyword %))))
(defn parse-command-request-msg-content [commands content] (defn parse-command-request [commands content]
(update content :command #(find-command commands (keyword %)))) (update content :command #(find-command commands (keyword %))))

View File

@ -15,7 +15,7 @@
get-chat-command get-chat-command
get-chat-command-content get-chat-command-content
get-chat-command-request get-chat-command-request
parse-command-request-msg-content]] parse-command-request]]
[syng-im.handlers.suggestions :refer [get-suggestions]])) [syng-im.handlers.suggestions :refer [get-suggestions]]))
;; -- Chat -------------------------------------------------------------- ;; -- Chat --------------------------------------------------------------