parent
4adbc18dab
commit
0ed10176b2
Binary file not shown.
After Width: | Height: | Size: 530 B |
|
@ -0,0 +1,78 @@
|
||||||
|
(ns messenger.android.chat
|
||||||
|
(:require-macros
|
||||||
|
[natal-shell.components :refer [view text image touchable-highlight list-view
|
||||||
|
toolbar-android]]
|
||||||
|
[natal-shell.data-source :refer [data-source clone-with-rows]]
|
||||||
|
[natal-shell.core :refer [with-error-view]]
|
||||||
|
[natal-shell.alert :refer [alert]])
|
||||||
|
(:require [om.next :as om :refer-macros [defui]]
|
||||||
|
[re-natal.support :as sup]
|
||||||
|
[messenger.state :as state]
|
||||||
|
[messenger.android.resources :as res]))
|
||||||
|
|
||||||
|
(defn nav-pop [nav]
|
||||||
|
(binding [state/*nav-render* false]
|
||||||
|
(.pop nav)))
|
||||||
|
|
||||||
|
(defui Message
|
||||||
|
static om/Ident
|
||||||
|
(ident [this {:keys [id]}]
|
||||||
|
[:message/by-id id])
|
||||||
|
static om/IQuery
|
||||||
|
(query [this]
|
||||||
|
'[:id :body :delivery-status :datetime])
|
||||||
|
Object
|
||||||
|
(render [this]
|
||||||
|
(let [{:keys [id body delivery-status datetime]}
|
||||||
|
(om/props this)]
|
||||||
|
(text {:style {:color "#AAB2B2"
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:fontSize 14
|
||||||
|
:marginTop 2
|
||||||
|
:paddingRight 10}}
|
||||||
|
body))))
|
||||||
|
|
||||||
|
(def message (om/factory Message {:keyfn :id}))
|
||||||
|
|
||||||
|
(defn render-row [row section-id row-id]
|
||||||
|
(message (js->clj row :keywordize-keys true)))
|
||||||
|
|
||||||
|
(defn generate-message [n]
|
||||||
|
{:id n
|
||||||
|
:body "Hi"
|
||||||
|
:delivery-status (if (< (rand) 0.5) :delivered :seen)
|
||||||
|
:datetime "15:30"})
|
||||||
|
|
||||||
|
(defn generate-messages [n]
|
||||||
|
(map generate-message (range 1 (inc n))))
|
||||||
|
|
||||||
|
(defn load-message []
|
||||||
|
(swap! state/app-state update :contacts-ds
|
||||||
|
#(clone-with-rows %
|
||||||
|
(vec (generate-messages 10)))))
|
||||||
|
|
||||||
|
(defui Chat
|
||||||
|
;; static om/IQuery
|
||||||
|
;; (query [this]
|
||||||
|
;; '[:contacts-ds])
|
||||||
|
Object
|
||||||
|
;; (componentDidMount [this]
|
||||||
|
;; (load-contacts))
|
||||||
|
(render [this]
|
||||||
|
(let [{:keys [contacts-ds]} (om/props this)
|
||||||
|
{:keys [nav]} (om/get-computed this)]
|
||||||
|
(view {:style {:flex 1}}
|
||||||
|
(toolbar-android {:logo res/logo-icon
|
||||||
|
:title "Chat name"
|
||||||
|
:style {:backgroundColor "#e9eaed"
|
||||||
|
:height 56}
|
||||||
|
:navIcon res/nav-back-icon
|
||||||
|
:onIconClicked (fn []
|
||||||
|
(nav-pop nav))})
|
||||||
|
(text {} "Hello")
|
||||||
|
;; (list-view {:dataSource contacts-ds
|
||||||
|
;; :renderRow render-row
|
||||||
|
;; :style {}})
|
||||||
|
))))
|
||||||
|
|
||||||
|
(def chat (om/factory Chat))
|
|
@ -7,18 +7,21 @@
|
||||||
[natal-shell.alert :refer [alert]])
|
[natal-shell.alert :refer [alert]])
|
||||||
(:require [om.next :as om :refer-macros [defui]]
|
(:require [om.next :as om :refer-macros [defui]]
|
||||||
[re-natal.support :as sup]
|
[re-natal.support :as sup]
|
||||||
[messenger.state :as state]))
|
[messenger.state :as state]
|
||||||
|
[messenger.android.resources :as res]
|
||||||
|
[messenger.android.chat :refer [chat]]))
|
||||||
|
|
||||||
(def fake-contacts? true)
|
(def fake-contacts? true)
|
||||||
|
|
||||||
(set! js/React (js/require "react-native"))
|
|
||||||
(def react-native-contacts (js/require "react-native-contacts"))
|
(def react-native-contacts (js/require "react-native-contacts"))
|
||||||
|
|
||||||
(def logo-icon (js/require "./images/logo.png"))
|
(defn nav-push [nav route]
|
||||||
(def user-no-photo (js/require "./images/no-photo.png"))
|
(binding [state/*nav-render* false]
|
||||||
(def online-icon (js/require "./images/online.png"))
|
(.push nav (clj->js route))))
|
||||||
(def seen-icon (js/require "./images/seen.png"))
|
|
||||||
(def delivered-icon (js/require "./images/delivered.png"))
|
(defn show-chat [nav]
|
||||||
|
(nav-push nav {:component chat
|
||||||
|
:name "chat"}))
|
||||||
|
|
||||||
(defui Contact
|
(defui Contact
|
||||||
static om/Ident
|
static om/Ident
|
||||||
|
@ -30,107 +33,111 @@
|
||||||
Object
|
Object
|
||||||
(render [this]
|
(render [this]
|
||||||
(let [{:keys [name photo delivery-status datetime new-messages-count online]}
|
(let [{:keys [name photo delivery-status datetime new-messages-count online]}
|
||||||
(om/props this)]
|
(dissoc (om/props this) :om.next/computed)
|
||||||
(view {:style {:flexDirection "row"
|
{:keys [nav]} (om/get-computed this)]
|
||||||
:marginTop 5
|
(touchable-highlight
|
||||||
:marginBottom 5
|
{:onPress (fn [] (show-chat nav))}
|
||||||
:paddingLeft 15
|
(view {:style {:flexDirection "row"
|
||||||
:paddingRight 15
|
:marginTop 5
|
||||||
:height 75
|
:marginBottom 5
|
||||||
:transform [{:translateX 0}
|
:paddingLeft 15
|
||||||
{:translateY 0}]}}
|
:paddingRight 15
|
||||||
(view {:width 54
|
:height 75
|
||||||
:height 54}
|
:transform [{:translateX 0}
|
||||||
;;; photo
|
{:translateY 0}]}}
|
||||||
(view {:width 54
|
(view {:width 54
|
||||||
:height 54
|
:height 54}
|
||||||
:borderRadius 50
|
;;; photo
|
||||||
:backgroundColor "#FFFFFF"
|
(view {:width 54
|
||||||
:elevation 6}
|
:height 54
|
||||||
(image {:source (if (< 0 (count photo))
|
:borderRadius 50
|
||||||
{:uri photo}
|
:backgroundColor "#FFFFFF"
|
||||||
user-no-photo)
|
:elevation 6}
|
||||||
:style {:borderWidth 2
|
(image {:source (if (< 0 (count photo))
|
||||||
:borderColor "#FFFFFF"
|
{:uri photo}
|
||||||
:borderRadius 50
|
res/user-no-photo)
|
||||||
:width 54
|
:style {:borderWidth 2
|
||||||
:height 54
|
:borderColor "#FFFFFF"
|
||||||
:position "absolute"
|
:borderRadius 50
|
||||||
;; :top 2
|
:width 54
|
||||||
;; :right 2
|
:height 54
|
||||||
}}))
|
:position "absolute"
|
||||||
;;; online
|
;; :top 2
|
||||||
(when online
|
;; :right 2
|
||||||
(view {:position "absolute"
|
}}))
|
||||||
:top 41
|
;;; online
|
||||||
:left 36
|
(when online
|
||||||
:width 12
|
(view {:position "absolute"
|
||||||
:height 12
|
:top 41
|
||||||
:borderRadius 50
|
:left 36
|
||||||
:backgroundColor "#FFFFFF"
|
:width 12
|
||||||
:elevation 6}
|
:height 12
|
||||||
(image {:source online-icon
|
:borderRadius 50
|
||||||
:style {:width 12
|
:backgroundColor "#FFFFFF"
|
||||||
:height 12}}))))
|
:elevation 6}
|
||||||
(view {:style {:flexDirection "column"
|
(image {:source res/online-icon
|
||||||
:marginLeft 7
|
:style {:width 12
|
||||||
:marginRight 10
|
:height 12}}))))
|
||||||
:flex 1
|
(view {:style {:flexDirection "column"
|
||||||
:position "relative"}}
|
:marginLeft 7
|
||||||
;;; name
|
:marginRight 10
|
||||||
(text {:style {:fontSize 15
|
:flex 1
|
||||||
:fontFamily "Avenir-Roman"}} name)
|
:position "relative"}}
|
||||||
;;; last message
|
;;; name
|
||||||
(text {:style {:color "#AAB2B2"
|
(text {:style {:fontSize 15
|
||||||
:fontFamily "Avenir-Roman"
|
:fontFamily "Avenir-Roman"}} name)
|
||||||
:fontSize 14
|
;;; last message
|
||||||
:marginTop 2
|
(text {:style {:color "#AAB2B2"
|
||||||
:paddingRight 10}}
|
:fontFamily "Avenir-Roman"
|
||||||
(str "Hi, I'm " name)))
|
:fontSize 14
|
||||||
(view {:style {:flexDirection "column"}}
|
:marginTop 2
|
||||||
;;; delivery status
|
:paddingRight 10}}
|
||||||
(view {:style {:flexDirection "row"
|
(str "Hi, I'm " name)))
|
||||||
:position "absolute"
|
(view {:style {:flexDirection "column"}}
|
||||||
:top 0
|
;;; delivery status
|
||||||
:right 0}}
|
(view {:style {:flexDirection "row"
|
||||||
(when delivery-status
|
:position "absolute"
|
||||||
(image {:source (if (= (keyword delivery-status) :seen)
|
:top 0
|
||||||
seen-icon
|
:right 0}}
|
||||||
delivered-icon)
|
(when delivery-status
|
||||||
:style {:marginTop 5}}))
|
(image {:source (if (= (keyword delivery-status) :seen)
|
||||||
;;; datetime
|
res/seen-icon
|
||||||
(text {:style {:fontFamily "Avenir-Roman"
|
res/delivered-icon)
|
||||||
:fontSize 11
|
:style {:marginTop 5}}))
|
||||||
:color "#AAB2B2"
|
;;; datetime
|
||||||
:letterSpacing 1
|
(text {:style {:fontFamily "Avenir-Roman"
|
||||||
:lineHeight 15
|
:fontSize 11
|
||||||
:marginLeft 5}}
|
:color "#AAB2B2"
|
||||||
datetime))
|
:letterSpacing 1
|
||||||
;;; new messages count
|
:lineHeight 15
|
||||||
(when (< 0 new-messages-count)
|
:marginLeft 5}}
|
||||||
(view {:style {:position "absolute"
|
datetime))
|
||||||
:right 0
|
;;; new messages count
|
||||||
:bottom 24
|
(when (< 0 new-messages-count)
|
||||||
:width 18
|
(view {:style {:position "absolute"
|
||||||
:height 18
|
:right 0
|
||||||
:backgroundColor "#6BC6C8"
|
:bottom 24
|
||||||
:borderColor "#FFFFFF"
|
:width 18
|
||||||
:borderRadius 50
|
:height 18
|
||||||
:alignSelf "flex-end"}}
|
:backgroundColor "#6BC6C8"
|
||||||
(text {:style {:width 18
|
:borderColor "#FFFFFF"
|
||||||
:height 17
|
:borderRadius 50
|
||||||
:fontFamily "Avenir-Roman"
|
:alignSelf "flex-end"}}
|
||||||
:fontSize 10
|
(text {:style {:width 18
|
||||||
:color "#FFFFFF"
|
:height 17
|
||||||
:lineHeight 19
|
:fontFamily "Avenir-Roman"
|
||||||
:textAlign "center"
|
:fontSize 10
|
||||||
:top 1}}
|
:color "#FFFFFF"
|
||||||
new-messages-count))))))))
|
:lineHeight 19
|
||||||
|
:textAlign "center"
|
||||||
|
:top 1}}
|
||||||
|
new-messages-count)))))))))
|
||||||
|
|
||||||
(def contact (om/factory Contact {:keyfn :name}))
|
(def contact (om/factory Contact {:keyfn :name}))
|
||||||
|
|
||||||
(defn render-row [row section-id row-id]
|
(defn render-row [nav row section-id row-id]
|
||||||
(contact (js->clj row :keywordize-keys true)))
|
(contact (om/computed (js->clj row :keywordize-keys true)
|
||||||
|
{:nav nav})))
|
||||||
|
|
||||||
(defn generate-contact [n]
|
(defn generate-contact [n]
|
||||||
{:name (str "Contact " n)
|
{:name (str "Contact " n)
|
||||||
|
@ -167,14 +174,15 @@
|
||||||
(componentDidMount [this]
|
(componentDidMount [this]
|
||||||
(load-contacts))
|
(load-contacts))
|
||||||
(render [this]
|
(render [this]
|
||||||
(let [{:keys [contacts-ds]} (om/props this)]
|
(let [{:keys [contacts-ds]} (om/props this)
|
||||||
|
{:keys [nav]} (om/get-computed this)]
|
||||||
(view {:style {:flex 1}}
|
(view {:style {:flex 1}}
|
||||||
(toolbar-android {:logo logo-icon
|
(toolbar-android {:logo res/logo-icon
|
||||||
:title "Chats"
|
:title "Chats"
|
||||||
:style {:backgroundColor "#e9eaed"
|
:style {:backgroundColor "#e9eaed"
|
||||||
:height 56}})
|
:height 56}})
|
||||||
(list-view {:dataSource contacts-ds
|
(list-view {:dataSource contacts-ds
|
||||||
:renderRow render-row
|
:renderRow (partial render-row nav)
|
||||||
:style {}})))))
|
:style {}})))))
|
||||||
|
|
||||||
(def contacts-list (om/factory ContactsList))
|
(def contacts-list (om/factory ContactsList))
|
||||||
|
|
|
@ -1,30 +1,52 @@
|
||||||
(ns messenger.android.core
|
(ns messenger.android.core
|
||||||
(:require-macros
|
(:require-macros
|
||||||
[natal-shell.components :refer [view text image touchable-highlight list-view
|
[natal-shell.components :refer [navigator view text image touchable-highlight list-view
|
||||||
toolbar-android]]
|
toolbar-android]]
|
||||||
[natal-shell.data-source :refer [data-source clone-with-rows]]
|
[natal-shell.data-source :refer [data-source clone-with-rows]]
|
||||||
|
[natal-shell.back-android :refer [add-event-listener]]
|
||||||
[natal-shell.core :refer [with-error-view]]
|
[natal-shell.core :refer [with-error-view]]
|
||||||
[natal-shell.alert :refer [alert]])
|
[natal-shell.alert :refer [alert]])
|
||||||
(:require [om.next :as om :refer-macros [defui]]
|
(:require [om.next :as om :refer-macros [defui]]
|
||||||
[re-natal.support :as sup]
|
[re-natal.support :as sup]
|
||||||
[messenger.state :as state]
|
[messenger.state :as state]
|
||||||
[messenger.android.contacts-list :as contacts-list]))
|
[messenger.android.contacts-list :refer [contacts-list]]
|
||||||
|
[messenger.android.chat :refer [chat]]))
|
||||||
|
|
||||||
(set! js/React (js/require "react-native"))
|
|
||||||
(def app-registry (.-AppRegistry js/React))
|
(def app-registry (.-AppRegistry js/React))
|
||||||
|
|
||||||
|
(def initialized-atom (atom false))
|
||||||
|
(defn init-back-button-handler! [nav]
|
||||||
|
(if (not @initialized-atom)
|
||||||
|
(swap! initialized-atom
|
||||||
|
(fn [initialized]
|
||||||
|
(when (not initialized)
|
||||||
|
(add-event-listener "hardwareBackPress"
|
||||||
|
(fn []
|
||||||
|
(binding [state/*nav-render* false]
|
||||||
|
(when (< 1 (.-length (.getCurrentRoutes nav)))
|
||||||
|
(.pop nav)
|
||||||
|
true)))))
|
||||||
|
true))))
|
||||||
|
|
||||||
(defui AppRoot
|
(defui AppRoot
|
||||||
static om/IQuery
|
static om/IQuery
|
||||||
(query [this]
|
(query [this]
|
||||||
'[:contacts-ds])
|
'[:page :contacts-ds])
|
||||||
Object
|
Object
|
||||||
(render [this]
|
(render [this]
|
||||||
(let [{:keys [contacts-ds]} (om/props this)]
|
(let [{:keys [page contacts-ds]} (om/props this)]
|
||||||
(contacts-list/contacts-list (om/props this)))))
|
(navigator
|
||||||
|
{:initialRoute {:component contacts-list}
|
||||||
|
:renderScene (fn [route nav]
|
||||||
|
(when state/*nav-render*
|
||||||
|
(init-back-button-handler! nav)
|
||||||
|
(let [{:keys [component]} (js->clj route :keywordize-keys true)]
|
||||||
|
(component (om/computed (om/props this) {:nav nav})))))}))))
|
||||||
|
|
||||||
(swap! state/app-state assoc :contacts-ds
|
(swap! state/app-state assoc :contacts-ds
|
||||||
(data-source {:rowHasChanged (fn [row1 row2]
|
(data-source {:rowHasChanged (fn [row1 row2]
|
||||||
(not= row1 row2))}))
|
(not= row1 row2))}))
|
||||||
|
(swap! state/app-state assoc :component contacts-list)
|
||||||
|
|
||||||
(defonce RootNode (sup/root-node! 1))
|
(defonce RootNode (sup/root-node! 1))
|
||||||
(defonce app-root (om/factory RootNode))
|
(defonce app-root (om/factory RootNode))
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
(ns messenger.android.resources)
|
||||||
|
|
||||||
|
(def logo-icon (js/require "./images/logo.png"))
|
||||||
|
(def nav-back-icon (js/require "./images/nav-back.png"))
|
||||||
|
(def user-no-photo (js/require "./images/no-photo.png"))
|
||||||
|
(def online-icon (js/require "./images/online.png"))
|
||||||
|
(def seen-icon (js/require "./images/seen.png"))
|
||||||
|
(def delivered-icon (js/require "./images/delivered.png"))
|
|
@ -2,7 +2,12 @@
|
||||||
(:require [om.next :as om]
|
(:require [om.next :as om]
|
||||||
[re-natal.support :as sup]))
|
[re-natal.support :as sup]))
|
||||||
|
|
||||||
(defonce app-state (atom {}))
|
(set! js/React (js/require "react-native"))
|
||||||
|
|
||||||
|
(defonce app-state (atom {:component nil}))
|
||||||
|
(def ^{:dynamic true :private true} *nav-render*
|
||||||
|
"Flag to suppress navigator re-renders from outside om when pushing/popping."
|
||||||
|
true)
|
||||||
|
|
||||||
(defmulti read om/dispatch)
|
(defmulti read om/dispatch)
|
||||||
(defmethod read :default
|
(defmethod read :default
|
||||||
|
|
Loading…
Reference in New Issue