commit
44074bd054
|
@ -2,28 +2,22 @@
|
|||
(:require-macros
|
||||
[natal-shell.back-android :refer [add-event-listener remove-event-listener]])
|
||||
(:require [reagent.core :as r :refer [atom]]
|
||||
[cljs.core :as cljs]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.handlers]
|
||||
[syng-im.subs]
|
||||
[syng-im.components.react :refer [navigator app-registry]]
|
||||
[syng-im.components.contact-list.contact-list :refer [contact-list]]
|
||||
[syng-im.components.discovery.discovery :refer [discovery]]
|
||||
[syng-im.components.discovery.discovery-tag :refer [discovery-tag]]
|
||||
[syng-im.components.chat :refer [chat]]
|
||||
[syng-im.components.chats.chats-list :refer [chats-list]]
|
||||
[syng-im.components.chats.new-group :refer [new-group]]
|
||||
[syng-im.components.chat.new-participants :refer [new-participants]]
|
||||
[syng-im.components.chat.remove-participants :refer [remove-participants]]
|
||||
[syng-im.components.profile :refer [profile my-profile]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.contacts.screen :refer [contact-list]]
|
||||
[syng-im.discovery.screen :refer [discovery]]
|
||||
[syng-im.discovery.tag :refer [discovery-tag]]
|
||||
[syng-im.chat.screen :refer [chat]]
|
||||
[syng-im.chats-list.screen :refer [chats-list]]
|
||||
[syng-im.new-group.screen :refer [new-group]]
|
||||
[syng-im.participants.views.create :refer [new-participants]]
|
||||
[syng-im.participants.views.remove :refer [remove-participants]]
|
||||
[syng-im.profile.screen :refer [profile my-profile]]
|
||||
[syng-im.utils.utils :refer [toast]]
|
||||
[syng-im.navigation :as nav]
|
||||
[syng-im.utils.encryption]))
|
||||
|
||||
(def back-button-handler (cljs/atom {:nav nil
|
||||
:handler nil}))
|
||||
|
||||
(defn init-back-button-handler! []
|
||||
(let [new-listener (fn []
|
||||
;; todo: it might be better always return false from
|
||||
|
@ -37,7 +31,7 @@
|
|||
|
||||
(defn app-root []
|
||||
(let [signed-up (subscribe [:signed-up])
|
||||
view-id (subscribe [:view-id])]
|
||||
view-id (subscribe [:view-id])]
|
||||
(fn []
|
||||
(case (if @signed-up @view-id :chat)
|
||||
:discovery [discovery]
|
||||
|
@ -57,7 +51,7 @@
|
|||
(dispatch [:initialize-chats])
|
||||
(dispatch [:initialize-protocol])
|
||||
(dispatch [:load-user-phone-number])
|
||||
(dispatch [:load-syng-contacts])
|
||||
(dispatch [:load-contacts])
|
||||
;; load commands from remote server (todo: uncomment)
|
||||
;; (dispatch [:load-commands])
|
||||
(dispatch [:init-console-chat])
|
||||
|
|
|
@ -0,0 +1,346 @@
|
|||
(ns syng-im.chat.handlers
|
||||
(:require [re-frame.core :refer [register-handler enrich after debug dispatch]]
|
||||
[syng-im.models.commands :as commands]
|
||||
[clojure.string :as str]
|
||||
[syng-im.chat.suggestions :as suggestions]
|
||||
[syng-im.protocol.api :as api]
|
||||
[syng-im.models.messages :as messages]
|
||||
[syng-im.constants :refer [text-content-type
|
||||
content-type-command]]
|
||||
[syng-im.utils.random :as random]
|
||||
[syng-im.components.react :as r]
|
||||
[syng-im.handlers.sign-up :as sign-up-service]
|
||||
[syng-im.models.chats :as chats]
|
||||
[syng-im.navigation.handlers :as nav]
|
||||
[syng-im.models.chats :as c]))
|
||||
|
||||
(register-handler :set-show-actions
|
||||
(fn [db [_ show-actions]]
|
||||
(assoc db :show-actions show-actions)))
|
||||
|
||||
(register-handler :load-more-messages
|
||||
(fn [db _]
|
||||
db
|
||||
;; TODO implement
|
||||
#_(let [chat-id (get-in db [:chat :current-chat-id])
|
||||
messages [:chats chat-id :messages]
|
||||
new-messages (gen-messages 10)]
|
||||
(update-in db messages concat new-messages))))
|
||||
|
||||
(defn safe-trim [s]
|
||||
(when (string? s)
|
||||
(str/trim s)))
|
||||
|
||||
(register-handler :cancel-command
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(-> db
|
||||
(assoc-in [:chats current-chat-id :command-input] {})
|
||||
(update-in [:chats current-chat-id :input-text] safe-trim))))
|
||||
|
||||
(register-handler :set-chat-command-content
|
||||
(fn [db [_ content]]
|
||||
(commands/set-chat-command-content db content)))
|
||||
|
||||
(defn update-input-text
|
||||
[{:keys [current-chat-id] :as db} text]
|
||||
(assoc-in db [:chats current-chat-id :input-text] text))
|
||||
|
||||
(register-handler :stage-command
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(let [db (update-input-text db nil)
|
||||
{:keys [command content]}
|
||||
(get-in db [:chats current-chat-id :command-input])
|
||||
command-info {:command command
|
||||
:content content
|
||||
:handler (:handler command)}]
|
||||
(commands/stage-command db command-info))))
|
||||
|
||||
(register-handler :set-response-chat-command
|
||||
(fn [db [_ to-msg-id command-key]]
|
||||
(commands/set-response-chat-command db to-msg-id command-key)))
|
||||
|
||||
(defn update-text
|
||||
[db [_ text]]
|
||||
(update-input-text db text))
|
||||
|
||||
(defn update-command [db [_ text]]
|
||||
(let [{:keys [command]} (suggestions/check-suggestion db text)]
|
||||
(commands/set-chat-command db command)))
|
||||
|
||||
(register-handler :set-chat-input-text
|
||||
((enrich update-command) update-text))
|
||||
|
||||
(register-handler :send-group-chat-msg
|
||||
(fn [db [_ chat-id text]]
|
||||
(let [{msg-id :msg-id
|
||||
{from :from} :msg} (api/send-group-user-msg {:group-id chat-id
|
||||
:content text})
|
||||
msg {:msg-id msg-id
|
||||
:from from
|
||||
:to nil
|
||||
:content text
|
||||
:content-type text-content-type
|
||||
:outgoing true}]
|
||||
(messages/save-message chat-id msg))))
|
||||
|
||||
(defn console? [s]
|
||||
(= "console" s))
|
||||
|
||||
(def not-console?
|
||||
(complement console?))
|
||||
|
||||
(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 add-message-to-db
|
||||
[db chat-id message]
|
||||
(let [messages [:chats chat-id :messages]]
|
||||
(update-in db messages conj message)))
|
||||
|
||||
(defn prepare-message
|
||||
[{:keys [identity current-chat-id] :as db} _]
|
||||
(let [text (get-in db [:chats current-chat-id :input-text])
|
||||
{:keys [command]} (suggestions/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
|
||||
(commands/set-chat-command db command)
|
||||
(assoc db :new-message (when-not (str/blank? text) message)))))
|
||||
|
||||
(defn prepare-command [identity chat-id staged-command]
|
||||
(let [command-key (get-in staged-command [:command :command])
|
||||
content {:command (name command-key)
|
||||
:content (:content staged-command)}]
|
||||
{:msg-id (random/id)
|
||||
:from identity
|
||||
:to chat-id
|
||||
:content content
|
||||
:content-type content-type-command
|
||||
:outgoing true
|
||||
:handler (:handler staged-command)}))
|
||||
|
||||
(defn prepare-staged-commans
|
||||
[{:keys [current-chat-id identity] :as db} _]
|
||||
(let [staged-commands (get-in db [:chats current-chat-id :staged-commands])]
|
||||
(->> staged-commands
|
||||
(map #(prepare-command identity current-chat-id %))
|
||||
;todo this is wrong :(
|
||||
(map #(check-author-direction db current-chat-id %))
|
||||
(assoc db :new-commands))))
|
||||
|
||||
(defn add-message
|
||||
[{:keys [new-message current-chat-id] :as db}]
|
||||
(if new-message
|
||||
(add-message-to-db db current-chat-id new-message)
|
||||
db))
|
||||
|
||||
(defn add-commands
|
||||
[{:keys [new-commands current-chat-id] :as db}]
|
||||
(reduce
|
||||
#(add-message-to-db %1 current-chat-id %2)
|
||||
db
|
||||
new-commands))
|
||||
|
||||
(defn clear-input
|
||||
[{:keys [current-chat-id new-message] :as db} _]
|
||||
(if new-message
|
||||
(assoc-in db [:chats current-chat-id :input-text] nil)
|
||||
db))
|
||||
|
||||
(defn clear-staged-commands
|
||||
[{:keys [current-chat-id] :as db} _]
|
||||
(assoc-in db [:chats current-chat-id :staged-commands] []))
|
||||
|
||||
(defn send-message!
|
||||
[{:keys [new-message current-chat-id]} _]
|
||||
(when (and new-message (not-console? current-chat-id))
|
||||
(api/send-user-msg {:to current-chat-id
|
||||
:content (:content new-message)})))
|
||||
|
||||
(defn save-message-to-realm!
|
||||
[{:keys [new-message current-chat-id]} _]
|
||||
(when new-message
|
||||
(messages/save-message current-chat-id new-message)))
|
||||
|
||||
(defn save-commands-to-realm!
|
||||
[{:keys [new-commands current-chat-id]} _]
|
||||
(doseq [new-command new-commands]
|
||||
(messages/save-message current-chat-id (dissoc new-command :handler))))
|
||||
|
||||
(defn handle-commands
|
||||
[{:keys [new-commands]}]
|
||||
(doseq [{{content :content} :content
|
||||
handler :handler} new-commands]
|
||||
(when handler
|
||||
(handler content))))
|
||||
|
||||
(register-handler :send-chat-msg
|
||||
(-> prepare-message
|
||||
((enrich prepare-staged-commans))
|
||||
((enrich add-message))
|
||||
((enrich add-commands))
|
||||
((enrich clear-input))
|
||||
((enrich clear-staged-commands))
|
||||
((after (fn [_ _] (r/dismiss-keyboard!))))
|
||||
((after send-message!))
|
||||
((after save-message-to-realm!))
|
||||
((after save-commands-to-realm!))
|
||||
((after handle-commands))))
|
||||
|
||||
(register-handler :unstage-command
|
||||
(fn [db [_ staged-command]]
|
||||
(let []
|
||||
(commands/unstage-command db staged-command))))
|
||||
|
||||
(register-handler :set-chat-command
|
||||
(fn [db [_ command-key]]
|
||||
;; todo what is going on there?!
|
||||
(commands/set-chat-command db command-key)))
|
||||
|
||||
(register-handler :init-console-chat
|
||||
(fn [db [_]]
|
||||
(sign-up-service/init db)))
|
||||
|
||||
(register-handler :save-password
|
||||
(fn [db [_ password]]
|
||||
(sign-up-service/save-password password)
|
||||
(assoc db :password-saved true)))
|
||||
|
||||
(register-handler :sign-up
|
||||
(-> (fn [db [_ phone-number]]
|
||||
;; todo save phone number to db
|
||||
(assoc db :user-phone-number phone-number))
|
||||
((after (fn [& _] (sign-up-service/on-sign-up-response))))))
|
||||
|
||||
(register-handler :sign-up-confirm
|
||||
(fn [db [_ confirmation-code]]
|
||||
(sign-up-service/on-send-code-response confirmation-code)
|
||||
(sign-up-service/set-signed-up db true)))
|
||||
|
||||
(register-handler :set-signed-up
|
||||
(fn [db [_ signed-up]]
|
||||
(sign-up-service/set-signed-up db signed-up)))
|
||||
|
||||
|
||||
(defn load-messages!
|
||||
([db] (load-messages! db nil))
|
||||
([db _]
|
||||
(->> (:current-chat-id db)
|
||||
messages/get-messages
|
||||
(assoc db :messages))))
|
||||
|
||||
(defn init-chat
|
||||
([db] (init-chat db nil))
|
||||
([{:keys [messages current-chat-id] :as db} _]
|
||||
(assoc-in db [:chats current-chat-id :messages] messages)))
|
||||
|
||||
(register-handler :init-chat
|
||||
(-> load-messages!
|
||||
((enrich init-chat))
|
||||
debug))
|
||||
|
||||
(defn initialize-chats
|
||||
[{:keys [loaded-chats] :as db} _]
|
||||
(let [chats (->> loaded-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
[chat-id chat]))
|
||||
(into {}))
|
||||
ids (set (keys chats))]
|
||||
(-> db
|
||||
(assoc :chats chats)
|
||||
(assoc :chats-ids ids)
|
||||
(dissoc :loaded-chats))))
|
||||
|
||||
(defn load-chats!
|
||||
[db _]
|
||||
(assoc db :loaded-chats (chats/chats-list)))
|
||||
|
||||
(register-handler :initialize-chats
|
||||
((enrich initialize-chats) load-chats!))
|
||||
|
||||
(defn store-message!
|
||||
[{:keys [new-message]} [_ {chat-id :from}]]
|
||||
(messages/save-message chat-id new-message))
|
||||
|
||||
(defn receive-message
|
||||
[db [_ {chat-id :from :as message}]]
|
||||
(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
|
||||
(-> receive-message
|
||||
((after store-message!))))
|
||||
|
||||
(register-handler :group-received-msg
|
||||
(fn [db [_ {chat-id :group-id :as msg}]]
|
||||
(messages/save-message chat-id msg)
|
||||
db))
|
||||
|
||||
(defn load-chat!
|
||||
[{:keys [chats current-chat-id] :as db}]
|
||||
(when-not (chats current-chat-id)
|
||||
(c/create-chat {}))
|
||||
db)
|
||||
|
||||
(defmethod nav/preload-data! :chat
|
||||
[{:keys [current-chat-id] :as db} [_ _ id]]
|
||||
(-> db
|
||||
(assoc :current-chat-id (or id current-chat-id))
|
||||
load-messages!
|
||||
init-chat))
|
||||
|
||||
(defn prepare-chat
|
||||
[{:keys [contacts] :as db} [_ contcat-id]]
|
||||
(let [name (get-in contacts [contcat-id :name])
|
||||
chat {:chat-id contcat-id
|
||||
:name name
|
||||
:group-chat false
|
||||
:is-active true
|
||||
:timestamp (.getTime (js/Date.))
|
||||
;; todo how to choose color?
|
||||
;; todo do we need to have some color for not group chat?
|
||||
:contacts [{:identity contcat-id
|
||||
:text-color :#FFFFFF
|
||||
:background-color :#AB7967}]}]
|
||||
(assoc db :new-chat chat)))
|
||||
|
||||
(defn add-chat [{:keys [new-chat] :as db} [_ chat-id]]
|
||||
(-> db
|
||||
(update :chats assoc chat-id new-chat)
|
||||
(update :chats-ids conj chat-id)))
|
||||
|
||||
(defn save-chat!
|
||||
[{:keys [new-chat]} _]
|
||||
(chats/create-chat new-chat))
|
||||
|
||||
(defn open-chat!
|
||||
[_ [_ chat-id]]
|
||||
(dispatch [:navigate-to :chat chat-id]))
|
||||
|
||||
(register-handler :start-chat
|
||||
(-> prepare-chat
|
||||
((enrich add-chat))
|
||||
((after save-chat!))
|
||||
((after open-chat!))
|
||||
debug))
|
||||
|
||||
(register-handler :switch-command-suggestions
|
||||
(fn [db [_]]
|
||||
(suggestions/switch-command-suggestions db)))
|
|
@ -1,25 +1,22 @@
|
|||
(ns syng-im.components.chat
|
||||
(ns syng-im.chat.screen
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require [clojure.string :as s]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
navigator
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item
|
||||
android?]]
|
||||
[syng-im.components.chat-styles :as st]
|
||||
[syng-im.utils.logging :as log]
|
||||
list-item]]
|
||||
[syng-im.chat.styles.screen :as st]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.constants :refer [content-type-status]]
|
||||
[syng-im.utils.listview :refer [to-datasource
|
||||
to-datasource2]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.components.invertible-scroll-view :refer [invertible-scroll-view]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.components.chat.chat-message :refer [chat-message]]
|
||||
[syng-im.components.chat.chat-message-new :refer [chat-message-new]]))
|
||||
[syng-im.chat.views.message :refer [chat-message]]
|
||||
[syng-im.chat.views.new-message :refer [chat-message-new]]))
|
||||
|
||||
|
||||
(defn contacts-by-identity [contacts]
|
||||
(->> contacts
|
||||
|
@ -29,8 +26,8 @@
|
|||
|
||||
(defn add-msg-color [{:keys [from] :as msg} contact-by-identity]
|
||||
(if (= "system" from)
|
||||
(assoc msg :text-color "#4A5258"
|
||||
:background-color "#D3EEEF")
|
||||
(assoc msg :text-color :#4A5258
|
||||
:background-color :#D3EEEF)
|
||||
(let [{:keys [text-color background-color]} (get contact-by-identity from)]
|
||||
(assoc msg :text-color text-color
|
||||
:background-color background-color))))
|
||||
|
@ -70,9 +67,9 @@
|
|||
|
||||
(defn on-action-selected [position]
|
||||
(case position
|
||||
0 (dispatch [:show-add-participants #_navigator])
|
||||
1 (dispatch [:show-remove-participants #_navigator])
|
||||
2 (dispatch [:leave-group-chat #_navigator])))
|
||||
0 (dispatch [:show-add-participants])
|
||||
1 (dispatch [:show-remove-participants])
|
||||
2 (dispatch [:leave-group-chat])))
|
||||
|
||||
(defn overlay [{:keys [on-click-outside]} items]
|
||||
[view st/actions-overlay
|
||||
|
@ -122,21 +119,18 @@
|
|||
:icon :menu_group
|
||||
:icon-style {:width 25
|
||||
:height 19}
|
||||
:handler nil #_#(dispatch [:show-add-participants
|
||||
navigator])}
|
||||
:handler #(dispatch [:show-add-participants])}
|
||||
{:title "Remove Contact from chat"
|
||||
:subtitle "Alex, John"
|
||||
:icon :search_gray_copy
|
||||
:icon-style {:width 17
|
||||
:height 17}
|
||||
:handler nil #_#(dispatch
|
||||
[:show-remove-participants navigator])}
|
||||
:handler #(dispatch [:show-remove-participants])}
|
||||
{:title "Leave Chat"
|
||||
:icon :muted
|
||||
:icon-style {:width 18
|
||||
:height 21}
|
||||
:handler nil #_#(dispatch [:leave-group-chat
|
||||
navigator])}
|
||||
:handler #(dispatch [:leave-group-chat])}
|
||||
{:title "Settings"
|
||||
:subtitle "Not implemented"
|
||||
:icon :settings
|
||||
|
@ -222,25 +216,23 @@
|
|||
:custom-content [toolbar-content]
|
||||
:custom-action [toolbar-action]}])))
|
||||
|
||||
(defn messages-view [group-chat]
|
||||
(let [messages (subscribe [:chat :messages])
|
||||
contacts (subscribe [:chat :contacts])]
|
||||
(fn [group-chat]
|
||||
(let [contacts' (contacts-by-identity @contacts)]
|
||||
[list-view {:renderRow (message-row contacts' group-chat)
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:enableEmptySections true
|
||||
:dataSource (to-datasource2 @messages)}]))))
|
||||
(defview messages-view [group-chat]
|
||||
[messages [:chat :messages]
|
||||
contacts [:chat :contacts]]
|
||||
(let [contacts' (contacts-by-identity contacts)]
|
||||
[list-view {:renderRow (message-row contacts' group-chat)
|
||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||
:onEndReached #(dispatch [:load-more-messages])
|
||||
:enableEmptySections true
|
||||
:dataSource (to-datasource messages)}]))
|
||||
|
||||
(defn chat []
|
||||
(let [is-active (subscribe [:chat :is-active])
|
||||
group-chat (subscribe [:chat :group-chat])
|
||||
show-actions-atom (subscribe [:show-actions])]
|
||||
(fn []
|
||||
[view st/chat-view
|
||||
[chat-toolbar]
|
||||
[messages-view @group-chat]
|
||||
(when @group-chat [typing-all])
|
||||
(when is-active [chat-message-new])
|
||||
(when @show-actions-atom [actions-view])])))
|
||||
(defview chat []
|
||||
[is-active [:chat :is-active]
|
||||
group-chat [:chat :group-chat]
|
||||
show-actions-atom [:show-actions]]
|
||||
[view st/chat-view
|
||||
[chat-toolbar]
|
||||
[messages-view group-chat]
|
||||
(when group-chat [typing-all])
|
||||
(when is-active [chat-message-new])
|
||||
(when show-actions-atom [actions-view])])
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.chat.content-suggestions-styles
|
||||
(ns syng-im.chat.styles.content-suggestions
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
color-light-blue-transparent
|
||||
color-white
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.chat.input.input-styles
|
||||
(ns syng-im.chat.styles.input
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
color-white
|
||||
color-blue
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.chat.chat-message-styles
|
||||
(ns syng-im.chat.styles.message
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
color-light-blue-transparent
|
||||
color-white
|
||||
|
@ -312,18 +312,3 @@
|
|||
(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})
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.chat.plain-message-input-styles
|
||||
(ns syng-im.chat.styles.plain-input
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
text2-color
|
||||
color-white
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.chat-styles
|
||||
(ns syng-im.chat.styles.screen
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.chat.suggestions-styles
|
||||
(ns syng-im.chat.styles.suggestions
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
color-light-blue-transparent
|
||||
color-white
|
|
@ -0,0 +1,94 @@
|
|||
(ns syng-im.chat.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]
|
||||
[syng-im.db :as db]
|
||||
;todo handlers in subs?...
|
||||
[syng-im.chat.suggestions :refer
|
||||
[get-suggestions typing-command? get-content-suggestions]]
|
||||
[syng-im.models.commands :as commands]
|
||||
[syng-im.handlers.content-suggestions :refer [get-content-suggestions]]))
|
||||
|
||||
(register-sub :chat-properties
|
||||
(fn [db [_ properties]]
|
||||
(->> properties
|
||||
(map (fn [k]
|
||||
[k (-> @db
|
||||
(get-in [:chats (:current-chat-id @db) k])
|
||||
(reaction))]))
|
||||
(into {}))))
|
||||
|
||||
(register-sub
|
||||
:show-actions
|
||||
(fn [db _]
|
||||
(reaction (:show-actions @db))))
|
||||
|
||||
(register-sub :chat
|
||||
(fn [db [_ k]]
|
||||
(-> @db
|
||||
(get-in [:chats (:current-chat-id @db) k])
|
||||
(reaction))))
|
||||
|
||||
|
||||
(register-sub :get-chat-messages
|
||||
(fn [db _]
|
||||
(let [chat-id (:current-chat-id @db)]
|
||||
(reaction (get-in @db [:chats chat-id :messages])))))
|
||||
|
||||
(register-sub :get-current-chat-id
|
||||
(fn [db _]
|
||||
(reaction (:current-chat-id @db))))
|
||||
|
||||
(register-sub :get-suggestions
|
||||
(fn [db _]
|
||||
(let [input-text (->> (:current-chat-id @db)
|
||||
db/chat-input-text-path
|
||||
(get-in @db)
|
||||
(reaction))]
|
||||
(reaction (get-suggestions @db @input-text)))))
|
||||
|
||||
(register-sub :get-commands
|
||||
(fn [db _]
|
||||
(reaction (commands/get-commands @db))))
|
||||
|
||||
(register-sub :get-chat-input-text
|
||||
(fn [db _]
|
||||
(->> [:chats (:current-chat-id @db) :input-text]
|
||||
(get-in @db)
|
||||
(reaction))))
|
||||
|
||||
(register-sub :get-chat-staged-commands
|
||||
(fn [db _]
|
||||
(->> [:chats (:current-chat-id @db) :staged-commands]
|
||||
(get-in @db)
|
||||
(reaction))))
|
||||
|
||||
(register-sub :get-chat-command
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command @db))))
|
||||
|
||||
(register-sub :get-chat-command-content
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command-content @db))))
|
||||
|
||||
(register-sub :chat-command-request
|
||||
(fn [db _]
|
||||
(reaction (commands/get-chat-command-request @db))))
|
||||
|
||||
(register-sub :get-current-chat
|
||||
(fn [db _]
|
||||
(let [current-chat-id (:current-chat-id @db)]
|
||||
(reaction (get-in @db [:chats current-chat-id])))))
|
||||
|
||||
(register-sub :get-chat
|
||||
(fn [db [_ chat-id]]
|
||||
(reaction (get-in @db [:chats chat-id]))))
|
||||
|
||||
(register-sub :typing-command?
|
||||
(fn [db _]
|
||||
(reaction (typing-command? @db))))
|
||||
|
||||
(register-sub :get-content-suggestions
|
||||
(fn [db _]
|
||||
(let [command (reaction (commands/get-chat-command @db))
|
||||
text (reaction (commands/get-chat-command-content @db))]
|
||||
(reaction (get-content-suggestions @db @command @text)))))
|
|
@ -1,9 +1,6 @@
|
|||
(ns syng-im.handlers.suggestions
|
||||
(ns syng-im.chat.suggestions
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.db :as db]
|
||||
[syng-im.models.chat :refer [current-chat-id
|
||||
set-chat-input-text
|
||||
get-chat-input-text]]
|
||||
[syng-im.models.commands :refer [commands
|
||||
suggestions
|
||||
get-commands
|
||||
|
@ -11,7 +8,6 @@
|
|||
get-chat-command-to-msg-id
|
||||
clear-staged-commands]]
|
||||
[syng-im.utils.utils :refer [log on-error http-get]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[clojure.string :as s]))
|
||||
|
||||
(defn suggestion? [text]
|
||||
|
@ -41,7 +37,8 @@
|
|||
(command-handler to-msg-id command-key content)))))
|
||||
|
||||
(defn apply-staged-commands [db]
|
||||
(let [staged-commands (get-in db (db/chat-staged-commands-path (current-chat-id db)))]
|
||||
(let [staged-commands (get-in db (db/chat-staged-commands-path
|
||||
(:current-chat-id db)))]
|
||||
(dorun (map (fn [staged-command]
|
||||
(when-let [handler (:handler staged-command)]
|
||||
(handler)))
|
||||
|
@ -66,8 +63,10 @@
|
|||
suggestion)))
|
||||
|
||||
(defn typing-command? [db]
|
||||
(let [text (get-chat-input-text db)]
|
||||
(suggestion? text)))
|
||||
(-> db
|
||||
(get-in [:chats (:current-chat-id db) :input-text])
|
||||
suggestion?))
|
||||
|
||||
(defn switch-command-suggestions [db]
|
||||
(set-chat-input-text db (if (typing-command? db) nil "!")))
|
||||
(let [text (if (typing-command? db) nil "!")]
|
||||
(assoc-in db [:chats (:current-chat-id db) :input-text] text)))
|
|
@ -1,13 +1,13 @@
|
|||
(ns syng-im.components.chat.input.simple-command
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
(ns syng-im.chat.views.command
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
icon
|
||||
text
|
||||
text-input
|
||||
touchable-highlight]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.chat.content-suggestions :refer [content-suggestions-view]]
|
||||
[syng-im.components.chat.input.input-styles :as st]))
|
||||
[syng-im.chat.views.content-suggestions :refer
|
||||
[content-suggestions-view]]
|
||||
[syng-im.chat.styles.input :as st]))
|
||||
|
||||
(defn cancel-command-input []
|
||||
(dispatch [:cancel-command]))
|
|
@ -0,0 +1,6 @@
|
|||
(ns syng-im.chat.views.confirmation-code
|
||||
(:require
|
||||
[syng-im.chat.views.command :refer [simple-command-input-view]]))
|
||||
|
||||
(defn confirmation-code-input-view [command]
|
||||
[simple-command-input-view command {:keyboardType :numeric}])
|
|
@ -0,0 +1,36 @@
|
|||
(ns syng-im.chat.views.content-suggestions
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
icon
|
||||
text
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[syng-im.chat.styles.content-suggestions :as st]
|
||||
[syng-im.utils.listview :refer [to-datasource]]))
|
||||
|
||||
(defn set-command-content [content]
|
||||
(dispatch [:set-chat-command-content content]))
|
||||
|
||||
(defn suggestion-list-item [{:keys [value description]}]
|
||||
[touchable-highlight {:onPress #(set-command-content value)}
|
||||
[view st/suggestion-container
|
||||
[view st/suggestion-sub-container
|
||||
[text {:style st/value-text} value]
|
||||
[text {:style st/description-text} description]]]])
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [suggestion-list-item row]))
|
||||
|
||||
(defview content-suggestions-view []
|
||||
[suggestions [:get-content-suggestions]]
|
||||
(when (seq suggestions)
|
||||
[view
|
||||
[touchable-highlight {:style st/drag-down-touchable
|
||||
;; TODO hide suggestions?
|
||||
:onPress (fn [])}
|
||||
[view [icon :drag_down st/drag-down-icon]]]
|
||||
[view (st/suggestions-container (count suggestions))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:renderRow render-row}]]]))
|
|
@ -1,11 +1,11 @@
|
|||
(ns syng-im.components.chat.chat-message
|
||||
(ns syng-im.chat.views.message
|
||||
(:require [clojure.string :as s]
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
touchable-highlight]]
|
||||
[syng-im.components.chat.chat-message-styles :as st]
|
||||
[syng-im.chat.styles.message :as st]
|
||||
[syng-im.models.commands :refer [parse-command-msg-content
|
||||
parse-command-request]]
|
||||
[syng-im.resources :as res]
|
||||
|
@ -112,8 +112,7 @@
|
|||
(defn text-message
|
||||
[{:keys [content] :as message}]
|
||||
[message-view message
|
||||
[text {:style (st/text-message message)}
|
||||
content]])
|
||||
[text {:style (st/text-message message)} content]])
|
||||
|
||||
(defmethod message-content text-content-type
|
||||
[wrapper message]
|
|
@ -0,0 +1,7 @@
|
|||
(ns syng-im.chat.views.money
|
||||
(:require
|
||||
[syng-im.chat.views.command :refer [simple-command-input-view]]))
|
||||
|
||||
(defn money-input-view [command]
|
||||
[simple-command-input-view command
|
||||
{:keyboardType :numeric}])
|
|
@ -1,15 +1,15 @@
|
|||
(ns syng-im.components.chat.chat-message-new
|
||||
(ns syng-im.chat.views.new-message
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[syng-im.components.react :refer [view]]
|
||||
[syng-im.components.chat.plain-message-input :refer [plain-message-input-view]]
|
||||
[syng-im.components.chat.input.simple-command :refer [simple-command-input-view]]
|
||||
[syng-im.components.chat.input.phone :refer [phone-input-view]]
|
||||
[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.components.chat.chat-message-styles :as st]))
|
||||
[syng-im.chat.views.plain-input :refer [plain-message-input-view]]
|
||||
[syng-im.chat.views.command :refer [simple-command-input-view]]
|
||||
[syng-im.chat.views.phone :refer [phone-input-view]]
|
||||
[syng-im.chat.views.password :refer [password-input-view]]
|
||||
[syng-im.chat.views.confirmation-code :refer [confirmation-code-input-view]]
|
||||
[syng-im.chat.views.money :refer [money-input-view]]
|
||||
[syng-im.chat.views.staged-command :refer [simple-command-staged-view]]
|
||||
[syng-im.chat.styles.message :as st]))
|
||||
|
||||
(defn staged-command-view [stage-command]
|
||||
[simple-command-staged-view stage-command])
|
|
@ -1,6 +1,6 @@
|
|||
(ns syng-im.components.chat.input.password
|
||||
(ns syng-im.chat.views.password
|
||||
(:require
|
||||
[syng-im.components.chat.input.simple-command
|
||||
[syng-im.chat.views.command
|
||||
:refer [simple-command-input-view]]))
|
||||
|
||||
(defn password-input-view [command]
|
|
@ -1,6 +1,6 @@
|
|||
(ns syng-im.components.chat.input.phone
|
||||
(ns syng-im.chat.views.phone
|
||||
(:require
|
||||
[syng-im.components.chat.input.simple-command
|
||||
[syng-im.chat.views.command
|
||||
:refer [simple-command-input-view]]
|
||||
[syng-im.utils.phone-number :refer [valid-mobile-number?]]))
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
(ns syng-im.components.chat.plain-message-input
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
(ns syng-im.chat.views.plain-input
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
icon
|
||||
touchable-highlight
|
||||
text-input]]
|
||||
[syng-im.components.chat.suggestions :refer [suggestions-view]]
|
||||
[syng-im.components.chat.plain-message-input-styles :as st]))
|
||||
[syng-im.chat.views.suggestions :refer [suggestions-view]]
|
||||
[syng-im.chat.styles.plain-input :as st]))
|
||||
|
||||
(defn set-input-message [message]
|
||||
(dispatch [:set-chat-input-text message]))
|
|
@ -1,11 +1,11 @@
|
|||
(ns syng-im.components.chat.input.simple-command-staged
|
||||
(ns syng-im.chat.views.staged-command
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
image
|
||||
text
|
||||
touchable-highlight]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.chat.input.input-styles :as st]))
|
||||
[syng-im.chat.styles.input :as st]))
|
||||
|
||||
(defn cancel-command-input [staged-command]
|
||||
(dispatch [:unstage-command staged-command]))
|
|
@ -1,6 +1,4 @@
|
|||
(ns syng-im.components.chat.suggestions
|
||||
(:require-macros
|
||||
[natal-shell.core :refer [with-error-view]])
|
||||
(ns syng-im.chat.views.suggestions
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
text
|
||||
|
@ -9,38 +7,38 @@
|
|||
list-view
|
||||
list-item]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.components.chat.suggestions-styles :as st]))
|
||||
[syng-im.chat.styles.suggestions :as st]))
|
||||
|
||||
(defn set-command-input [command]
|
||||
(dispatch [:set-chat-command command]))
|
||||
|
||||
(defn suggestion-list-item [suggestion]
|
||||
(defn suggestion-list-item
|
||||
[{:keys [description command]
|
||||
label :text
|
||||
:as suggestion}]
|
||||
[touchable-highlight
|
||||
{:onPress #(set-command-input (keyword (:command suggestion)))}
|
||||
{:onPress #(set-command-input (keyword command))}
|
||||
[view st/suggestion-container
|
||||
[view st/suggestion-sub-container
|
||||
[view (st/suggestion-background suggestion)
|
||||
[text {:style st/suggestion-text}
|
||||
(:text suggestion)]]
|
||||
[text {:style st/value-text}
|
||||
(:text suggestion)]
|
||||
[text {:style st/description-text}
|
||||
(:description suggestion)]]]])
|
||||
[text {:style st/suggestion-text} label]]
|
||||
[text {:style st/value-text} label]
|
||||
[text {:style st/description-text} description]]]])
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [suggestion-list-item (js->clj row :keywordize-keys true)]))
|
||||
(list-item [suggestion-list-item row]))
|
||||
|
||||
(defn suggestions-view []
|
||||
(let [suggestions-atom (subscribe [:get-suggestions])]
|
||||
(fn []
|
||||
(let [suggestions @suggestions-atom]
|
||||
(when (seq suggestions)
|
||||
[view nil
|
||||
[view
|
||||
[touchable-highlight {:style st/drag-down-touchable
|
||||
:onPress (fn []
|
||||
;; TODO hide suggestions?
|
||||
)}
|
||||
[view nil
|
||||
[view
|
||||
[icon :drag_down st/drag-down-icon]]]
|
||||
[view (st/suggestions-container (count suggestions))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
|
@ -0,0 +1,52 @@
|
|||
(ns syng-im.chats-list.screen
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [list-view
|
||||
list-item
|
||||
view
|
||||
text
|
||||
image
|
||||
touchable-highlight]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.chats-list.views.chat-list-item :refer [chat-list-item]]
|
||||
[syng-im.components.action-button :refer [action-button
|
||||
action-button-item]]
|
||||
[syng-im.components.drawer.view :refer [drawer-view open-drawer]]
|
||||
[syng-im.components.styles :refer [color-blue]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.components.icons.ionicons :refer [icon]]
|
||||
[syng-im.chats-list.styles :as st]))
|
||||
|
||||
|
||||
(defn chats-list-toolbar []
|
||||
[toolbar {:nav-action {:image {:source {:uri :icon_hamburger}
|
||||
:style st/hamburger-icon}
|
||||
:handler open-drawer}
|
||||
:title "Chats"
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:style st/search-icon}
|
||||
:handler (fn [])}}])
|
||||
|
||||
(defn chats-list []
|
||||
(let [chats (subscribe [:get :chats])]
|
||||
(fn []
|
||||
[drawer-view
|
||||
[view st/chats-container
|
||||
[chats-list-toolbar]
|
||||
[list-view {:dataSource (to-datasource (vals @chats))
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item [chat-list-item row]))
|
||||
:style st/list-container}]
|
||||
[action-button {:buttonColor color-blue}
|
||||
[action-button-item
|
||||
{:title "New Chat"
|
||||
:buttonColor :#9b59b6
|
||||
:onPress #(dispatch [:navigate-to :contact-list])}
|
||||
[icon {:name :android-create
|
||||
:style st/create-icon}]]
|
||||
[action-button-item
|
||||
{:title "New Group Chat"
|
||||
:buttonColor :#1abc9c
|
||||
:onPress #(dispatch [:show-group-new])}
|
||||
[icon {:name :person-stalker
|
||||
:style st/person-stalker-icon}]]]]])))
|
|
@ -0,0 +1,147 @@
|
|||
(ns syng-im.chats-list.styles
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
||||
color-blue
|
||||
online-color
|
||||
text1-color
|
||||
text2-color
|
||||
new-messages-count-color]]))
|
||||
|
||||
(def contact-photo-container
|
||||
{:borderRadius 50})
|
||||
|
||||
(def contact-photo-image
|
||||
{:borderRadius 50
|
||||
:width 40
|
||||
:height 40})
|
||||
|
||||
(def online-container
|
||||
{:position :absolute
|
||||
:top 24
|
||||
:left 24
|
||||
:width 20
|
||||
:height 20
|
||||
:borderRadius 50
|
||||
:backgroundColor online-color
|
||||
:borderWidth 2
|
||||
:borderColor color-white})
|
||||
|
||||
(def online-dot
|
||||
{:position :absolute
|
||||
:top 6
|
||||
:width 4
|
||||
:height 4
|
||||
:borderRadius 50
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def online-dot-left
|
||||
(assoc online-dot :left 3))
|
||||
|
||||
(def online-dot-right
|
||||
(assoc online-dot :left 9))
|
||||
|
||||
(def chat-container
|
||||
{:flexDirection :row
|
||||
:paddingVertical 15
|
||||
:paddingHorizontal 16
|
||||
:height 90})
|
||||
|
||||
(def photo-container
|
||||
{:marginTop 2
|
||||
:width 44
|
||||
:height 44})
|
||||
|
||||
(def item-container
|
||||
{:flexDirection :column
|
||||
:marginLeft 12
|
||||
:flex 1})
|
||||
|
||||
(def name-view
|
||||
{:flexDirection :row})
|
||||
|
||||
(def name-text
|
||||
{:marginTop -2.5
|
||||
:color text1-color
|
||||
:fontSize 14
|
||||
:fontFamily title-font})
|
||||
|
||||
(def group-icon
|
||||
{:marginTop 4
|
||||
:marginLeft 8
|
||||
:width 14
|
||||
:height 9})
|
||||
|
||||
(def memebers-text
|
||||
{:marginTop -0.5
|
||||
:marginLeft 4
|
||||
:fontFamily font
|
||||
:fontSize 12
|
||||
:color text2-color})
|
||||
|
||||
(def last-message-text
|
||||
{:marginTop 7
|
||||
:marginRight 40
|
||||
:color text1-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20})
|
||||
|
||||
(def status-container
|
||||
{:flexDirection :row
|
||||
:position :absolute
|
||||
:top 0
|
||||
:right 0})
|
||||
|
||||
(def status-image
|
||||
{:marginTop 6
|
||||
:width 9
|
||||
:height 7})
|
||||
|
||||
(def datetime-text
|
||||
{:fontFamily font
|
||||
:fontSize 12
|
||||
:color text2-color
|
||||
:marginLeft 5})
|
||||
|
||||
(def new-messages-container
|
||||
{:position :absolute
|
||||
:top 36
|
||||
:right 0
|
||||
:width 24
|
||||
:height 24
|
||||
:backgroundColor new-messages-count-color
|
||||
:borderRadius 50})
|
||||
|
||||
(def new-messages-text
|
||||
{:top 4
|
||||
:left 0
|
||||
:fontFamily title-font
|
||||
:fontSize 10
|
||||
:color color-blue
|
||||
:textAlign :center})
|
||||
|
||||
(def hamburger-icon
|
||||
{:width 16
|
||||
:height 12})
|
||||
|
||||
(def search-icon
|
||||
{:width 17
|
||||
:height 17})
|
||||
|
||||
(def chats-container
|
||||
{:flex 1
|
||||
:backgroundColor :white})
|
||||
|
||||
(def list-container
|
||||
{:backgroundColor :white})
|
||||
|
||||
(def create-icon
|
||||
{:fontSize 20
|
||||
:height 22
|
||||
:color :white})
|
||||
|
||||
(def person-stalker-icon
|
||||
{:fontSize 20
|
||||
:height 22
|
||||
:color :white})
|
|
@ -0,0 +1,20 @@
|
|||
(ns syng-im.chats-list.views.chat-list-item
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
touchable-highlight]]
|
||||
[syng-im.components.styles :refer [font]]
|
||||
[syng-im.chats-list.views.inner-item :refer
|
||||
[chat-list-item-inner-view]]))
|
||||
|
||||
(defn chat-list-item [{:keys [chat-id] :as chat}]
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:show-chat chat-id :push])}
|
||||
;; TODO add [photo-path delivery-status new-messages-count online] values to chat-obj
|
||||
[view [chat-list-item-inner-view (merge chat
|
||||
{:photo-path nil
|
||||
:delivery-status :seen
|
||||
:new-messages-count 3
|
||||
:timestamp "13:54"
|
||||
:online true})]]])
|
|
@ -0,0 +1,52 @@
|
|||
(ns syng-im.chats-list.views.inner-item
|
||||
(:require [clojure.string :as s]
|
||||
[syng-im.components.react :refer [view image icon text]]
|
||||
[syng-im.chats-list.styles :as st]
|
||||
[syng-im.resources :as res]))
|
||||
|
||||
|
||||
(defn contact-photo [photo-path]
|
||||
[view st/contact-photo-container
|
||||
[image {:source (if (s/blank? photo-path)
|
||||
res/user-no-photo
|
||||
{:uri photo-path})
|
||||
:style st/contact-photo-image}]])
|
||||
|
||||
(defn contact-online [online]
|
||||
(when online
|
||||
[view st/online-container
|
||||
[view st/online-dot-left]
|
||||
[view st/online-dot-right]]))
|
||||
|
||||
(defn chat-list-item-inner-view
|
||||
[{:keys [name photo-path delivery-status timestamp new-messages-count online
|
||||
group-chat contacts]}]
|
||||
[view st/chat-container
|
||||
[view st/photo-container
|
||||
[contact-photo photo-path]
|
||||
[contact-online online]]
|
||||
[view st/item-container
|
||||
[view st/name-view
|
||||
[text {:style st/name-text} name]
|
||||
(when group-chat
|
||||
[icon :group st/group-icon])
|
||||
(when group-chat
|
||||
[text {:style st/memebers-text}
|
||||
(if (< 1 (count contacts))
|
||||
(str (count contacts) " members")
|
||||
"1 member")])]
|
||||
[text {:style st/last-message-text
|
||||
:numberOfLines 2}
|
||||
(repeatedly 5 #(str "Hi, I'm " name "! "))]]
|
||||
[view
|
||||
[view st/status-container
|
||||
(when delivery-status
|
||||
[image {:source (if (= (keyword delivery-status) :seen)
|
||||
{:uri :icon_ok_small}
|
||||
;; todo change icon
|
||||
{:uri :icon_ok_small})
|
||||
:style st/status-image}])
|
||||
[text {:style st/datetime-text} timestamp]]
|
||||
(when (pos? new-messages-count)
|
||||
[view st/new-messages-container
|
||||
[text {:style st/new-messages-text} new-messages-count]])]])
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.carousel
|
||||
(ns syng-im.components.carousel.carousel
|
||||
(:require [syng-im.components.react :refer [android?
|
||||
view
|
||||
scroll-view
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
(defn page [page-width margin]
|
||||
{:width page-width
|
||||
:justifyContent "center"
|
||||
:justifyContent :center
|
||||
:marginLeft margin
|
||||
:marginRight margin})
|
|
@ -1,50 +0,0 @@
|
|||
(ns syng-im.components.chat.content-suggestions
|
||||
(:require-macros
|
||||
[natal-shell.core :refer [with-error-view]])
|
||||
(:require [clojure.string :as cstr]
|
||||
[reagent.core :as r]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view
|
||||
icon
|
||||
text
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[syng-im.components.chat.content-suggestions-styles :as st]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.utils.utils :refer [log toast http-post]]
|
||||
[syng-im.utils.logging :as log]))
|
||||
|
||||
(defn set-command-content [content]
|
||||
(dispatch [:set-chat-command-content content]))
|
||||
|
||||
(defn suggestion-list-item [suggestion]
|
||||
[touchable-highlight {:onPress (fn []
|
||||
(set-command-content (:value suggestion)))
|
||||
:underlay-color :transparent}
|
||||
[view st/suggestion-container
|
||||
[view st/suggestion-sub-container
|
||||
[text {:style st/value-text}
|
||||
(:value suggestion)]
|
||||
[text {:style st/description-text}
|
||||
(:description suggestion)]]]])
|
||||
|
||||
(defn render-row [row section-id row-id]
|
||||
(list-item [suggestion-list-item (js->clj row :keywordize-keys true)]))
|
||||
|
||||
(defn content-suggestions-view []
|
||||
(let [suggestions-atom (subscribe [:get-content-suggestions])]
|
||||
(fn []
|
||||
(let [suggestions @suggestions-atom]
|
||||
(when (seq suggestions)
|
||||
[view nil
|
||||
[touchable-highlight {:style st/drag-down-touchable
|
||||
:onPress (fn []
|
||||
;; TODO hide suggestions?
|
||||
)
|
||||
:underlay-color :transparent}
|
||||
[view nil
|
||||
[icon :drag_down st/drag-down-icon]]]
|
||||
[view (st/suggestions-container (count suggestions))
|
||||
[list-view {:dataSource (to-datasource suggestions)
|
||||
:renderRow render-row}]]])))))
|
|
@ -1,7 +0,0 @@
|
|||
(ns syng-im.components.chat.input.confirmation-code
|
||||
(:require
|
||||
[syng-im.components.chat.input.simple-command
|
||||
:refer [simple-command-input-view]]))
|
||||
|
||||
(defn confirmation-code-input-view [command]
|
||||
[simple-command-input-view command {:keyboardType :numeric}])
|
|
@ -1,9 +0,0 @@
|
|||
(ns syng-im.components.chat.input.money
|
||||
(:require
|
||||
[syng-im.components.chat.input.simple-command
|
||||
:refer [simple-command-input-view]]
|
||||
[syng-im.components.chat.input.input-styles :as st]))
|
||||
|
||||
(defn money-input-view [command]
|
||||
[simple-command-input-view command
|
||||
{:keyboardType :numeric}])
|
|
@ -1,35 +0,0 @@
|
|||
(ns syng-im.components.chat.new-participants
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.react :refer [view]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[syng-im.components.chats.new-participant-contact
|
||||
:refer [new-participant-contact]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.components.chat.chat-message-styles :as st]))
|
||||
|
||||
(defn new-participants-toolbar [navigator]
|
||||
[toolbar
|
||||
{:navigator navigator
|
||||
:title "Add Participants"
|
||||
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style st/new-participant-image}
|
||||
:handler #(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]}]
|
||||
(let [contacts (subscribe [:all-new-contacts])]
|
||||
(fn []
|
||||
(let [contacts-ds (to-realm-datasource @contacts)]
|
||||
[view st/participants-container
|
||||
[new-participants-toolbar navigator]
|
||||
[list-view {:dataSource contacts-ds
|
||||
:enableEmptySections true
|
||||
:renderRow (new-participants-row navigator)
|
||||
:style st/participants-list}]]))))
|
|
@ -1,36 +0,0 @@
|
|||
(ns syng-im.components.chat.remove-participants
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.react :refer [view text-input text image
|
||||
touchable-highlight]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[syng-im.components.chats.new-participant-contact
|
||||
:refer [new-participant-contact]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.components.chat.chat-message-styles :as st]))
|
||||
|
||||
(defn remove-participants-toolbar [navigator]
|
||||
[toolbar
|
||||
{:navigator navigator
|
||||
:title "Remove Participants"
|
||||
:action {:handler #(dispatch [:remove-selected-participants navigator])
|
||||
:image {:source res/trash-icon ;; {:uri "icon_search"}
|
||||
:style st/remove-participants-image}}}])
|
||||
|
||||
(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]}]
|
||||
(let [contacts (subscribe [:current-chat-contacts])]
|
||||
(fn []
|
||||
(let [contacts-ds (to-realm-datasource @contacts)]
|
||||
[view st/participants-container
|
||||
[remove-participants-toolbar navigator]
|
||||
[list-view {:dataSource contacts-ds
|
||||
:enableEmptySections true
|
||||
:renderRow (remove-participants-row navigator)
|
||||
:style st/participants-list}]]))))
|
|
@ -1,37 +0,0 @@
|
|||
(ns syng-im.components.chats.chat-list-item
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
touchable-highlight]]
|
||||
[syng-im.components.styles :refer [font]]
|
||||
[syng-im.components.chats.chat-list-item-inner :refer [chat-list-item-inner-view]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.resources :as res]))
|
||||
|
||||
(defn chat-list-item [chat-obj navigator]
|
||||
[touchable-highlight
|
||||
{:on-press #(dispatch [:show-chat (aget chat-obj "chat-id") navigator :push])}
|
||||
;; TODO add [photo-path delivery-status new-messages-count online] values to chat-obj
|
||||
;; TODO should chat-obj be clj-map?
|
||||
[view {} [chat-list-item-inner-view (merge (js->clj chat-obj :keywordize-keys true)
|
||||
{:photo-path nil
|
||||
:delivery-status :seen
|
||||
:new-messages-count 3
|
||||
:timestamp "13:54"
|
||||
:online true})]]])
|
||||
|
||||
(comment [view {:style {:flexDirection "row"
|
||||
:width 260
|
||||
:marginVertical 5}}
|
||||
[image {:source res/chat-icon
|
||||
:style {:borderWidth 2
|
||||
:borderColor "#FFFFFF"
|
||||
:width 32
|
||||
:height 30
|
||||
:marginRight 5
|
||||
:marginLeft 5}}]
|
||||
[text {:style {:fontSize 14
|
||||
:fontFamily font
|
||||
:color "#4A5258"}}
|
||||
(subs (aget chat-obj "name") 0 30)]])
|
|
@ -1,131 +0,0 @@
|
|||
(ns syng-im.components.chats.chat-list-item-inner
|
||||
(:require [clojure.string :as s]
|
||||
[syng-im.components.react :refer [view image text]]
|
||||
[syng-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
||||
color-blue
|
||||
online-color
|
||||
text1-color
|
||||
text2-color
|
||||
new-messages-count-color]]
|
||||
[syng-im.resources :as res]))
|
||||
|
||||
(defn contact-photo [{:keys [photo-path]}]
|
||||
[view {:borderRadius 50}
|
||||
[image {:source (if (s/blank? photo-path)
|
||||
res/user-no-photo
|
||||
{:uri photo-path})
|
||||
:style {:borderRadius 50
|
||||
:width 40
|
||||
:height 40}}]])
|
||||
|
||||
(defn contact-online [{:keys [online]}]
|
||||
(when online
|
||||
[view {:position "absolute"
|
||||
:top 24
|
||||
:left 24
|
||||
: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 chat-list-item-inner-view
|
||||
[{:keys [name photo-path delivery-status timestamp new-messages-count online
|
||||
group-chat contacts]}]
|
||||
[view {:style {:flexDirection "row"
|
||||
:paddingVertical 15
|
||||
:paddingHorizontal 16
|
||||
:height 90}}
|
||||
[view {:marginTop 2
|
||||
:width 44
|
||||
:height 44}
|
||||
;;; photo
|
||||
[contact-photo {:photo-path photo-path}]
|
||||
;;; online
|
||||
[contact-online {:online online}]]
|
||||
[view {:style {:flexDirection "column"
|
||||
:marginLeft 12
|
||||
:flex 1}}
|
||||
;;; name
|
||||
[view {:style {:flexDirection "row"}}
|
||||
[text {:style {:marginTop -2.5
|
||||
:color text1-color
|
||||
:fontSize 14
|
||||
:fontFamily title-font}} name]
|
||||
;;; group size
|
||||
(when group-chat
|
||||
[image {:source {:uri "icon_group"}
|
||||
:style {:marginTop 4
|
||||
:marginLeft 8
|
||||
:width 14
|
||||
:height 9}}])
|
||||
(when group-chat
|
||||
[text {:style {:marginTop -0.5
|
||||
:marginLeft 4
|
||||
:fontFamily font
|
||||
:fontSize 12
|
||||
:color text2-color}}
|
||||
(if (< 1 (count contacts))
|
||||
(str (count contacts) " members")
|
||||
"1 member")])]
|
||||
;;; last message
|
||||
[text {:style {:marginTop 7
|
||||
:marginRight 40
|
||||
:color text1-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20}
|
||||
:numberOfLines 2}
|
||||
(repeatedly 5 #(str "Hi, I'm " name "! "))]]
|
||||
[view {}
|
||||
;;; delivery status
|
||||
[view {:style {:flexDirection "row"
|
||||
:position "absolute"
|
||||
:top 0
|
||||
:right 0}}
|
||||
(when delivery-status
|
||||
[image {:source (if (= (keyword delivery-status) :seen)
|
||||
{:uri "icon_ok_small"}
|
||||
{:uri "icon_ok_small"})
|
||||
:style {:marginTop 6
|
||||
:width 9
|
||||
:height 7}}])
|
||||
;;; datetime
|
||||
[text {:style {:fontFamily font
|
||||
:fontSize 12
|
||||
:color text2-color
|
||||
:marginLeft 5}}
|
||||
timestamp]]
|
||||
;;; new messages count
|
||||
(when (pos? new-messages-count)
|
||||
[view {:style {:position "absolute"
|
||||
:top 36
|
||||
:right 0
|
||||
:width 24
|
||||
:height 24
|
||||
:backgroundColor new-messages-count-color
|
||||
:borderRadius 50}}
|
||||
[text {:style {:top 4
|
||||
:left 0
|
||||
:fontFamily title-font
|
||||
:fontSize 10
|
||||
:color color-blue
|
||||
:textAlign "center"}}
|
||||
new-messages-count]])]])
|
|
@ -1,71 +0,0 @@
|
|||
(ns syng-im.components.chats.chats-list
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [android?
|
||||
view
|
||||
text
|
||||
image
|
||||
touchable-highlight
|
||||
navigator]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.navigation :refer [nav-pop]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.components.chats.chat-list-item :refer [chat-list-item]]
|
||||
[syng-im.components.drawer :refer [drawer-view open-drawer]]
|
||||
[syng-im.components.action-button :refer [action-button
|
||||
action-button-item]]
|
||||
[syng-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
||||
color-black
|
||||
color-blue
|
||||
text1-color
|
||||
text2-color]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[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 open-drawer}
|
||||
:title "Chats"
|
||||
:action {:image {:source {:uri "icon_search"}
|
||||
:style {:width 17
|
||||
:height 17}}
|
||||
:handler (fn [])}}])
|
||||
|
||||
(defn chats-list [{:keys [navigator]}]
|
||||
(let [chats (subscribe [:get-chats])]
|
||||
(fn []
|
||||
(let [chats @chats
|
||||
_ (log/debug "chats=" chats)
|
||||
datasource (to-realm-datasource chats)]
|
||||
[drawer-view {:navigator navigator}
|
||||
[view {:style {:flex 1
|
||||
:backgroundColor "white"}}
|
||||
[chats-list-toolbar]
|
||||
[list-view {:dataSource datasource
|
||||
:enableEmptySections true
|
||||
:renderRow (fn [row section-id row-id]
|
||||
(r/as-element [chat-list-item row navigator]))
|
||||
:style {:backgroundColor "white"}}]
|
||||
[action-button {:buttonColor color-blue}
|
||||
[action-button-item {:title "New Chat"
|
||||
:buttonColor "#9b59b6"
|
||||
:onPress #(dispatch [:navigate-to
|
||||
:contact-list])}
|
||||
[icon {:name "android-create"
|
||||
:style {:fontSize 20
|
||||
:height 22
|
||||
:color "white"}}]]
|
||||
[action-button-item {:title "New Group Chat"
|
||||
:buttonColor "#1abc9c"
|
||||
:onPress (fn []
|
||||
(dispatch [:show-group-new]))}
|
||||
[icon {:name "person-stalker"
|
||||
:style {:fontSize 20
|
||||
:height 22
|
||||
:color "white"}}]]]]]))))
|
|
@ -1,90 +0,0 @@
|
|||
(ns syng-im.components.chats.new-group
|
||||
(: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.toolbar :refer [toolbar]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[syng-im.components.chats.new-group-contact :refer [new-group-contact]]
|
||||
[reagent.core :as r]
|
||||
[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]}]
|
||||
(let [contacts (subscribe [:all-contacts])
|
||||
group-name (r/atom nil)]
|
||||
(fn [{:keys [navigator]}]
|
||||
(let [contacts-ds (to-realm-datasource @contacts)]
|
||||
[view {:style {:flex 1
|
||||
:flexDirection "column"
|
||||
:backgroundColor color-white}}
|
||||
[new-group-toolbar navigator @group-name]
|
||||
[view {:style {:marginHorizontal 16}}
|
||||
[text {:style {:marginTop 24
|
||||
:marginBottom 16
|
||||
:color text2-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20}}
|
||||
"Chat name"]
|
||||
[text-input {:underlineColorAndroid color-purple
|
||||
:style {:marginLeft -4
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text1-color}
|
||||
:autoFocus true
|
||||
:placeholder "Group Name"
|
||||
:placeholderTextColor text2-color
|
||||
:onChangeText (fn [new-text]
|
||||
(reset! group-name new-text)
|
||||
(r/flush))
|
||||
:onSubmitEditing (fn [e]
|
||||
;(dispatch [:send-chat-msg @chat-id @text])
|
||||
(reset! group-name nil))}
|
||||
@group-name]
|
||||
[text {:style {:marginTop 24
|
||||
:marginBottom 16
|
||||
:color text2-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20}}
|
||||
"Members"]
|
||||
[touchable-highlight {:on-press (fn [])}
|
||||
[view {:style {:flexDirection "row"
|
||||
:marginBottom 16}}
|
||||
[image {:source {:uri "icon_add_gray"}
|
||||
:style {:marginVertical 19
|
||||
:marginHorizontal 3
|
||||
:width 17
|
||||
:height 17}}]
|
||||
[text {:style {:marginTop 18
|
||||
:marginLeft 32
|
||||
:color text2-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20}}
|
||||
"Add members"]]]
|
||||
[list-view {:dataSource contacts-ds
|
||||
:enableEmptySections true
|
||||
:renderRow (fn [row section-id row-id]
|
||||
(r/as-element [new-group-contact (js->clj row :keywordize-keys true) navigator]))
|
||||
:style {:backgroundColor "white"}}]]]))))
|
|
@ -1,20 +0,0 @@
|
|||
(ns syng-im.components.chats.new-group-contact
|
||||
(:require [syng-im.resources :as res]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view]]
|
||||
[syng-im.components.contact-list.contact-inner :refer [contact-inner-view]]
|
||||
[syng-im.components.item-checkbox :refer [item-checkbox]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn new-group-contact [{:keys [whisper-identity] :as contact} navigator]
|
||||
(let [checked (r/atom false)]
|
||||
(fn []
|
||||
[view {:style {:flexDirection "row"
|
||||
:height 56}}
|
||||
[item-checkbox {:onToggle (fn [checked?]
|
||||
(reset! checked checked?)
|
||||
(dispatch [:select-for-new-group whisper-identity checked?]))
|
||||
:checked @checked
|
||||
:size 30}]
|
||||
[contact-inner-view contact]])))
|
|
@ -1,24 +0,0 @@
|
|||
(ns syng-im.components.chats.new-participant-contact
|
||||
(:require [syng-im.resources :as res]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view]]
|
||||
[syng-im.components.contact-list.contact-inner :refer [contact-inner-view]]
|
||||
[syng-im.components.item-checkbox :refer [item-checkbox]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn new-participant-contact [{:keys [whisper-identity] :as contact} navigator]
|
||||
(let [checked (r/atom false)]
|
||||
(fn []
|
||||
[view {:style {:flexDirection "row"
|
||||
:marginTop 5
|
||||
:marginBottom 5
|
||||
:paddingLeft 15
|
||||
:paddingRight 15
|
||||
:height 75}}
|
||||
[item-checkbox {:onToggle (fn [checked?]
|
||||
(reset! checked checked?)
|
||||
(dispatch [:select-new-participant whisper-identity checked?]))
|
||||
:checked @checked
|
||||
:size 30}]
|
||||
[contact-inner-view contact]])))
|
|
@ -1,13 +0,0 @@
|
|||
(ns syng-im.components.contact-list.contact
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view text image touchable-highlight]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.contact-list.contact-inner :refer [contact-inner-view]]))
|
||||
|
||||
(defn show-chat [navigator whisper-identity]
|
||||
(dispatch [:show-chat whisper-identity navigator :push]))
|
||||
|
||||
(defn contact-view [{:keys [navigator contact]}]
|
||||
(let [{:keys [whisper-identity]} contact]
|
||||
[touchable-highlight {:onPress #(show-chat navigator whisper-identity)}
|
||||
[view {} [contact-inner-view contact]]]))
|
|
@ -1,66 +0,0 @@
|
|||
(ns syng-im.components.contact-list.contact-inner
|
||||
(:require [clojure.string :as s]
|
||||
[syng-im.components.react :refer [view image text]]
|
||||
[syng-im.components.styles :refer [font
|
||||
title-font
|
||||
text1-color
|
||||
color-white
|
||||
online-color]]
|
||||
[syng-im.resources :as res]))
|
||||
|
||||
(defn contact-photo [{:keys [photo-path]}]
|
||||
[view {:borderRadius 50}
|
||||
[image {:source (if (s/blank? photo-path)
|
||||
res/user-no-photo
|
||||
{:uri photo-path})
|
||||
:style {:borderRadius 50
|
||||
:width 40
|
||||
:height 40}}]])
|
||||
|
||||
(defn contact-online [{:keys [online]}]
|
||||
(when online
|
||||
[view {:position "absolute"
|
||||
:top 24
|
||||
:left 24
|
||||
: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 contact-inner-view [{:keys [name photo-path delivery-status datetime new-messages-count
|
||||
online whisper-identity]}]
|
||||
[view {:style {:flexDirection "row"
|
||||
:height 56}}
|
||||
[view {:style {:marginTop 8
|
||||
:marginLeft 16
|
||||
:width 44
|
||||
:height 44}}
|
||||
;;; photo
|
||||
[contact-photo {:photo-path photo-path}]
|
||||
;;; online
|
||||
[contact-online {:online online}]]
|
||||
;;; name
|
||||
[view {:style {:justifyContent "center"}}
|
||||
[text {:style {:marginLeft 16
|
||||
:fontSize 16
|
||||
:fontFamily font
|
||||
:color text1-color}}
|
||||
(if (pos? (count name))
|
||||
name
|
||||
"Noname")]]])
|
|
@ -1,52 +0,0 @@
|
|||
(ns syng-im.components.contact-list.contact-list
|
||||
(:require-macros
|
||||
[natal-shell.data-source :refer [data-source clone-with-rows]]
|
||||
[natal-shell.core :refer [with-error-view]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view text image touchable-highlight
|
||||
navigator list-view
|
||||
list-item]]
|
||||
[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.utils.logging :as log]))
|
||||
|
||||
(defn render-row [navigator row section-id row-id]
|
||||
(list-item [contact-view {:navigator navigator
|
||||
:contact (js->clj row :keywordize-keys true)}]))
|
||||
|
||||
(defn get-data-source [contacts]
|
||||
(clone-with-rows (data-source {:rowHasChanged (fn [row1 row2]
|
||||
(not= row1 row2))})
|
||||
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]}]
|
||||
(let [contacts (subscribe [:get-contacts])]
|
||||
(fn []
|
||||
(let [contacts-ds (get-data-source @contacts)]
|
||||
[view {:style {:flex 1
|
||||
:backgroundColor color-white}}
|
||||
[contact-list-toolbar navigator]
|
||||
(when contacts-ds
|
||||
[list-view {:dataSource contacts-ds
|
||||
:enableEmptySections true
|
||||
:renderRow (partial render-row navigator)
|
||||
:style {:backgroundColor "white"}}])]))))
|
|
@ -1,83 +0,0 @@
|
|||
(ns syng-im.components.discovery.discovery
|
||||
|
||||
(:require
|
||||
[syng-im.utils.logging :as log]
|
||||
[re-frame.core :refer [dispatch]]
|
||||
[syng-im.models.discoveries :refer [save-discoveries]]
|
||||
[syng-im.components.react :refer [android?
|
||||
view
|
||||
scroll-view
|
||||
text
|
||||
text-input]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.components.discovery.discovery-popular :refer [discovery-popular]]
|
||||
[syng-im.components.discovery.discovery-recent :refer [discovery-recent]]
|
||||
[syng-im.components.discovery.styles :as st]
|
||||
[syng-im.persistence.realm :as realm]))
|
||||
|
||||
(def search-input (atom {:search "x"}))
|
||||
|
||||
(defn get-hashtags [status]
|
||||
(let [hashtags (map #(subs % 1) (re-seq #"#[^ !?,;:.]+" status))]
|
||||
(if hashtags
|
||||
hashtags
|
||||
[])))
|
||||
|
||||
(defn title-content [showSearch]
|
||||
[view st/discovery-toolbar-content
|
||||
(if showSearch
|
||||
[text-input {:underlineColorAndroid "transparent"
|
||||
:style st/discovery-search-input
|
||||
:autoFocus true
|
||||
:placeholder "Type your search tags here"
|
||||
:onSubmitEditing (fn [e]
|
||||
(let [search (aget e "nativeEvent" "text")
|
||||
hashtags (get-hashtags search)]
|
||||
(dispatch [:broadcast-status search hashtags])))}]
|
||||
[view
|
||||
[text {:style st/discovery-title} "Discover"]])])
|
||||
|
||||
(defn create-fake-discovery []
|
||||
(let [number (rand-int 999)]
|
||||
(do
|
||||
(save-discoveries [{:name (str "Name " number)
|
||||
:status (str "Status This is some longer status to get the second line " number)
|
||||
:whisper-id (str number)
|
||||
:photo ""
|
||||
:location ""
|
||||
:tags ["tag1" "tag2" "tag3"]
|
||||
:last-updated (new js/Date)}])
|
||||
(dispatch [:updated-discoveries]))))
|
||||
|
||||
(defn discovery [{:keys [navigator]}]
|
||||
(let [showSearch (r/atom false)]
|
||||
(fn []
|
||||
[view {:style {:flex 1
|
||||
:backgroundColor "#eef2f5"}}
|
||||
[toolbar {:style st/discovery-toolbar
|
||||
:navigator navigator
|
||||
:nav-action {:image {:source {:uri "icon_hamburger"}
|
||||
:style {:width 16
|
||||
:height 12}}
|
||||
:handler create-fake-discovery}
|
||||
:title "Add Participants"
|
||||
:custom-content [title-content @showSearch]
|
||||
:action {:image {:source {:uri "icon_search"}
|
||||
:style {:width 17
|
||||
:height 17}}
|
||||
:handler (fn []
|
||||
(if @showSearch
|
||||
(reset! showSearch false)
|
||||
(reset! showSearch true)))}}]
|
||||
[scroll-view {:style {}}
|
||||
[view {:style st/section-spacing}
|
||||
[text {:style st/discovery-subtitle} "Popular tags"]]
|
||||
[discovery-popular navigator]
|
||||
[view {:style st/section-spacing}
|
||||
[text {:style st/discovery-subtitle} "Recent"]]
|
||||
[discovery-recent]]])))
|
||||
(comment
|
||||
(def page-width (aget (natal-shell.dimensions/get "window") "width"))
|
||||
(def page-height (aget (natal-shell.dimensions/get "window") "height"))
|
||||
)
|
|
@ -1,23 +0,0 @@
|
|||
(ns syng-im.components.discovery.discovery-popular
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.components.react :refer [android?
|
||||
text]]
|
||||
[syng-im.components.carousel :refer [carousel]]
|
||||
[syng-im.components.discovery.styles :as st]
|
||||
[syng-im.components.discovery.discovery-popular-list :refer [discovery-popular-list]]
|
||||
))
|
||||
|
||||
(defn page-width []
|
||||
(.-width (.get (.. js/React -Dimensions) "window")))
|
||||
|
||||
(defn discovery-popular [navigator]
|
||||
(let [popular-tags (subscribe [:get-popular-tags 3])]
|
||||
(log/debug "Got popular tags: " @popular-tags)
|
||||
(if (> (count @popular-tags) 0)
|
||||
[carousel {:pageStyle st/carousel-page-style
|
||||
:sneak 20}
|
||||
(for [tag @popular-tags]
|
||||
(discovery-popular-list (.-name tag) (.-count tag) navigator))]
|
||||
[text "None"])))
|
|
@ -1,44 +0,0 @@
|
|||
(ns syng-im.components.discovery.discovery-popular-list
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.components.react :refer [android?
|
||||
view
|
||||
list-view
|
||||
touchable-highlight
|
||||
text
|
||||
image]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.components.discovery.styles :as st]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[syng-im.components.discovery.discovery-popular-list-item :refer [discovery-popular-list-item] ])
|
||||
)
|
||||
|
||||
|
||||
(defn render-row [row section-id row-id]
|
||||
(let [elem (discovery-popular-list-item row)]
|
||||
elem)
|
||||
)
|
||||
|
||||
(defn render-separator [sectionID, rowID, adjacentRowHighlighted]
|
||||
(let [elem (r/as-element [view {:style st/row-separator
|
||||
:key rowID}])]
|
||||
elem))
|
||||
|
||||
(defn discovery-popular-list [tag count navigator]
|
||||
(let [discoveries (subscribe [:get-discoveries-by-tag tag 3])]
|
||||
[view {:style st/popular-list-container}
|
||||
[view st/row
|
||||
[view st/tag-name-container
|
||||
[touchable-highlight {:onPress #(dispatch [:show-discovery-tag tag navigator :push])}
|
||||
[text {:style st/tag-name}
|
||||
(str " #" (name tag))]]]
|
||||
[view {:style st/tag-count-container}
|
||||
[text {:style st/tag-count}
|
||||
count]]]
|
||||
[list-view {:dataSource (to-realm-datasource @discoveries)
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/popular-list}]]))
|
|
@ -1,23 +0,0 @@
|
|||
(ns syng-im.components.discovery.discovery-popular-list-item
|
||||
(:require
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.components.react :refer [android?
|
||||
view
|
||||
text
|
||||
image]]
|
||||
[syng-im.components.discovery.styles :as st]
|
||||
[reagent.core :as r])
|
||||
)
|
||||
|
||||
(defn discovery-popular-list-item [discovery]
|
||||
(r/as-element [view {:style st/popular-list-item}
|
||||
[view {:style st/popular-list-item-name-container}
|
||||
[text {:style st/popular-list-item-name} (aget discovery "name")]
|
||||
[text {:style st/popular-list-item-status
|
||||
:numberOfLines 2} (aget discovery "status")]
|
||||
]
|
||||
[view {:style st/popular-list-item-avatar-container}
|
||||
[image {:style st/popular-list-item-avatar
|
||||
:source {:uri "icon_avatar"}}]
|
||||
]
|
||||
]))
|
|
@ -1,35 +0,0 @@
|
|||
(ns syng-im.components.discovery.discovery-recent
|
||||
(:require-macros
|
||||
[natal-shell.data-source :refer [data-source clone-with-rows]]
|
||||
|
||||
)
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[syng-im.components.react :refer [android?
|
||||
view]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[syng-im.components.discovery.styles :as st]
|
||||
[syng-im.components.discovery.discovery-popular-list-item :refer [discovery-popular-list-item]]
|
||||
[reagent.core :as r]))
|
||||
|
||||
|
||||
(defn render-row [row section-id row-id]
|
||||
(let [elem (discovery-popular-list-item row)]
|
||||
elem)
|
||||
)
|
||||
|
||||
(defn render-separator [sectionID, rowID, adjacentRowHighlighted]
|
||||
(let [elem (r/as-element [view {:style st/row-separator
|
||||
:key rowID}])]
|
||||
elem))
|
||||
|
||||
(defn discovery-recent []
|
||||
(let [discoveries (subscribe [:get-discoveries])
|
||||
datasource (to-realm-datasource @discoveries)]
|
||||
[list-view {:dataSource datasource
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}]
|
||||
))
|
|
@ -1,59 +0,0 @@
|
|||
(ns syng-im.components.discovery.discovery-tag
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource
|
||||
to-datasource]]
|
||||
[syng-im.navigation :refer [nav-pop]]
|
||||
[syng-im.components.react :refer [android?
|
||||
view
|
||||
text]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.components.discovery.discovery-popular-list-item :refer [discovery-popular-list-item]]
|
||||
[syng-im.components.discovery.styles :as st]))
|
||||
|
||||
(defn render-row [row section-id row-id]
|
||||
(log/debug "discovery-tag-row: " row section-id row-id)
|
||||
(if row
|
||||
(let [elem (discovery-popular-list-item row)]
|
||||
elem)
|
||||
(r/as-element [text "null"])
|
||||
))
|
||||
|
||||
(defn render-separator [sectionID, rowID, adjacentRowHighlighted]
|
||||
(let [elem (r/as-element [view {:style st/row-separator
|
||||
:key rowID}])]
|
||||
elem))
|
||||
|
||||
(defn title-content [tag]
|
||||
[view {:style st/tag-title-container}
|
||||
[text {:style st/tag-title}
|
||||
(str " #" tag)]])
|
||||
|
||||
(defn discovery-tag [{:keys [tag navigator]}]
|
||||
(let [tag (subscribe [:get-current-tag])
|
||||
discoveries (subscribe [:get-discoveries-by-tag @tag 0])]
|
||||
(log/debug "Got discoveries: " @discoveries)
|
||||
(fn []
|
||||
(let [items @discoveries
|
||||
datasource (to-realm-datasource items)]
|
||||
[view {:style st/discovery-tag-container}
|
||||
[toolbar {:navigator navigator
|
||||
:nav-action {:image {:source {:uri "icon_back"}
|
||||
:style st/icon-back}
|
||||
:handler (fn [] (nav-pop navigator))}
|
||||
:title "Add Participants"
|
||||
:content (title-content @tag)
|
||||
:action {:image {:source {:uri "icon_search"}
|
||||
:style st/icon-search}
|
||||
:handler (fn []
|
||||
())}}]
|
||||
|
||||
[list-view {:dataSource datasource
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}]
|
||||
]))))
|
|
@ -1,44 +0,0 @@
|
|||
(ns syng-im.components.discovery.handlers
|
||||
(:require [re-frame.core :refer [register-handler after dispatch]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.protocol.api :as api]
|
||||
[syng-im.navigation :refer [nav-push
|
||||
nav-replace
|
||||
nav-pop]]
|
||||
[syng-im.models.discoveries :refer [save-discoveries
|
||||
set-current-tag
|
||||
signal-discoveries-updated]]))
|
||||
|
||||
|
||||
;; -- Discovery --------------------------------------------------------------
|
||||
|
||||
(register-handler :discovery-response-received
|
||||
(fn [db [_ from payload]]
|
||||
(let [{:keys [name status hashtags location]} payload
|
||||
location (if location location "")]
|
||||
(save-discoveries [{:name name
|
||||
:status status
|
||||
:whisper-id from
|
||||
:photo ""
|
||||
:location location
|
||||
:tags hashtags
|
||||
:last-updated (js/Date.)}])
|
||||
(signal-discoveries-updated db))))
|
||||
|
||||
(register-handler :updated-discoveries
|
||||
(fn [db _]
|
||||
(signal-discoveries-updated db)))
|
||||
|
||||
(register-handler :broadcast-status
|
||||
(fn [db [action status hashtags]]
|
||||
(let [name (:name db)]
|
||||
(log/debug "Status: " status ", Hashtags: " hashtags)
|
||||
(api/broadcast-discover-status name status hashtags)
|
||||
db)))
|
||||
|
||||
(register-handler :show-discovery-tag
|
||||
(fn [db [action tag navigator nav-type]]
|
||||
(log/debug action "setting current tag: " tag)
|
||||
(let [db (set-current-tag db tag)]
|
||||
(dispatch [:navigate-to navigator {:view-id :discovery-tag} nav-type])
|
||||
db)))
|
|
@ -1,48 +0,0 @@
|
|||
(ns syng-im.components.discovery.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]
|
||||
[syng-im.db :as db]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.models.discoveries :refer [discovery-list
|
||||
current-tag
|
||||
get-tag-popular
|
||||
discoveries-by-tag
|
||||
current-tag-updated?
|
||||
discoveries-updated?]]))
|
||||
|
||||
|
||||
|
||||
(register-sub :get-discoveries
|
||||
(fn [db _]
|
||||
(let [discoveries-updated (-> (discoveries-updated? @db)
|
||||
(reaction))]
|
||||
(reaction
|
||||
(let [_ @discoveries-updated]
|
||||
(discovery-list))))))
|
||||
|
||||
(register-sub :get-discoveries-by-tag
|
||||
(fn [db [_ tag limit]]
|
||||
(let [discoveries-updated (-> (discoveries-updated? @db)
|
||||
(reaction))]
|
||||
(log/debug "Getting discoveries for: " tag)
|
||||
(reaction
|
||||
(let [_ @discoveries-updated]
|
||||
(discoveries-by-tag tag limit))))))
|
||||
|
||||
(register-sub :get-popular-tags
|
||||
(fn [db [_ limit]]
|
||||
(let [discoveries-updated (-> (discoveries-updated? @db)
|
||||
(reaction))]
|
||||
(log/debug "Getting tags limited: " limit)
|
||||
(reaction
|
||||
(let [_ @discoveries-updated]
|
||||
(get-tag-popular limit))))))
|
||||
|
||||
(register-sub :get-current-tag
|
||||
(fn [db _]
|
||||
(let [current-tag-updated (-> (current-tag-updated? @db)
|
||||
(reaction))]
|
||||
(reaction
|
||||
(let [_ @current-tag-updated]
|
||||
(current-tag @db))))))
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.drawer-styles
|
||||
(ns syng-im.components.drawer.styles
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
color-light-blue-transparent
|
||||
color-white
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.drawer
|
||||
(ns syng-im.components.drawer.view
|
||||
(:require [clojure.string :as s]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[reagent.core :as r]
|
||||
|
@ -11,7 +11,7 @@
|
|||
drawer-layout-android
|
||||
touchable-opacity]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.drawer-styles :as st]))
|
||||
[syng-im.components.drawer.styles :as st]))
|
||||
|
||||
(defonce drawer-atom (atom))
|
||||
|
||||
|
@ -35,9 +35,9 @@
|
|||
[text {:style st/menu-item-text}
|
||||
name]])
|
||||
|
||||
(defn drawer-menu [navigator]
|
||||
(let [username (subscribe [:username])]
|
||||
(fn [navigator]
|
||||
(defn drawer-menu []
|
||||
(let [username (subscribe [:get :username])]
|
||||
(fn []
|
||||
[view st/drawer-menu
|
||||
[view st/user-photo-container
|
||||
[user-photo {}]]
|
||||
|
@ -72,10 +72,10 @@
|
|||
[text {:style st/switch-users-text}
|
||||
"Switch users"]]]])))
|
||||
|
||||
(defn drawer-view [{:keys [navigator]} items]
|
||||
(defn drawer-view [items]
|
||||
[drawer-layout-android {:drawerWidth 260
|
||||
:drawerPosition js/React.DrawerLayoutAndroid.positions.Left
|
||||
:render-navigation-view #(r/as-element [drawer-menu navigator])
|
||||
:render-navigation-view #(r/as-element [drawer-menu])
|
||||
:ref (fn [drawer]
|
||||
(reset! drawer-atom drawer))}
|
||||
items])
|
|
@ -1,109 +0,0 @@
|
|||
(ns syng-im.components.profile
|
||||
(:require [clojure.string :as s]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [android?
|
||||
view
|
||||
text
|
||||
text-input
|
||||
image
|
||||
icon
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
touchable-opacity]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.profile-styles :as st]))
|
||||
|
||||
(defn user-photo [{:keys [photo-path]}]
|
||||
[image {:source (if (s/blank? photo-path)
|
||||
res/user-no-photo
|
||||
{:uri photo-path})
|
||||
:style st/user-photo}])
|
||||
|
||||
(defn user-online [{:keys [online]}]
|
||||
(when online
|
||||
[view st/user-online-container
|
||||
[view st/user-online-dot-left]
|
||||
[view st/user-online-dot-right]]))
|
||||
|
||||
(defn profile-property-view [{:keys [name value]}]
|
||||
[view st/profile-property-view-container
|
||||
[view st/profile-property-view-sub-container
|
||||
[text {:style st/profile-property-view-label}
|
||||
name]
|
||||
[text {:style st/profile-property-view-value}
|
||||
value]]])
|
||||
|
||||
(defn message-user [identity]
|
||||
(when identity
|
||||
(dispatch [:show-chat identity nil :push])))
|
||||
|
||||
(defn profile []
|
||||
(let [contact (subscribe [:contact])]
|
||||
(fn []
|
||||
[scroll-view {:style st/profile}
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
:on-press #(dispatch [:navigate-back])}
|
||||
[view st/back-btn-container
|
||||
[icon :back st/back-btn-icon]]]
|
||||
[view st/status-block
|
||||
[view st/user-photo-container
|
||||
[user-photo {}]
|
||||
[user-online {:online true}]]
|
||||
[text {:style st/user-name}
|
||||
(:name @contact)]
|
||||
[text {:style st/status}
|
||||
"!not implemented"]
|
||||
[view st/btns-container
|
||||
[touchable-highlight {:onPress #(message-user (:whisper-identity @contact))}
|
||||
[view st/message-btn
|
||||
[text {:style st/message-btn-text}
|
||||
"Message"]]]
|
||||
[touchable-highlight {:onPress (fn []
|
||||
;; TODO not implemented
|
||||
)}
|
||||
[view st/more-btn
|
||||
[icon :more_vertical_blue st/more-btn-image]]]]]
|
||||
[view st/profile-properties-container
|
||||
[profile-property-view {:name "Username"
|
||||
:value (:name @contact)}]
|
||||
[profile-property-view {:name "Phone number"
|
||||
:value (:phone-number @contact)}]
|
||||
[profile-property-view {:name "Email"
|
||||
:value "!not implemented"}]
|
||||
[view st/report-user-container
|
||||
[touchable-opacity {}
|
||||
[text {:style st/report-user-text}
|
||||
"REPORT USER"]]]]])))
|
||||
|
||||
(defn my-profile []
|
||||
(let [username (subscribe [:username])
|
||||
phone-number (subscribe [:phone-number])
|
||||
email (subscribe [:email])
|
||||
status (subscribe [:status])]
|
||||
(fn []
|
||||
[scroll-view {:style st/profile}
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
:on-press #(dispatch [:navigate-back])}
|
||||
[view st/back-btn-container
|
||||
[icon :back st/back-btn-icon]]]
|
||||
[touchable-highlight {:style st/actions-btn-touchable
|
||||
:on-press (fn []
|
||||
;; TODO not implemented
|
||||
)}
|
||||
[view st/actions-btn-container
|
||||
[icon :dots st/actions-btn-icon]]]
|
||||
[view st/status-block
|
||||
[view st/user-photo-container
|
||||
[user-photo {}]
|
||||
[user-online {:online true}]]
|
||||
[text {:style st/user-name}
|
||||
@username]
|
||||
[text {:style st/status}
|
||||
@status]]
|
||||
[view st/profile-properties-container
|
||||
[profile-property-view {:name "Username"
|
||||
:value @username}]
|
||||
[profile-property-view {:name "Phone number"
|
||||
:value @phone-number}]
|
||||
[profile-property-view {:name "Email"
|
||||
:value @email}]]])))
|
|
@ -15,7 +15,9 @@
|
|||
(merge {:underlay-color :transparent} props)
|
||||
content])
|
||||
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
||||
(def list-view (r/adapt-react-class (.-ListView js/React)))
|
||||
(def list-view-class (r/adapt-react-class (.-ListView js/React)))
|
||||
(defn list-view [props]
|
||||
[list-view-class (merge {:enableEmptySections true} props)])
|
||||
(def scroll-view (r/adapt-react-class (.-ScrollView js/React)))
|
||||
(def touchable-without-feedback (r/adapt-react-class (.-TouchableWithoutFeedback js/React)))
|
||||
(def text-input-class (r/adapt-react-class (.-TextInput js/React)))
|
||||
|
@ -42,42 +44,3 @@
|
|||
(r/as-element component))
|
||||
|
||||
(def dismiss-keyboard! (js/require "dismissKeyboard"))
|
||||
|
||||
(comment
|
||||
(.-width (.get (.. js/React -Dimensions) "window"))
|
||||
)
|
||||
|
||||
|
||||
;; (do
|
||||
;; (def activity-indicator-ios (r/adapt-react-class (.-ActivityIndicatorIOS js/React)))
|
||||
;; (def animated-image (r/adapt-react-class (.-Animated.Image js/React)))
|
||||
;; (def animated-text (r/adapt-react-class (.-Animated.Text js/React)))
|
||||
;; (def animated-view (r/adapt-react-class (.-Animated.View js/React)))
|
||||
;; (def date-picker-ios (r/adapt-react-class (.-DatePickerIOS js/React)))
|
||||
;; (def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React)))
|
||||
;; (def image (r/adapt-react-class (.-Image js/React)))
|
||||
;; (def list-view (r/adapt-react-class (.-ListView js/React)))
|
||||
;; (def map-view (r/adapt-react-class (.-MapView js/React)))
|
||||
;; (def modal (r/adapt-react-class (.-Modal js/React)))
|
||||
;; (def navigator (r/adapt-react-class (.-Navigator js/React)))
|
||||
;; (def navigator-ios (r/adapt-react-class (.-NavigatorIOS js/React)))
|
||||
;; (def picker-ios (r/adapt-react-class (.-PickerIOS js/React)))
|
||||
;; (def progress-bar-android (r/adapt-react-class (.-ProgressBarAndroid js/React)))
|
||||
;; (def progress-view-ios (r/adapt-react-class (.-ProgressViewIOS js/React)))
|
||||
;; (def pull-to-refresh-view-android (r/adapt-react-class (.-PullToRefreshViewAndroid js/React)))
|
||||
;; (def scroll-view (r/adapt-react-class (.-ScrollView js/React)))
|
||||
;; (def segmented-control-ios (r/adapt-react-class (.-SegmentedControlIOS js/React)))
|
||||
;; (def slider-ios (r/adapt-react-class (.-SliderIOS js/React)))
|
||||
;; (def switch (r/adapt-react-class (.-Switch js/React)))
|
||||
;; (def tab-bar-ios (r/adapt-react-class (.-TabBarIOS js/React)))
|
||||
;; (def tab-bar-ios-item (r/adapt-react-class (.-TabBarIOS.Item js/React)))
|
||||
;; (def text (r/adapt-react-class (.-Text js/React)))
|
||||
;; (def text-input (r/adapt-react-class (.-TextInput js/React)))
|
||||
;; (def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
||||
;; (def touchable-highlight (r/adapt-react-class (.-TouchableHighlight js/React)))
|
||||
;; (def touchable-native-feedback (r/adapt-react-class (.-TouchableNativeFeedback js/React)))
|
||||
;; (def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React)))
|
||||
;; (def touchable-without-feedback (r/adapt-react-class (.-TouchableWithoutFeedback js/React)))
|
||||
;; (def view (r/adapt-react-class (.-View js/React)))
|
||||
;; (def view-pager-android (r/adapt-react-class (.-ViewPagerAndroid js/React)))
|
||||
;; (def web-view (r/adapt-react-class (.-WebView js/React))))
|
||||
|
|
|
@ -3,16 +3,7 @@
|
|||
|
||||
(set! js/window.RealmReactNative (js/require "realm/react-native"))
|
||||
|
||||
(def list-view (r/adapt-react-class (.-ListView js/RealmReactNative)))
|
||||
(def list-view-class (r/adapt-react-class (.-ListView js/RealmReactNative)))
|
||||
|
||||
(comment
|
||||
|
||||
|
||||
;(set! js/wat (js/require "realm.react-native.ListView"))
|
||||
;(.-Results js/Realm)
|
||||
;
|
||||
;(r/realm)
|
||||
;
|
||||
;(require '[syng-im.persistence.realm :as r])
|
||||
|
||||
)
|
||||
(defn list-view [props]
|
||||
[list-view-class (merge {:enableEmptySections true} props)])
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
(def color-black "#000000de")
|
||||
(def color-purple "#a187d5")
|
||||
(def color-gray "#838c93de")
|
||||
(def color-white "white")
|
||||
(def color-white :white)
|
||||
(def color-light-blue "#bbc4cb")
|
||||
(def color-light-blue-transparent "#bbc4cb32")
|
||||
(def color-dark-mint "#5fc48d")
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
(ns syng-im.components.toolbar
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.resources :as res]
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
text-input
|
||||
icon
|
||||
text
|
||||
image
|
||||
touchable-highlight]]
|
||||
|
@ -14,10 +14,9 @@
|
|||
text2-color
|
||||
toolbar-background1]]
|
||||
[syng-im.components.realm :refer [list-view]]
|
||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn toolbar [{:keys [navigator title nav-action hide-nav? action custom-action
|
||||
(defn toolbar [{:keys [title nav-action hide-nav? action custom-action
|
||||
background-color custom-content style]}]
|
||||
(let [style (merge {:flexDirection "row"
|
||||
:backgroundColor (or background-color toolbar-background1)
|
||||
|
@ -54,6 +53,7 @@
|
|||
[touchable-highlight {:on-press (:handler action)}
|
||||
[view {:width 56
|
||||
:height 56
|
||||
|
||||
:alignItems "center"
|
||||
:justifyContent "center"}
|
||||
[image (:image action)]]])]))
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
(ns syng-im.contacts.handlers
|
||||
(:require [re-frame.core :refer [register-handler after dispatch]]
|
||||
[syng-im.models.contacts :as contacts]
|
||||
[syng-im.utils.crypt :refer [encrypt]]
|
||||
[clojure.string :as s]
|
||||
[syng-im.utils.utils :refer [http-post]]
|
||||
[syng-im.utils.phone-number :refer [format-phone-number]]
|
||||
[syng-im.utils.handlers :as u]))
|
||||
|
||||
(defn save-contact
|
||||
[_ [_ contact]]
|
||||
(contacts/save-contacts [contact]))
|
||||
|
||||
(register-handler :add-contact
|
||||
(-> (fn [db [_ {:keys [whisper-identity] :as contact}]]
|
||||
(update db :contacts assoc whisper-identity contact))
|
||||
((after save-contact))))
|
||||
|
||||
(defn load-contacts! [db _]
|
||||
(let [contacts (->> (contacts/get-contacts)
|
||||
(map (fn [{:keys [whisper-identity] :as contact}]
|
||||
[whisper-identity contact]))
|
||||
(into {}))]
|
||||
(assoc db :contacts contacts)))
|
||||
|
||||
(register-handler :load-contacts load-contacts!)
|
||||
|
||||
;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
|
||||
(def react-native-contacts (js/require "react-native-contacts"))
|
||||
|
||||
(defn contact-name [contact]
|
||||
(->> contact
|
||||
((juxt :givenName :middleName :familyName))
|
||||
(remove s/blank?)
|
||||
(s/join " ")))
|
||||
|
||||
(defn normalize-phone-contacts [contacts]
|
||||
(let [contacts' (js->clj contacts :keywordize-keys true)]
|
||||
(map (fn [{:keys [thumbnailPath phoneNumbers] :as contact}]
|
||||
{:name (contact-name contact)
|
||||
:photo-path thumbnailPath
|
||||
:phone-numbers phoneNumbers}) contacts')))
|
||||
|
||||
(defn fetch-contacts-from-phone!
|
||||
[_ _]
|
||||
(.getAll react-native-contacts
|
||||
(fn [error contacts]
|
||||
(if error
|
||||
(dispatch [:error-on-fetching-loading error])
|
||||
(let [contacts' (normalize-phone-contacts contacts)]
|
||||
(dispatch [:get-contacts-identities contacts']))))))
|
||||
|
||||
(register-handler :sync-contacts
|
||||
(u/side-effect! fetch-contacts-from-phone!))
|
||||
|
||||
(defn get-contacts-by-hash [contacts]
|
||||
(->> contacts
|
||||
(mapcat (fn [{:keys [phone-numbers] :as contact}]
|
||||
(map (fn [{:keys [number]}]
|
||||
(let [number' (format-phone-number number)]
|
||||
[(encrypt number')
|
||||
(-> contact
|
||||
(assoc :phone-number number')
|
||||
(dissoc :phone-numbers))]))
|
||||
phone-numbers)))
|
||||
(into {})))
|
||||
|
||||
(defn add-identity [contacts-by-hash contacts]
|
||||
(map (fn [{:keys [phone-number-hash whisper-identity]}]
|
||||
(let [contact (contacts-by-hash phone-number-hash)]
|
||||
(assoc contact :whisper-identity whisper-identity)))
|
||||
(js->clj contacts)))
|
||||
|
||||
(defn request-stored-contacts [contacts]
|
||||
(let [contacts-by-hash (get-contacts-by-hash contacts)
|
||||
data (keys contacts-by-hash)]
|
||||
(http-post "get-contacts" {:phone-number-hashes data}
|
||||
(fn [{:keys [contacts]}]
|
||||
(let [contacts' (add-identity contacts-by-hash contacts)]
|
||||
(dispatch [:add-contacts contacts']))))))
|
||||
|
||||
(defn get-identities-by-contacts! [_ [_ contacts]]
|
||||
(request-stored-contacts contacts))
|
||||
|
||||
(register-handler :get-contacts-identities
|
||||
(u/side-effect! get-identities-by-contacts!))
|
||||
|
||||
(defn save-contacts! [{:keys [new-contacts]} _]
|
||||
(contacts/save-contacts new-contacts))
|
||||
|
||||
(defn add-new-contacts
|
||||
[{:keys [contacts] :as db} [_ new-contacts]]
|
||||
(let [identities (set (map :whisper-identity contacts))
|
||||
new-contacts' (remove #(identities (:whisper-identity %)) new-contacts)]
|
||||
(-> db
|
||||
(update :contacts concat new-contacts')
|
||||
(assoc :new-contacts new-contacts'))))
|
||||
|
||||
(register-handler :add-contacts
|
||||
(after save-contacts!)
|
||||
add-new-contacts)
|
|
@ -0,0 +1,35 @@
|
|||
(ns syng-im.contacts.screen
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view text
|
||||
image
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[syng-im.contacts.views.contact :refer [contact-view]]
|
||||
[syng-im.components.styles :refer [toolbar-background2]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.contacts.styles :as st]
|
||||
[syng-im.utils.listview :as lw]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [contact-view row]))
|
||||
|
||||
(defn contact-list-toolbar []
|
||||
[toolbar {:title "Contacts"
|
||||
:background-color toolbar-background2
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:style st/search-icon}
|
||||
:handler (fn [])}}])
|
||||
|
||||
(defview contact-list []
|
||||
[contacts [:get-contacts]]
|
||||
[view st/contacts-list-container
|
||||
[contact-list-toolbar]
|
||||
;; todo what if there is no contacts, should we show some information
|
||||
;; about this?
|
||||
(when contacts
|
||||
[list-view {:dataSource (lw/to-datasource contacts)
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:style st/contacts-list}])])
|
|
@ -0,0 +1,69 @@
|
|||
(ns syng-im.contacts.styles
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
title-font
|
||||
text1-color
|
||||
color-white
|
||||
online-color]]))
|
||||
|
||||
(def search-icon
|
||||
{:width 17
|
||||
:height 17})
|
||||
|
||||
(def contacts-list-container
|
||||
{:flex 1
|
||||
:backgroundColor :white})
|
||||
|
||||
(def contacts-list
|
||||
{:backgroundColor :white})
|
||||
|
||||
(def contact-photo-container
|
||||
{:borderRadius 50})
|
||||
|
||||
(def photo-image
|
||||
{:borderRadius 50
|
||||
:width 40
|
||||
:height 40})
|
||||
|
||||
(def online-container
|
||||
{:position :absolute
|
||||
:top 24
|
||||
:left 24
|
||||
:width 20
|
||||
:height 20
|
||||
:borderRadius 50
|
||||
:backgroundColor online-color
|
||||
:borderWidth 2
|
||||
:borderColor color-white})
|
||||
|
||||
(def online-dot
|
||||
{:position :absolute
|
||||
:top 6
|
||||
:width 4
|
||||
:height 4
|
||||
:borderRadius 50
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def online-dot-left
|
||||
(assoc online-dot :left 3))
|
||||
|
||||
(def online-dot-right
|
||||
(assoc online-dot :left 9))
|
||||
|
||||
(def contact-container
|
||||
{:flexDirection :row
|
||||
:height 56})
|
||||
|
||||
(def photo-container
|
||||
{:marginTop 8
|
||||
:marginLeft 16
|
||||
:width 44
|
||||
:height 44})
|
||||
|
||||
(def name-container
|
||||
{:justifyContent :center})
|
||||
|
||||
(def name-text
|
||||
{:marginLeft 16
|
||||
:fontSize 16
|
||||
:fontFamily font
|
||||
:color text1-color})
|
|
@ -0,0 +1,39 @@
|
|||
(ns syng-im.contacts.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]))
|
||||
|
||||
(register-sub :get-contacts
|
||||
(fn [db _]
|
||||
(let [contacts (reaction (:contacts @db))]
|
||||
(reaction (vals @contacts)))))
|
||||
|
||||
(register-sub :all-contacts
|
||||
(fn [db _]
|
||||
(let [contacts (reaction (:contacts @db))]
|
||||
(reaction (sort-by :name (vals @contacts))))))
|
||||
|
||||
(defn contacts-by-current-chat [fn db]
|
||||
(let [current-chat-id (:current-chat-id @db)
|
||||
chat (reaction (get-in @db [:chats current-chat-id]))
|
||||
contacts (reaction (:contacts @db))]
|
||||
(reaction
|
||||
(when @chat
|
||||
(let [current-participants (->> @chat
|
||||
:contacts
|
||||
(map :identity)
|
||||
set)]
|
||||
(fn #(current-participants (:whisper-identity %))
|
||||
(vals @contacts)))))))
|
||||
|
||||
(register-sub :contact
|
||||
(fn [db _]
|
||||
(let [identity (:contact-identity @db)]
|
||||
(reaction (get-in @db [:contacts identity])))))
|
||||
|
||||
(register-sub :all-new-contacts
|
||||
(fn [db _]
|
||||
(contacts-by-current-chat remove db)))
|
||||
|
||||
(register-sub :current-chat-contacts
|
||||
(fn [db _]
|
||||
(contacts-by-current-chat filter db)))
|
|
@ -0,0 +1,16 @@
|
|||
(ns syng-im.contacts.views.contact
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require [syng-im.components.react :refer [view touchable-highlight]]
|
||||
[re-frame.core :refer [dispatch subscribe]]
|
||||
[syng-im.contacts.views.contact-inner :refer [contact-inner-view]]))
|
||||
|
||||
(defn on-press [chat whisper-identity]
|
||||
(if chat
|
||||
#(dispatch [:navigate-to :chat whisper-identity])
|
||||
#(dispatch [:start-chat whisper-identity])))
|
||||
|
||||
(defview contact-view [{:keys [whisper-identity] :as contact}]
|
||||
[chat [:get-chat whisper-identity]]
|
||||
[touchable-highlight
|
||||
{:onPress (on-press chat whisper-identity)}
|
||||
[view {} [contact-inner-view contact]]])
|
|
@ -0,0 +1,30 @@
|
|||
(ns syng-im.contacts.views.contact-inner
|
||||
(:require [clojure.string :as s]
|
||||
[syng-im.components.react :refer [view image text]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.contacts.styles :as st]))
|
||||
|
||||
(defn contact-photo [{:keys [photo-path]}]
|
||||
[view st/contact-photo-container
|
||||
[image {:source (if (s/blank? photo-path)
|
||||
res/user-no-photo
|
||||
{:uri photo-path})
|
||||
:style st/photo-image}]])
|
||||
|
||||
(defn contact-online [{:keys [online]}]
|
||||
(when online
|
||||
[view st/online-container
|
||||
[view st/online-dot-left]
|
||||
[view st/online-dot-right]]))
|
||||
|
||||
(defn contact-inner-view [{:keys [name photo-path online]}]
|
||||
[view st/contact-container
|
||||
[view st/photo-container
|
||||
[contact-photo {:photo-path photo-path}]
|
||||
[contact-online {:online online}]]
|
||||
[view st/name-container
|
||||
[text {:style st/name-text}
|
||||
(if (pos? (count name))
|
||||
name
|
||||
;; todo is this correct behaviour?
|
||||
"Noname")]]])
|
|
@ -10,15 +10,16 @@
|
|||
(def app-db {:identity-password "replace-me-with-user-entered-password"
|
||||
:identity "me"
|
||||
:contacts []
|
||||
:contacts-ids #{}
|
||||
:current-chat-id "console"
|
||||
:chat {:command nil
|
||||
:last-message nil}
|
||||
:chat {:command nil
|
||||
:last-message nil}
|
||||
:chats {}
|
||||
:chats-updated-signal 0
|
||||
:show-actions false
|
||||
:new-group #{}
|
||||
:new-participants #{}
|
||||
:signed-up false
|
||||
:signed-up true
|
||||
:view-id default-view
|
||||
:navigation-stack (list default-view)
|
||||
;; TODO fix hardcoded values
|
||||
|
@ -29,12 +30,6 @@
|
|||
:current-tag nil})
|
||||
|
||||
(def protocol-initialized-path [:protocol-initialized])
|
||||
(def identity-password-path [:identity-password])
|
||||
(def contact-identity-path [:contact-identity])
|
||||
(def current-chat-id-path [:current-chat-id])
|
||||
(def updated-chats-signal-path [:chats-updated-signal])
|
||||
(defn updated-chat-signal-path [chat-id]
|
||||
[:chats chat-id :chat-updated-signal])
|
||||
(defn chat-input-text-path [chat-id]
|
||||
[:chats chat-id :input-text])
|
||||
(defn chat-staged-commands-path [chat-id]
|
||||
|
@ -49,11 +44,3 @@
|
|||
[:chats chat-id :command-requests])
|
||||
(defn chat-command-request-path [chat-id msg-id]
|
||||
[:chats chat-id :command-requests msg-id])
|
||||
(def show-actions-path [:show-actions])
|
||||
(def new-group-path [:new-group])
|
||||
(def new-participants-path [:new-participants])
|
||||
(def updated-discoveries-signal-path [:discovery-updated-signal])
|
||||
(defn updated-discovery-signal-path [whisper-id]
|
||||
[:discoveries whisper-id :discovery-updated-signal])
|
||||
(def current-tag-path [:current-tag])
|
||||
(def updated-current-tag-signal-path [:current-tag-updated-signal])
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
(ns syng-im.discovery.handlers
|
||||
(:require [re-frame.core :refer [register-handler after dispatch enrich]]
|
||||
[syng-im.protocol.api :as api]
|
||||
[syng-im.navigation.handlers :as nav]
|
||||
[syng-im.discovery.model :as discoveries]
|
||||
[syng-im.utils.handlers :as u]))
|
||||
|
||||
(defmethod nav/preload-data! :discovery
|
||||
[{:keys [discoveries] :as db} _]
|
||||
(if-not (seq discoveries)
|
||||
(-> db
|
||||
(assoc :tags (discoveries/all-tags))
|
||||
;; todo add limit
|
||||
;; todo hash-map with whisper-id as key and sorted by last-update
|
||||
;; may be more efficient here
|
||||
(assoc :discoveries (discoveries/discovery-list)))
|
||||
db))
|
||||
|
||||
(register-handler :discovery-response-received
|
||||
(u/side-effect!
|
||||
(fn [_ [_ from payload]]
|
||||
(let [{:keys [name status hashtags location]} payload
|
||||
location (or location "")
|
||||
discovery [{:name name
|
||||
:status status
|
||||
:whisper-id from
|
||||
:photo ""
|
||||
:location location
|
||||
:tags (map #(hash-map :name %) hashtags)
|
||||
:last-updated (js/Date.)}]]
|
||||
(dispatch [:add-discovery discovery])))))
|
||||
|
||||
(register-handler :broadcast-status
|
||||
(u/side-effect!
|
||||
(fn [{:keys [name]} [_ status hashtags]]
|
||||
(api/broadcast-discover-status name status hashtags))))
|
||||
|
||||
(register-handler :show-discovery-tag
|
||||
(fn [db [_ tag]]
|
||||
(dispatch [:navigate-to :discovery-tag])
|
||||
(assoc db :current-tag tag)))
|
||||
|
||||
;; todo remove this
|
||||
(register-handler :create-fake-discovery!
|
||||
(u/side-effect!
|
||||
(fn [_ _]
|
||||
(let [number (rand-int 999)
|
||||
discovery {:name (str "Name " number)
|
||||
:status (str "Status This is some longer status to get the second line " number)
|
||||
:whisper-id (str number)
|
||||
:photo ""
|
||||
:location ""
|
||||
:tags [{:name "tag1"}
|
||||
{:name "tag2"}
|
||||
{:name "tag3"}]
|
||||
:last-updated (new js/Date)}]
|
||||
(dispatch [:add-discovery discovery])))))
|
||||
|
||||
(defn add-discovery
|
||||
[db [_ discovery]]
|
||||
(-> db
|
||||
(assoc :new-discovery discovery)
|
||||
(update :discoveries conj discovery)))
|
||||
|
||||
(defn save-discovery!
|
||||
[{:keys [new-discovery]} _]
|
||||
(discoveries/save-discoveries [new-discovery]))
|
||||
|
||||
(defn reload-tags!
|
||||
[db _]
|
||||
(assoc db :tags (discoveries/all-tags)))
|
||||
|
||||
(register-handler :add-discovery
|
||||
(-> add-discovery
|
||||
((after save-discovery!))
|
||||
((enrich reload-tags!))))
|
|
@ -0,0 +1,89 @@
|
|||
(ns syng-im.discovery.model
|
||||
;syng-im.models.discoveries
|
||||
(:require [syng-im.utils.logging :as log]
|
||||
[syng-im.persistence.realm :as realm]
|
||||
[syng-im.persistence.realm :as r]))
|
||||
|
||||
(defn get-tag [tag]
|
||||
(log/debug "Getting tag: " tag)
|
||||
(-> (r/get-by-field :tag :name tag)
|
||||
(r/single-cljs)))
|
||||
|
||||
(defn decrease-tag-counter [tag]
|
||||
(let [tag (:name tag)
|
||||
tag-object (get-tag tag)]
|
||||
(if tag-object
|
||||
(let [counter (dec (:count tag-object))]
|
||||
(if (zero? counter)
|
||||
(realm/delete tag-object)
|
||||
(realm/create :tag {:name tag
|
||||
:count counter}
|
||||
true))))))
|
||||
|
||||
(defn increase-tag-counter [tag]
|
||||
(let [tag (:name tag)
|
||||
tag-object (get-tag tag)]
|
||||
(if tag-object
|
||||
(realm/create :tag {:name tag
|
||||
:count (inc (:count tag-object))}
|
||||
true))))
|
||||
|
||||
(defn decrease-tags-counter [tags]
|
||||
(doseq [tag tags]
|
||||
(decrease-tag-counter tag)))
|
||||
|
||||
(defn increase-tags-counter [tags]
|
||||
(doseq [tag tags]
|
||||
(increase-tag-counter tag)))
|
||||
|
||||
(defn get-tags [whisper-id]
|
||||
(:tags (-> (r/get-by-field :discoveries :whisper-id whisper-id)
|
||||
(r/single-cljs))))
|
||||
|
||||
(defn- create-discovery [{:keys [tags] :as discovery}]
|
||||
(log/debug "Creating discovery: " discovery tags)
|
||||
(realm/create :discoveries discovery true)
|
||||
(increase-tags-counter tags))
|
||||
|
||||
(defn- update-discovery [{:keys [whisper-id tags] :as discovery}]
|
||||
(let [old-tags (get-tags whisper-id)
|
||||
tags (map :name tags)]
|
||||
(decrease-tags-counter old-tags)
|
||||
(realm/create :discoveries discovery true)
|
||||
(increase-tags-counter tags)))
|
||||
|
||||
(defn- discovery-exist? [discoveries discovery]
|
||||
(some #(= (:whisper-id discovery) (:whisper-id %)) discoveries))
|
||||
|
||||
(defn discovery-list []
|
||||
(->> (-> (r/get-all :discoveries)
|
||||
(r/sorted :last-updated :desc)
|
||||
r/collection->map)
|
||||
(map #(update % :tags vals))))
|
||||
|
||||
(defn- add-discoveries [discoveries]
|
||||
(realm/write (fn []
|
||||
(let [db-discoveries (discovery-list)]
|
||||
(mapv (fn [discovery]
|
||||
(if-not (discovery-exist? db-discoveries
|
||||
discovery)
|
||||
(create-discovery discovery)
|
||||
(update-discovery discovery)))
|
||||
discoveries)))))
|
||||
|
||||
(defn save-discoveries [discoveries]
|
||||
(add-discoveries discoveries))
|
||||
|
||||
(defn discoveries-by-tag [tag limit]
|
||||
(let [discoveries (-> (r/get-by-filter :discoveries (str "tags.name = '" tag "'"))
|
||||
(r/sorted :last-updated :desc))]
|
||||
(log/debug "Discoveries by tag: " tag)
|
||||
(if (pos? limit)
|
||||
(r/page discoveries 0 limit)
|
||||
discoveries)))
|
||||
|
||||
(defn all-tags []
|
||||
(-> (r/get-all :tag)
|
||||
(r/sorted :count :desc)
|
||||
r/collection->map))
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
(ns syng-im.discovery.screen
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require
|
||||
[re-frame.core :refer [dispatch subscribe]]
|
||||
[syng-im.components.react :refer [view
|
||||
scroll-view
|
||||
text
|
||||
text-input]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.discovery.views.popular :refer [popular]]
|
||||
[syng-im.discovery.views.recent :refer [discovery-recent]]
|
||||
[syng-im.discovery.styles :as st]))
|
||||
|
||||
(defn get-hashtags [status]
|
||||
(let [hashtags (map #(subs % 1) (re-seq #"#[^ !?,;:.]+" status))]
|
||||
(or hashtags [])))
|
||||
|
||||
(defn title-content [show-search]
|
||||
[view st/discovery-toolbar-content
|
||||
(if show-search
|
||||
[text-input {:style st/discovery-search-input
|
||||
:autoFocus true
|
||||
:placeholder "Type your search tags here"
|
||||
:onSubmitEditing (fn [e]
|
||||
(let [search (aget e "nativeEvent" "text")
|
||||
hashtags (get-hashtags search)]
|
||||
(dispatch [:broadcast-status search hashtags])))}]
|
||||
[view
|
||||
[text {:style st/discovery-title} "Discover"]])])
|
||||
|
||||
(defn toogle-search [current-value]
|
||||
(dispatch [:set ::show-search (not current-value)]))
|
||||
|
||||
(defview discovery []
|
||||
[show-search [:get ::show-search]]
|
||||
[view st/discovery-container
|
||||
[toolbar
|
||||
{:style st/discovery-toolbar
|
||||
:nav-action {:image {:source {:uri :icon_hamburger}
|
||||
:style st/hamburger-icon}
|
||||
:handler #(dispatch [:create-fake-discovery!])}
|
||||
:custom-content [title-content show-search]
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:style st/search-icon}
|
||||
:handler #(toogle-search show-search)}}]
|
||||
[scroll-view {:style {}}
|
||||
[view st/section-spacing
|
||||
[text {:style st/discovery-subtitle} "Popular tags"]]
|
||||
[popular]
|
||||
[view st/section-spacing
|
||||
[text {:style st/discovery-subtitle} "Recent"]]
|
||||
[discovery-recent]]])
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.discovery.styles
|
||||
(ns syng-im.discovery.styles
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
||||
|
@ -17,7 +17,7 @@
|
|||
:borderBottomColor "#eff2f3"})
|
||||
|
||||
(def row
|
||||
{:flexDirection "row"})
|
||||
{:flexDirection :row})
|
||||
|
||||
(def column
|
||||
{:flexDirection "column"})
|
||||
|
@ -39,8 +39,8 @@
|
|||
|
||||
(def discovery-title
|
||||
{:color "#000000de"
|
||||
:alignSelf "center"
|
||||
:textAlign "center"
|
||||
:alignSelf :center
|
||||
:textAlign :center
|
||||
:fontFamily "sans-serif"
|
||||
:fontSize 16})
|
||||
|
||||
|
@ -76,8 +76,8 @@
|
|||
:fontSize 14
|
||||
:paddingRight 5
|
||||
:paddingBottom 2
|
||||
:alignItems "center"
|
||||
:justifyContent "center"})
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def tag-name-container
|
||||
{:flexDirection "column"
|
||||
|
@ -91,8 +91,8 @@
|
|||
:fontSize 12
|
||||
:paddingRight 5
|
||||
:paddingBottom 2
|
||||
:alignItems "center"
|
||||
:justifyContent "center"})
|
||||
:alignItems :center
|
||||
:justifyContent :center})
|
||||
|
||||
(def tag-count-container
|
||||
{:flex 0.2
|
||||
|
@ -103,18 +103,18 @@
|
|||
|
||||
(def popular-list-container
|
||||
{:flex 1
|
||||
:backgroundColor "white"
|
||||
:backgroundColor :white
|
||||
:paddingLeft 10
|
||||
:paddingTop 16})
|
||||
|
||||
(def popular-list
|
||||
{:backgroundColor "white"
|
||||
{:backgroundColor :white
|
||||
:paddingTop 13})
|
||||
|
||||
;; discover_popular_list_item.cjls
|
||||
|
||||
(def popular-list-item
|
||||
{:flexDirection "row"
|
||||
{:flexDirection :row
|
||||
:paddingTop 10
|
||||
:paddingBottom 10})
|
||||
|
||||
|
@ -137,7 +137,7 @@
|
|||
(def popular-list-item-avatar-container
|
||||
{:flex 0.2
|
||||
:flexDirection "column"
|
||||
:alignItems "center"
|
||||
:alignItems :center
|
||||
:paddingTop 5})
|
||||
|
||||
(def popular-list-item-avatar
|
||||
|
@ -149,7 +149,7 @@
|
|||
;; discovery_recent
|
||||
|
||||
(def recent-list
|
||||
{:backgroundColor "white"
|
||||
{:backgroundColor :white
|
||||
:paddingLeft 15})
|
||||
|
||||
;; discovery_tag
|
||||
|
@ -178,3 +178,15 @@
|
|||
(def icon-search
|
||||
{:width 17
|
||||
:height 17})
|
||||
|
||||
(def discovery-container
|
||||
{:flex 1
|
||||
:backgroundColor :#eef2f5})
|
||||
|
||||
(def hamburger-icon
|
||||
{:width 16
|
||||
:height 12})
|
||||
|
||||
(def search-icon
|
||||
{:width 17
|
||||
:height 17})
|
|
@ -0,0 +1,20 @@
|
|||
(ns syng-im.discovery.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]))
|
||||
|
||||
(register-sub :get-discoveries-by-tag
|
||||
(fn [db [_ tag limit]]
|
||||
(let [discoveries (reaction (:discoveries @db))
|
||||
tag' (or tag (:current-tag @db))
|
||||
filter-tag (filter #(some #{tag'} (map :name (:tags %))))
|
||||
xform (if limit
|
||||
(comp filter-tag (take limit))
|
||||
filter-tag)]
|
||||
(->> @discoveries
|
||||
(into [] xform)
|
||||
(reaction)))))
|
||||
|
||||
(register-sub :get-popular-tags
|
||||
(fn [db [_ limit]]
|
||||
(reaction (take limit (:tags @db)))))
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
(ns syng-im.discovery.tag
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.components.react :refer [view text list-view list-item]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.discovery.views.popular-list-item :refer [popular-list-item]]
|
||||
[syng-im.discovery.styles :as st]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [popular-list-item row]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item [view {:style st/row-separator
|
||||
:key row-id}]))
|
||||
|
||||
(defn title-content [tag]
|
||||
[view st/tag-title-container
|
||||
[text {:style st/tag-title} (str " #" tag)]])
|
||||
|
||||
(defn discovery-tag []
|
||||
(let [tag (subscribe [:get :current-tag])
|
||||
discoveries (subscribe [:get-discoveries-by-tag])]
|
||||
(log/debug "Got discoveries: " @discoveries)
|
||||
(fn []
|
||||
(let [items @discoveries
|
||||
datasource (to-datasource items)]
|
||||
[view st/discovery-tag-container
|
||||
[toolbar {:nav-action {:image {:source {:uri :icon_back}
|
||||
:style st/icon-back}
|
||||
:handler #(dispatch [:navigate-back])}
|
||||
:title "Add Participants"
|
||||
:content (title-content @tag)
|
||||
:action {:image {:source {:uri :icon_search}
|
||||
:style st/icon-search}
|
||||
:handler (fn [])}}]
|
||||
|
||||
[list-view {:dataSource datasource
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}]]))))
|
|
@ -0,0 +1,22 @@
|
|||
(ns syng-im.discovery.views.popular
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.components.react :refer [android?
|
||||
text]]
|
||||
[syng-im.components.carousel.carousel :refer [carousel]]
|
||||
[syng-im.discovery.styles :as st]
|
||||
[syng-im.discovery.views.popular-list :refer [discovery-popular-list]]))
|
||||
|
||||
(defn page-width []
|
||||
(.-width (.get (.. js/React -Dimensions) "window")))
|
||||
|
||||
(defview popular []
|
||||
[popular-tags [:get-popular-tags 3]]
|
||||
(if (pos? (count popular-tags))
|
||||
[carousel {:pageStyle st/carousel-page-style
|
||||
:sneak 20}
|
||||
(for [{:keys [name count]} popular-tags]
|
||||
[discovery-popular-list name count])]
|
||||
[text "None"]))
|
|
@ -0,0 +1,34 @@
|
|||
(ns syng-im.discovery.views.popular-list
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
list-view
|
||||
list-item
|
||||
touchable-highlight
|
||||
text]]
|
||||
[syng-im.discovery.styles :as st]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.discovery.views.popular-list-item :refer [popular-list-item]]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [popular-list-item row]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item [view {:style st/row-separator
|
||||
:key row-id}]))
|
||||
|
||||
(defview discovery-popular-list [tag count]
|
||||
[discoveries [:get-discoveries-by-tag tag 3]]
|
||||
[view st/popular-list-container
|
||||
[view st/row
|
||||
[view st/tag-name-container
|
||||
[touchable-highlight {:onPress #(dispatch [:show-discovery-tag tag])}
|
||||
[text {:style st/tag-name} (str " #" (name tag))]]]
|
||||
[view st/tag-count-container
|
||||
[text {:style st/tag-count} count]]]
|
||||
[list-view {:dataSource (to-datasource discoveries)
|
||||
:enableEmptySections true
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/popular-list}]])
|
|
@ -0,0 +1,15 @@
|
|||
(ns syng-im.discovery.views.popular-list-item
|
||||
(:require [syng-im.components.react :refer [view text image]]
|
||||
[syng-im.discovery.styles :as st]
|
||||
[reagent.core :as r]))
|
||||
|
||||
(defn popular-list-item
|
||||
[{:keys [name status]}]
|
||||
[view st/popular-list-item
|
||||
[view st/popular-list-item-name-container
|
||||
[text {:style st/popular-list-item-name} name]
|
||||
[text {:style st/popular-list-item-status
|
||||
:numberOfLines 2} status]]
|
||||
[view st/popular-list-item-avatar-container
|
||||
[image {:style st/popular-list-item-avatar
|
||||
:source {:uri :icon_avatar}}]]])
|
|
@ -0,0 +1,23 @@
|
|||
(ns syng-im.discovery.views.recent
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require
|
||||
[re-frame.core :refer [subscribe]]
|
||||
[syng-im.components.react :refer [view list-view list-item]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.discovery.styles :as st]
|
||||
[syng-im.discovery.views.popular-list-item
|
||||
:refer [popular-list-item]]))
|
||||
|
||||
(defn render-row [row _ _]
|
||||
(list-item [popular-list-item row]))
|
||||
|
||||
(defn render-separator [_ row-id _]
|
||||
(list-item [view {:style st/row-separator
|
||||
:key row-id}]))
|
||||
|
||||
(defview discovery-recent []
|
||||
[discoveries [:get :discoveries]]
|
||||
[list-view {:dataSource (to-datasource discoveries)
|
||||
:renderRow render-row
|
||||
:renderSeparator render-separator
|
||||
:style st/recent-list}])
|
|
@ -2,6 +2,7 @@
|
|||
(:require
|
||||
[re-frame.core :refer [register-handler after dispatch debug enrich]]
|
||||
[schema.core :as s :include-macros true]
|
||||
[syng-im.db :refer [app-db schema]]
|
||||
[syng-im.persistence.simple-kv-store :as kv]
|
||||
[syng-im.protocol.state.storage :as storage]
|
||||
[syng-im.db :as db :refer [app-db schema]]
|
||||
|
@ -9,47 +10,19 @@
|
|||
[syng-im.protocol.protocol-handler :refer [make-handler]]
|
||||
[syng-im.models.protocol :refer [update-identity
|
||||
set-initialized]]
|
||||
[syng-im.models.user-data :as user-data]
|
||||
[syng-im.models.contacts :as contacts]
|
||||
[syng-im.models.messages :refer [save-message
|
||||
update-message!
|
||||
message-by-id
|
||||
get-messages]]
|
||||
[syng-im.models.commands :as commands :refer [set-chat-command
|
||||
set-response-chat-command
|
||||
set-chat-command-content
|
||||
set-chat-command-request
|
||||
stage-command
|
||||
unstage-command
|
||||
set-commands]]
|
||||
[syng-im.models.messages :refer [save-message update-message!]]
|
||||
[syng-im.models.commands :refer [set-commands]]
|
||||
[syng-im.handlers.server :as server]
|
||||
[syng-im.handlers.contacts :as contacts-service]
|
||||
[syng-im.handlers.suggestions :refer [get-command
|
||||
handle-command
|
||||
get-command-handler
|
||||
load-commands
|
||||
apply-staged-commands
|
||||
check-suggestion
|
||||
switch-command-suggestions]]
|
||||
[syng-im.chat.suggestions :refer [load-commands]]
|
||||
[syng-im.handlers.sign-up :as sign-up-service]
|
||||
[syng-im.components.discovery.handlers :as discovery]
|
||||
[syng-im.models.chats :refer [chat-exists?
|
||||
create-chat
|
||||
chat-add-participants
|
||||
chat-remove-participants
|
||||
set-chat-active
|
||||
re-join-group-chat
|
||||
chat-by-id2] :as chats]
|
||||
[syng-im.models.chat :refer [signal-chat-updated
|
||||
set-current-chat-id
|
||||
current-chat-id
|
||||
update-new-group-selection
|
||||
update-new-participants-selection
|
||||
clear-new-group
|
||||
clear-new-participants
|
||||
new-group-selection
|
||||
set-chat-input-text
|
||||
new-participants-selection]]
|
||||
chat-by-id2]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.protocol.api :as api]
|
||||
[syng-im.constants :refer [text-content-type
|
||||
|
@ -59,8 +32,10 @@
|
|||
nav-pop]]
|
||||
[syng-im.utils.crypt :refer [gen-random-bytes]]
|
||||
[syng-im.utils.random :as random]
|
||||
[clojure.string :as str]
|
||||
[syng-im.components.react :as r]))
|
||||
syng-im.chat.handlers
|
||||
[syng-im.navigation.handlers :as nav]
|
||||
syng-im.discovery.handlers
|
||||
syng-im.contacts.handlers))
|
||||
|
||||
;; -- Middleware ------------------------------------------------------------
|
||||
;;
|
||||
|
@ -78,10 +53,19 @@
|
|||
|
||||
;; -- Common --------------------------------------------------------------
|
||||
|
||||
(register-handler :set
|
||||
(debug
|
||||
(fn [db [_ k v]]
|
||||
(assoc db k v))))
|
||||
|
||||
(defn preload-data!
|
||||
[{:keys [view-id] :as db} _]
|
||||
(nav/preload-data! db [nil view-id]))
|
||||
|
||||
(register-handler :initialize-db
|
||||
(fn [_ _]
|
||||
(assoc app-db
|
||||
:signed-up (storage/get kv/kv-store :signed-up))))
|
||||
:signed-up (storage/get kv/kv-store :signed-up))))
|
||||
|
||||
(register-handler :set-loading
|
||||
(fn [db [_ value]]
|
||||
|
@ -119,11 +103,6 @@
|
|||
(log/debug action 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 --------------------------------------------------------------
|
||||
|
||||
(register-handler :initialize-protocol
|
||||
|
@ -137,55 +116,6 @@
|
|||
(update-identity identity)
|
||||
(set-initialized true))))
|
||||
|
||||
(defn gen-messages [n]
|
||||
(mapv (fn [_]
|
||||
(let [id (random-uuid)]
|
||||
{:msg-id id
|
||||
:content (str id
|
||||
"ooops sdfg dsfg"
|
||||
"s dfg\ndsfg dfg\ndsfgdsfgdsfg")
|
||||
:content-type text-content-type
|
||||
:outgoing false
|
||||
:from "console"
|
||||
:to "me"})) (range n)))
|
||||
|
||||
(defn store-message!
|
||||
[{:keys [new-message]} [_ {chat-id :from}]]
|
||||
(save-message chat-id new-message))
|
||||
|
||||
(defn add-message-to-db
|
||||
[db chat-id message]
|
||||
(let [messages [:chats chat-id :messages]]
|
||||
(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
|
||||
[db [_ {chat-id :from :as message}]]
|
||||
(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
|
||||
(-> receive-message
|
||||
((after store-message!))))
|
||||
|
||||
(register-handler :group-received-msg
|
||||
(fn [db [action {chat-id :group-id :as msg}]]
|
||||
(log/debug action "msg" msg)
|
||||
(save-message chat-id msg)
|
||||
(signal-chat-updated db chat-id)))
|
||||
|
||||
(defn system-message [msg-id content]
|
||||
{:from "system"
|
||||
:msg-id msg-id
|
||||
|
@ -243,357 +173,109 @@
|
|||
(register-handler :group-chat-invite-acked
|
||||
(fn [db [action from group-id ack-msg-id]]
|
||||
(log/debug action from group-id ack-msg-id)
|
||||
(joined-chat-msg group-id from ack-msg-id)
|
||||
(signal-chat-updated db group-id)))
|
||||
(joined-chat-msg group-id from ack-msg-id)))
|
||||
|
||||
(register-handler :participant-removed-from-group
|
||||
(fn [db [action from group-id identity msg-id]]
|
||||
(log/debug action msg-id from group-id identity)
|
||||
(chat-remove-participants group-id [identity])
|
||||
(participant-removed-from-group-msg group-id identity from msg-id)
|
||||
(signal-chat-updated db group-id)))
|
||||
(participant-removed-from-group-msg group-id identity from msg-id)))
|
||||
|
||||
(register-handler :you-removed-from-group
|
||||
(fn [db [action from group-id msg-id]]
|
||||
(log/debug action msg-id from group-id)
|
||||
(you-removed-from-group-msg group-id from msg-id)
|
||||
(set-chat-active group-id false)
|
||||
(signal-chat-updated db group-id)))
|
||||
(set-chat-active group-id false)))
|
||||
|
||||
(register-handler :participant-left-group
|
||||
(fn [db [action from group-id msg-id]]
|
||||
(log/debug action msg-id from group-id)
|
||||
(if (= (api/my-identity) from)
|
||||
db
|
||||
(do (participant-left-group-msg group-id from msg-id)
|
||||
(signal-chat-updated db group-id)))))
|
||||
(participant-left-group-msg group-id from msg-id))))
|
||||
|
||||
(register-handler :participant-invited-to-group
|
||||
(fn [db [action from group-id identity msg-id]]
|
||||
(log/debug action msg-id from group-id identity)
|
||||
(participant-invited-to-group-msg group-id identity from msg-id)
|
||||
(signal-chat-updated db group-id)))
|
||||
(participant-invited-to-group-msg group-id identity from msg-id)))
|
||||
|
||||
(register-handler :acked-msg
|
||||
(fn [db [action from msg-id]]
|
||||
(log/debug action from msg-id)
|
||||
(update-message! {:msg-id msg-id
|
||||
:delivery-status :delivered})
|
||||
(signal-chat-updated db from)))
|
||||
:delivery-status :delivered})))
|
||||
|
||||
(register-handler :msg-delivery-failed
|
||||
(fn [db [action msg-id]]
|
||||
(log/debug action msg-id)
|
||||
(update-message! {:msg-id msg-id
|
||||
:delivery-status :failed})
|
||||
(let [{:keys [chat-id]} (message-by-id msg-id)]
|
||||
(signal-chat-updated db chat-id))))
|
||||
|
||||
(defn console? [s]
|
||||
(= "console" s))
|
||||
|
||||
(def not-console?
|
||||
(complement console?))
|
||||
|
||||
(defn prepare-message
|
||||
[{:keys [identity current-chat-id] :as db} _]
|
||||
(let [text (get-in db [:chats current-chat-id :input-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
|
||||
(set-chat-command db command)
|
||||
(assoc db :new-message (when-not (str/blank? text) message)))))
|
||||
|
||||
(defn prepare-command [identity chat-id staged-command]
|
||||
(let [command-key (get-in staged-command [:command :command])
|
||||
content {:command (name command-key)
|
||||
:content (:content staged-command)}]
|
||||
{:msg-id (random/id)
|
||||
:from identity
|
||||
:to chat-id
|
||||
:content content
|
||||
:content-type content-type-command
|
||||
:outgoing true
|
||||
:handler (:handler staged-command)}))
|
||||
|
||||
(defn prepare-staged-commans
|
||||
[{:keys [current-chat-id identity] :as db} _]
|
||||
(let [staged-commands (get-in db [:chats current-chat-id :staged-commands])]
|
||||
(->> staged-commands
|
||||
(map #(prepare-command identity current-chat-id %))
|
||||
;todo this is wrong :(
|
||||
(map #(check-author-direction db current-chat-id %))
|
||||
(assoc db :new-commands))))
|
||||
|
||||
(defn add-message
|
||||
[{:keys [new-message current-chat-id] :as db}]
|
||||
(if new-message
|
||||
(add-message-to-db db current-chat-id new-message)
|
||||
db))
|
||||
|
||||
(defn add-commands
|
||||
[{:keys [new-commands current-chat-id] :as db}]
|
||||
(reduce
|
||||
#(add-message-to-db %1 current-chat-id %2)
|
||||
db
|
||||
new-commands))
|
||||
|
||||
(defn clear-input
|
||||
[{:keys [current-chat-id new-message] :as db} _]
|
||||
(if new-message
|
||||
(assoc-in db [:chats current-chat-id :input-text] nil)
|
||||
db))
|
||||
|
||||
(defn clear-staged-commands
|
||||
[{:keys [current-chat-id] :as db} _]
|
||||
(assoc-in db [:chats current-chat-id :staged-commands] []))
|
||||
|
||||
(defn send-message!
|
||||
[{:keys [new-message current-chat-id]} _]
|
||||
(when (and new-message (not-console? current-chat-id))
|
||||
(api/send-user-msg {:to current-chat-id
|
||||
:content (:content new-message)})))
|
||||
|
||||
(defn save-message-to-realm!
|
||||
[{:keys [new-message current-chat-id]} _]
|
||||
(when new-message
|
||||
(save-message current-chat-id new-message)))
|
||||
|
||||
(defn save-commands-to-realm!
|
||||
[{:keys [new-commands current-chat-id]} _]
|
||||
(doseq [new-command new-commands]
|
||||
(save-message current-chat-id (dissoc new-command :handler))))
|
||||
|
||||
(defn handle-commands
|
||||
[{:keys [new-commands]}]
|
||||
(doseq [{{content :content} :content
|
||||
handler :handler} new-commands]
|
||||
(when handler
|
||||
(handler content))))
|
||||
|
||||
(register-handler :send-chat-msg
|
||||
(-> prepare-message
|
||||
((enrich prepare-staged-commans))
|
||||
((enrich add-message))
|
||||
((enrich add-commands))
|
||||
((enrich clear-input))
|
||||
((enrich clear-staged-commands))
|
||||
((after (fn [_ _] (r/dismiss-keyboard!))))
|
||||
((after send-message!))
|
||||
((after save-message-to-realm!))
|
||||
((after save-commands-to-realm!))
|
||||
((after handle-commands))))
|
||||
:delivery-status :failed})))
|
||||
|
||||
(register-handler :leave-group-chat
|
||||
(fn [db [action navigator]]
|
||||
(log/debug action)
|
||||
(let [chat-id (current-chat-id db)]
|
||||
(let [chat-id (:current-chat-id db)]
|
||||
(api/leave-group-chat chat-id)
|
||||
(set-chat-active chat-id false)
|
||||
(left-chat-msg chat-id)
|
||||
(signal-chat-updated db chat-id))))
|
||||
|
||||
(register-handler :send-group-chat-msg
|
||||
(fn [db [action chat-id text]]
|
||||
(log/debug action "chat-id" chat-id "text" text)
|
||||
(let [{msg-id :msg-id
|
||||
{from :from} :msg} (api/send-group-user-msg {:group-id chat-id
|
||||
:content text})
|
||||
msg {:msg-id msg-id
|
||||
:from from
|
||||
:to nil
|
||||
:content text
|
||||
:content-type text-content-type
|
||||
:outgoing true}]
|
||||
(save-message chat-id msg)
|
||||
(signal-chat-updated db chat-id))))
|
||||
(left-chat-msg chat-id))))
|
||||
|
||||
;; -- User data --------------------------------------------------------------
|
||||
|
||||
(register-handler :set-user-phone-number
|
||||
(fn [db [_ value]]
|
||||
(assoc db :user-phone-number value)))
|
||||
|
||||
(register-handler :load-user-phone-number
|
||||
(fn [db [_]]
|
||||
(user-data/load-phone-number)
|
||||
db))
|
||||
|
||||
;; -- Sign up --------------------------------------------------------------
|
||||
|
||||
(register-handler :sign-up
|
||||
(-> (fn [db [_ phone-number]]
|
||||
(assoc db :user-phone-number phone-number))
|
||||
((after (fn [& _] (sign-up-service/on-sign-up-response))))))
|
||||
|
||||
(register-handler :sign-up-confirm
|
||||
(fn [db [_ confirmation-code]]
|
||||
(sign-up-service/on-send-code-response confirmation-code)
|
||||
db))
|
||||
|
||||
(register-handler :sync-contacts
|
||||
(fn [db [_ handler]]
|
||||
(contacts-service/sync-contacts handler)
|
||||
db))
|
||||
|
||||
;; -- Contacts --------------------------------------------------------------
|
||||
|
||||
(register-handler :load-syng-contacts
|
||||
(fn [db [_ value]]
|
||||
(contacts/load-syng-contacts db)))
|
||||
|
||||
(register-handler :show-profile
|
||||
(fn [db [action identity]]
|
||||
(log/debug action)
|
||||
(let [db (contacts/set-contact-identity db identity)]
|
||||
(dispatch [:navigate-to :profile])
|
||||
db)))
|
||||
|
||||
(register-handler :show-my-profile
|
||||
(fn [db [action]]
|
||||
(log/debug action)
|
||||
(dispatch [:navigate-to :my-profile])
|
||||
db))
|
||||
;; todo fetch phone number from db
|
||||
(assoc db :user-phone-number "123")))
|
||||
|
||||
;; -- Chats --------------------------------------------------------------
|
||||
|
||||
(register-handler :show-chat
|
||||
(fn [db [action chat-id navigator nav-type]]
|
||||
(log/debug action "chat-id" chat-id)
|
||||
(let [db (-> db
|
||||
(create-chat chat-id [chat-id] false)
|
||||
(set-current-chat-id chat-id))]
|
||||
;; (dispatch [:navigate-to navigator {:view-id :chat} nav-type])
|
||||
(dispatch [:navigate-to :chat])
|
||||
db)))
|
||||
|
||||
(register-handler :init-console-chat
|
||||
(fn [db [_]]
|
||||
(sign-up-service/init db)))
|
||||
|
||||
(register-handler :set-signed-up
|
||||
(fn [db [_ signed-up]]
|
||||
(sign-up-service/set-signed-up db signed-up)))
|
||||
|
||||
;; -- Chat --------------------------------------------------------------
|
||||
|
||||
(defn update-text [db [_ text]]
|
||||
(set-chat-input-text db text))
|
||||
|
||||
(defn update-command [db [_ text]]
|
||||
(let [{:keys [command]} (check-suggestion db text)]
|
||||
(set-chat-command db command)))
|
||||
|
||||
(register-handler :set-chat-input-text
|
||||
((enrich update-command) update-text))
|
||||
|
||||
(register-handler :switch-command-suggestions
|
||||
(fn [db [_]]
|
||||
(switch-command-suggestions db)))
|
||||
|
||||
(register-handler :set-chat-command
|
||||
(fn [db [_ command-key]]
|
||||
;; todo what is going on there?!
|
||||
(set-chat-command db command-key)))
|
||||
|
||||
(register-handler :stage-command
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(let [db (set-chat-input-text db nil)
|
||||
{:keys [command content]}
|
||||
(get-in db [:chats current-chat-id :command-input])
|
||||
command-info {:command command
|
||||
:content content
|
||||
:handler (:handler command)}]
|
||||
(stage-command db command-info))))
|
||||
|
||||
(register-handler :unstage-command
|
||||
(fn [db [_ staged-command]]
|
||||
(let []
|
||||
(unstage-command db staged-command))))
|
||||
|
||||
(register-handler :set-response-chat-command
|
||||
(fn [db [_ to-msg-id command-key]]
|
||||
(set-response-chat-command db to-msg-id command-key)))
|
||||
|
||||
(register-handler :set-chat-command-content
|
||||
(fn [db [_ content]]
|
||||
(set-chat-command-content db content)))
|
||||
|
||||
(register-handler :set-chat-command-request
|
||||
(fn [db [_ msg-id handler]]
|
||||
(set-chat-command-request db msg-id handler)))
|
||||
|
||||
(register-handler :show-contacts
|
||||
(fn [db [action navigator]]
|
||||
(nav-push navigator {:view-id :contact-list})
|
||||
db))
|
||||
(defn update-new-participants-selection [db identity add?]
|
||||
(update db :new-participants (fn [new-participants]
|
||||
(if add?
|
||||
(conj new-participants identity)
|
||||
(disj new-participants identity)))))
|
||||
|
||||
(register-handler :select-new-participant
|
||||
(fn [db [action identity add?]]
|
||||
(log/debug action identity add?)
|
||||
(update-new-participants-selection db identity add?)))
|
||||
|
||||
(register-handler :show-remove-participants
|
||||
(fn [db [action navigator]]
|
||||
(log/debug action)
|
||||
(nav-push navigator {:view-id :remove-participants})
|
||||
(clear-new-participants db)))
|
||||
|
||||
(register-handler :remove-selected-participants
|
||||
(fn [db [action navigator]]
|
||||
(fn [db [action]]
|
||||
(log/debug action)
|
||||
(let [identities (vec (new-participants-selection db))
|
||||
chat-id (current-chat-id db)]
|
||||
(let [identities (vec (:new-participants db))
|
||||
chat-id (:current-chat-id db)]
|
||||
(chat-remove-participants chat-id identities)
|
||||
(nav-pop navigator)
|
||||
(dispatch [:navigate-back])
|
||||
(doseq [ident identities]
|
||||
(api/group-remove-participant chat-id ident)
|
||||
(removed-participant-msg chat-id ident))
|
||||
(signal-chat-updated db chat-id))))
|
||||
|
||||
(register-handler :show-add-participants
|
||||
(fn [db [action navigator]]
|
||||
(log/debug action)
|
||||
(nav-push navigator {:view-id :add-participants})
|
||||
(clear-new-participants db)))
|
||||
(removed-participant-msg chat-id ident)))))
|
||||
|
||||
(register-handler :add-new-participants
|
||||
(fn [db [action navigator]]
|
||||
(log/debug action)
|
||||
(let [identities (vec (new-participants-selection db))
|
||||
chat-id (current-chat-id db)]
|
||||
(let [identities (vec (:new-participants db))
|
||||
chat-id (:current-chat-id db)]
|
||||
(chat-add-participants chat-id identities)
|
||||
(nav-pop navigator)
|
||||
(doseq [ident identities]
|
||||
(api/group-add-participant chat-id ident))
|
||||
db)))
|
||||
|
||||
(register-handler :show-group-new
|
||||
(fn [db [action]]
|
||||
(log/debug action)
|
||||
(dispatch [:navigate-to :new-group])
|
||||
(clear-new-group db)))
|
||||
(defn update-new-group-selection [db identity add?]
|
||||
(update-in db :new-group (fn [new-group]
|
||||
(if add?
|
||||
(conj new-group identity)
|
||||
(disj new-group identity)))))
|
||||
|
||||
(register-handler :select-for-new-group
|
||||
(fn [db [action identity add?]]
|
||||
(log/debug action identity add?)
|
||||
(fn [db [_ identity add?]]
|
||||
(update-new-group-selection db identity add?)))
|
||||
|
||||
(register-handler :create-new-group
|
||||
(fn [db [action group-name navigator]]
|
||||
(fn [db [action group-name]]
|
||||
(log/debug action)
|
||||
(let [identities (vec (new-group-selection db))
|
||||
(let [identities (vec (:new-group db))
|
||||
group-id (api/start-group-chat identities group-name)
|
||||
db (create-chat db group-id identities true group-name)]
|
||||
(dispatch [:show-chat group-id navigator :replace])
|
||||
(dispatch [:show-chat group-id :replace])
|
||||
db)))
|
||||
|
||||
(register-handler :group-chat-invite-received
|
||||
|
@ -602,77 +284,3 @@
|
|||
(if (chat-exists? group-id)
|
||||
(re-join-group-chat db group-id identities group-name)
|
||||
(create-chat db group-id identities true group-name))))
|
||||
|
||||
(register-handler :navigate-to
|
||||
(fn [db [_ view-id]]
|
||||
(-> db
|
||||
(assoc :view-id view-id)
|
||||
(update :navigation-stack conj view-id))))
|
||||
|
||||
(register-handler :navigate-back
|
||||
(fn [{:keys [navigation-stack] :as db} _]
|
||||
(log/debug :navigate-back)
|
||||
(if (>= 1 (count navigation-stack))
|
||||
db
|
||||
(let [[view-id :as navigation-stack'] (pop navigation-stack)]
|
||||
(-> db
|
||||
(assoc :view-id view-id)
|
||||
(assoc :navigation-stack navigation-stack'))))))
|
||||
|
||||
(register-handler :load-more-messages
|
||||
(fn [db _]
|
||||
db
|
||||
;; TODO implement
|
||||
#_(let [chat-id (get-in db [:chat :current-chat-id])
|
||||
messages [:chats chat-id :messages]
|
||||
new-messages (gen-messages 10)]
|
||||
(update-in db messages concat new-messages))))
|
||||
|
||||
(defn load-messages!
|
||||
[db _]
|
||||
db
|
||||
(->> (current-chat-id db)
|
||||
get-messages
|
||||
(assoc db :messages)))
|
||||
|
||||
(defn init-chat
|
||||
[{:keys [messages] :as db} _]
|
||||
(let [id (current-chat-id db)]
|
||||
(assoc-in db [:chats id :messages] messages)))
|
||||
|
||||
(register-handler :init-chat
|
||||
(-> load-messages!
|
||||
((enrich init-chat))
|
||||
debug))
|
||||
|
||||
(defn initialize-chats
|
||||
[{:keys [loaded-chats] :as db} _]
|
||||
(let [chats (->> loaded-chats
|
||||
(map (fn [{:keys [chat-id] :as chat}]
|
||||
[chat-id chat]))
|
||||
(into {}))]
|
||||
(-> db
|
||||
(assoc :chats chats)
|
||||
(dissoc :loaded-chats))))
|
||||
|
||||
(defn load-chats!
|
||||
[db _]
|
||||
(assoc db :loaded-chats (chats/chats-list)))
|
||||
|
||||
(register-handler :initialize-chats
|
||||
((enrich initialize-chats) load-chats!))
|
||||
|
||||
(defn safe-trim [s]
|
||||
(when (string? s)
|
||||
(str/trim s)))
|
||||
|
||||
(register-handler :cancel-command
|
||||
(fn [{:keys [current-chat-id] :as db} _]
|
||||
(-> db
|
||||
(assoc-in [:chats current-chat-id :command-input] {})
|
||||
(update-in [:chats current-chat-id :input-text] safe-trim))))
|
||||
|
||||
(register-handler :save-password
|
||||
(fn [db [_ password]]
|
||||
(sign-up-service/save-password password)
|
||||
(assoc db :password-saved true)))
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
(ns syng-im.handlers.contacts
|
||||
(:require-macros [cljs.core.async.macros :refer [go]])
|
||||
(:require [clojure.string :as cstr]
|
||||
[cljs.core.async :as async :refer [chan put! <!]]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.utils.utils :refer [log on-error http-post toast]]
|
||||
[syng-im.utils.crypt :refer [encrypt]]
|
||||
[syng-im.utils.phone-number :refer [format-phone-number]]
|
||||
[syng-im.models.contacts :as contacts-model]
|
||||
[syng-im.utils.logging :as log]))
|
||||
|
||||
(defn- get-contact-name [phone-contact]
|
||||
(cstr/join " "
|
||||
(remove cstr/blank?
|
||||
[(:givenName phone-contact)
|
||||
(:middleName phone-contact)
|
||||
(:familyName phone-contact)])))
|
||||
|
||||
(defn- to-syng-contacts [contacts-by-hash data]
|
||||
(map (fn [server-contact]
|
||||
(let [number-info (get contacts-by-hash
|
||||
(:phone-number-hash server-contact))
|
||||
phone-contact (:contact number-info)]
|
||||
{:phone-number (:number number-info)
|
||||
:whisper-identity (:whisper-identity server-contact)
|
||||
:name (get-contact-name phone-contact)
|
||||
:photo-path (:photo-path phone-contact)}))
|
||||
(js->clj (:contacts data))))
|
||||
|
||||
(defn- get-contacts-by-hash [contacts]
|
||||
(let [numbers-info (reduce (fn [numbers contact]
|
||||
(into numbers
|
||||
(map (fn [c]
|
||||
{:number (format-phone-number (:number c))
|
||||
:contact contact})
|
||||
(:phone-numbers contact))))
|
||||
'()
|
||||
contacts)]
|
||||
(reduce (fn [m number-info]
|
||||
(let [number (:number number-info)
|
||||
hash (encrypt number)]
|
||||
(assoc m hash number-info)))
|
||||
{}
|
||||
numbers-info)))
|
||||
|
||||
(defn- request-syng-contacts [contacts]
|
||||
(let [contacts-by-hash (get-contacts-by-hash contacts)
|
||||
data (keys contacts-by-hash)
|
||||
ch (chan)]
|
||||
(http-post "get-contacts" {:phone-number-hashes data}
|
||||
(fn [data]
|
||||
(put! ch
|
||||
(to-syng-contacts contacts-by-hash data))))
|
||||
ch))
|
||||
|
||||
(defn sync-contacts [handler]
|
||||
(go
|
||||
(let [result (<! (contacts-model/load-phone-contacts))]
|
||||
(if-let [error (:error result)]
|
||||
(on-error error)
|
||||
(let [syng-contacts (<! (request-syng-contacts (:contacts result)))]
|
||||
(contacts-model/save-syng-contacts syng-contacts)
|
||||
(dispatch [:load-syng-contacts])
|
||||
(handler))))))
|
|
@ -1,12 +1,11 @@
|
|||
(ns syng-im.handlers.server
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.models.user-data :as user-data]
|
||||
[syng-im.utils.utils :refer [log on-error http-post]]
|
||||
[syng-im.utils.logging :as log]))
|
||||
|
||||
(defn sign-up
|
||||
[db phone-number handler]
|
||||
(user-data/save-phone-number phone-number)
|
||||
;(user-data/save-phone-number phone-number)
|
||||
(http-post "sign-up" {:phone-number phone-number
|
||||
:whisper-identity (get-in db [:user-identity :public])}
|
||||
(fn [body]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.persistence.simple-kv-store :as kv]
|
||||
[syng-im.protocol.state.storage :as s]
|
||||
[syng-im.models.chat :refer [set-current-chat-id]]
|
||||
[syng-im.models.chats :as c]
|
||||
[syng-im.utils.utils :refer [log on-error http-post toast]]
|
||||
[syng-im.utils.random :as random]
|
||||
|
@ -196,5 +195,5 @@
|
|||
(-> db
|
||||
(assoc-in [:chats "console"] console-chat)
|
||||
(assoc :new-chat console-chat)
|
||||
(set-current-chat-id "console")
|
||||
(assoc :current-chat-id "console")
|
||||
(intro))))))
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
(defn app-root []
|
||||
(let [greeting (subscribe [:get-greeting])]
|
||||
(fn []
|
||||
[view {:style {:flex-direction "column" :margin 40 :align-items "center"}}
|
||||
[text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align "center"}} @greeting]
|
||||
[view {:style {:flex-direction "column" :margin 40 :align-items :center}}
|
||||
[text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align :center}} @greeting]
|
||||
[image {:source logo-img
|
||||
:style {:width 80 :height 80 :margin-bottom 30}}]
|
||||
[touchable-highlight {:style {:background-color "#999" :padding 10 :border-radius 5}
|
||||
:on-press #(alert "HELLO!")}
|
||||
[text {:style {:color "white" :text-align "center" :font-weight "bold"}} "press me"]]])))
|
||||
[text {:style {:color :white :text-align :center :font-weight "bold"}} "press me"]]])))
|
||||
|
||||
(defn init []
|
||||
(dispatch-sync [:initialize-db])
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
(ns syng-im.models.chat
|
||||
(:require [syng-im.db :as db]))
|
||||
|
||||
(defn set-current-chat-id [db chat-id]
|
||||
(assoc-in db db/current-chat-id-path chat-id))
|
||||
|
||||
(defn current-chat-id [db]
|
||||
(get-in db db/current-chat-id-path))
|
||||
|
||||
(defn signal-chat-updated [db chat-id]
|
||||
(update-in db (db/updated-chat-signal-path chat-id) (fn [current]
|
||||
(if current
|
||||
(inc current)
|
||||
0))))
|
||||
|
||||
(defn chat-updated? [db chat-id]
|
||||
(get-in db (db/updated-chat-signal-path chat-id)))
|
||||
|
||||
(defn update-new-group-selection [db identity add?]
|
||||
(update-in db db/new-group-path (fn [new-group]
|
||||
(if add?
|
||||
(conj new-group identity)
|
||||
(disj new-group identity)))))
|
||||
|
||||
(defn update-new-participants-selection [db identity add?]
|
||||
(update-in db db/new-participants-path (fn [new-participants]
|
||||
(if add?
|
||||
(conj new-participants identity)
|
||||
(disj new-participants identity)))))
|
||||
|
||||
(defn new-group-selection [db]
|
||||
(get-in db db/new-group-path))
|
||||
|
||||
(defn clear-new-group [db]
|
||||
(assoc-in db db/new-group-path #{}))
|
||||
|
||||
(defn new-participants-selection [db]
|
||||
(get-in db db/new-participants-path))
|
||||
|
||||
(defn clear-new-participants [db]
|
||||
(assoc-in db db/new-participants-path #{}))
|
||||
|
||||
(defn set-chat-input-text [db text]
|
||||
(assoc-in db (db/chat-input-text-path (current-chat-id db)) text))
|
||||
|
||||
(defn get-chat-input-text [db]
|
||||
(get-in db (db/chat-input-text-path (current-chat-id db))))
|
||||
|
||||
(comment
|
||||
|
||||
(swap! re-frame.db/app-db (fn [db]
|
||||
(signal-chat-updated db "0x0479a5ed1f38cadfad1db6cd56c4b659b0ebe052bbe9efa950f6660058519fa4ca6be2dda66afa80de96ab00eb97a2605d5267a1e8f4c2a166ab551f6826608cdd")))
|
||||
|
||||
(current-chat-id @re-frame.db/app-db)
|
||||
)
|
|
@ -3,21 +3,10 @@
|
|||
[syng-im.persistence.realm :as r]
|
||||
[syng-im.utils.random :as random :refer [timestamp]]
|
||||
[clojure.string :refer [join blank?]]
|
||||
[syng-im.db :as db]
|
||||
[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.models.chat :refer [signal-chat-updated]]))
|
||||
|
||||
(defn signal-chats-updated [db]
|
||||
(update-in db db/updated-chats-signal-path (fn [current]
|
||||
(if current
|
||||
(inc current)
|
||||
0))))
|
||||
|
||||
(defn chats-updated? [db]
|
||||
(get-in db db/updated-chats-signal-path))
|
||||
[syng-im.persistence.realm-queries :refer [include-query]]))
|
||||
|
||||
(defn chat-name-from-contacts [identities]
|
||||
(let [chat-name (->> identities
|
||||
|
@ -53,8 +42,6 @@
|
|||
([{:keys [last-msg-id] :as chat}]
|
||||
(let [chat (assoc chat :last-msg-id (or last-msg-id ""))]
|
||||
(r/write #(r/create :chats chat))))
|
||||
([db chat-id identities group-chat?]
|
||||
(create-chat db chat-id identities group-chat? nil))
|
||||
([db chat-id identities group-chat? chat-name]
|
||||
(if (chat-exists? chat-id)
|
||||
db
|
||||
|
@ -73,7 +60,7 @@
|
|||
:contacts contacts
|
||||
:last-msg-id ""}))))
|
||||
(add-status-message chat-id)
|
||||
(signal-chats-updated db)))))
|
||||
db))))
|
||||
|
||||
(defn chat-contacts [chat-id]
|
||||
(-> (r/get-by-field :chats :chat-id chat-id)
|
||||
|
@ -96,8 +83,7 @@
|
|||
:is-active true
|
||||
:name group-name
|
||||
:contacts contacts} true))))
|
||||
(-> (signal-chats-updated db)
|
||||
(signal-chat-updated group-id)))
|
||||
db)
|
||||
|
||||
(defn normalize-contacts
|
||||
[chats]
|
||||
|
@ -136,13 +122,13 @@
|
|||
chat (r/single (r/get-by-field :chats :chat-id chat-id))]
|
||||
(-> (aget chat "contacts")
|
||||
(r/filtered query)
|
||||
(.forEach (fn [object index collection]
|
||||
(.forEach (fn [object _ _]
|
||||
(aset object "is-in-chat" false))))))))
|
||||
|
||||
(defn active-group-chats []
|
||||
(let [results (r/filtered (r/get-all :chats)
|
||||
"group-chat = true && is-active = true")]
|
||||
(js->clj (.map results (fn [object index collection]
|
||||
(js->clj (.map results (fn [object _ _]
|
||||
(aget object "chat-id"))))))
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
(ns syng-im.models.commands
|
||||
(:require [clojure.string :refer [join split]]
|
||||
[clojure.walk :refer [stringify-keys keywordize-keys]]
|
||||
[cljs.core.async :as async :refer [chan put! <! >!]]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.db :as db]
|
||||
[syng-im.models.chat :refer [current-chat-id]]
|
||||
[syng-im.components.styles :refer [color-blue
|
||||
color-dark-mint]]
|
||||
[syng-im.utils.utils :refer [log toast]]))
|
||||
[syng-im.components.styles :refer [color-blue color-dark-mint]]))
|
||||
|
||||
;; todo delete
|
||||
(def commands [{:command :money
|
||||
|
@ -79,52 +75,56 @@
|
|||
(defn find-command [commands command-key]
|
||||
(first (filter #(= command-key (:command %)) commands)))
|
||||
|
||||
(defn get-chat-command-content [db]
|
||||
(get-in db (db/chat-command-content-path (current-chat-id db))))
|
||||
(defn get-chat-command-content
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(get-in db (db/chat-command-content-path current-chat-id)))
|
||||
|
||||
(defn set-chat-command-content [db content]
|
||||
(assoc-in db
|
||||
[:chats (get-in db db/current-chat-id-path) :command-input :content]
|
||||
content))
|
||||
(defn set-chat-command-content
|
||||
[{:keys [current-chat-id] :as db} content]
|
||||
(assoc-in db [:chats current-chat-id :command-input :content] content))
|
||||
|
||||
(defn get-chat-command [db]
|
||||
(get-in db (db/chat-command-path (current-chat-id db))))
|
||||
(defn get-chat-command
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(get-in db (db/chat-command-path current-chat-id)))
|
||||
|
||||
(defn set-response-chat-command [db msg-id command-key]
|
||||
(let [chat-id (current-chat-id db)]
|
||||
(-> db
|
||||
(assoc-in [:chats chat-id :command-input :content] nil)
|
||||
(assoc-in [:chats chat-id :command-input :command]
|
||||
(get-command db command-key))
|
||||
(assoc-in [:chats chat-id :command-input :to-msg-id] msg-id))))
|
||||
(defn set-response-chat-command
|
||||
[{:keys [current-chat-id] :as db} msg-id command-key]
|
||||
(update-in db [:chats current-chat-id :command-input] merge
|
||||
{:content nil
|
||||
:command (get-command db command-key)
|
||||
:to-msg-id msg-id}))
|
||||
|
||||
(defn set-chat-command [db command-key]
|
||||
(set-response-chat-command db nil command-key))
|
||||
|
||||
(defn get-chat-command-to-msg-id [db]
|
||||
(get-in db (db/chat-command-to-msg-id-path (current-chat-id db))))
|
||||
(defn get-chat-command-to-msg-id
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(get-in db (db/chat-command-to-msg-id-path current-chat-id)))
|
||||
|
||||
(defn stage-command [db command-info]
|
||||
(update-in db (db/chat-staged-commands-path (current-chat-id db))
|
||||
(fn [staged-commands]
|
||||
(if staged-commands
|
||||
(conj staged-commands command-info)
|
||||
[command-info]))))
|
||||
(defn stage-command
|
||||
[{:keys [current-chat-id] :as db} command-info]
|
||||
(update-in db (db/chat-staged-commands-path current-chat-id)
|
||||
#(if %
|
||||
(conj % command-info)
|
||||
[command-info])))
|
||||
|
||||
(defn unstage-command [db staged-command]
|
||||
(update-in db (db/chat-staged-commands-path (current-chat-id db))
|
||||
(update-in db (db/chat-staged-commands-path (:current-chat-id db))
|
||||
(fn [staged-commands]
|
||||
(filterv #(not= % staged-command) staged-commands))))
|
||||
|
||||
(defn clear-staged-commands [db]
|
||||
(assoc-in db (db/chat-staged-commands-path (current-chat-id db)) []))
|
||||
(defn clear-staged-commands
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(assoc-in db (db/chat-staged-commands-path current-chat-id) []))
|
||||
|
||||
(defn get-chat-command-request [db]
|
||||
(get-in db (db/chat-command-request-path (current-chat-id db)
|
||||
(defn get-chat-command-request
|
||||
[{:keys [current-chat-id] :as db}]
|
||||
(get-in db (db/chat-command-request-path current-chat-id
|
||||
(get-chat-command-to-msg-id db))))
|
||||
|
||||
(defn set-chat-command-request [db msg-id handler]
|
||||
(update-in db (db/chat-command-requests-path (current-chat-id db))
|
||||
(defn set-chat-command-request
|
||||
[{:keys [current-chat-id] :as db} msg-id handler]
|
||||
(update-in db (db/chat-command-requests-path current-chat-id)
|
||||
#(assoc % msg-id handler)))
|
||||
|
||||
(defn parse-command-msg-content [commands content]
|
||||
|
|
|
@ -1,92 +1,21 @@
|
|||
(ns syng-im.models.contacts
|
||||
(:require [cljs.core.async :as async :refer [chan put! <! >!]]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.db :as db]
|
||||
[syng-im.utils.utils :refer [log toast]]
|
||||
[syng-im.persistence.realm :as realm]
|
||||
[syng-im.persistence.realm :as r]
|
||||
(:require [syng-im.persistence.realm :as r]
|
||||
[syng-im.persistence.realm-queries :refer [include-query
|
||||
exclude-query]]
|
||||
[clojure.string :as s]))
|
||||
exclude-query]]))
|
||||
|
||||
;; TODO see https://github.com/rt2zz/react-native-contacts/issues/45
|
||||
(def fake-phone-contacts? false)
|
||||
(def fake-contacts? false)
|
||||
(defn get-contacts []
|
||||
(-> (r/get-all :contacts)
|
||||
(r/sorted :name :asc)
|
||||
r/collection->map))
|
||||
|
||||
(def react-native-contacts (js/require "react-native-contacts"))
|
||||
(defn create-contact [{:keys [name photo-path] :as contact}]
|
||||
(->> {:name (or name "")
|
||||
:photo-path (or photo-path "")}
|
||||
(merge contact)
|
||||
(r/create :contacts)))
|
||||
|
||||
(defn- generate-contact [n]
|
||||
{:name (str "Contact " n)
|
||||
:photo-path ""
|
||||
:phone-numbers [{:label "mobile" :number (apply str (repeat 7 n))}]
|
||||
:delivery-status (if (< (rand) 0.5) :delivered :seen)
|
||||
:datetime "15:30"
|
||||
:new-messages-count (rand-int 3)
|
||||
:online (< (rand) 0.5)})
|
||||
|
||||
(defn- generate-contacts [n]
|
||||
(map generate-contact (range 1 (inc n))))
|
||||
|
||||
(defn load-phone-contacts []
|
||||
(let [ch (chan)]
|
||||
(if fake-phone-contacts?
|
||||
(put! ch {:error nil, :contacts (generate-contacts 10)})
|
||||
(.getAll react-native-contacts
|
||||
(fn [error raw-contacts]
|
||||
(put! ch
|
||||
{:error error
|
||||
:contacts
|
||||
(when (not error)
|
||||
(log raw-contacts)
|
||||
(map (fn [contact]
|
||||
(merge contact
|
||||
(generate-contact 1)
|
||||
{:name (:givenName contact)
|
||||
:photo-path (:thumbnailPath contact)
|
||||
:phone-numbers (:phoneNumbers contact)}))
|
||||
(js->clj raw-contacts :keywordize-keys true)))}))))
|
||||
ch))
|
||||
|
||||
(defn- get-contacts []
|
||||
(if fake-contacts?
|
||||
[{:phone-number "123"
|
||||
:whisper-identity "abc"
|
||||
:name "fake"
|
||||
:photo-path ""}]
|
||||
(realm/get-list :contacts)))
|
||||
|
||||
(defn load-syng-contacts [db]
|
||||
(let [contacts (map (fn [contact]
|
||||
(merge contact
|
||||
{:delivery-status (if (< (rand) 0.5) :delivered :seen)
|
||||
:datetime "15:30"
|
||||
:new-messages-count (rand-int 3)
|
||||
:online (< (rand) 0.5)}))
|
||||
(get-contacts))]
|
||||
(assoc db :contacts contacts)))
|
||||
|
||||
(defn- create-contact [{:keys [phone-number whisper-identity name photo-path]}]
|
||||
(realm/create :contacts
|
||||
{:phone-number phone-number
|
||||
:whisper-identity whisper-identity
|
||||
:name (or name "")
|
||||
:photo-path (or photo-path "")}))
|
||||
|
||||
(defn- contact-exist? [contacts contact]
|
||||
(some #(= (:phone-number contact) (:phone-number %)) contacts))
|
||||
|
||||
(defn- add-contacts [contacts]
|
||||
(realm/write (fn []
|
||||
(let [db-contacts (get-contacts)]
|
||||
(dorun (map (fn [contact]
|
||||
(if (not (contact-exist? db-contacts contact))
|
||||
(create-contact contact)
|
||||
;; TODO else override?
|
||||
))
|
||||
contacts))))))
|
||||
|
||||
(defn save-syng-contacts [syng-contacts]
|
||||
(add-contacts syng-contacts))
|
||||
(defn save-contacts [contacts]
|
||||
(r/write #(mapv create-contact contacts)))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
|
||||
|
@ -107,45 +36,4 @@
|
|||
(r/sorted :name :asc))))
|
||||
|
||||
(defn contact-by-identity [identity]
|
||||
(if (= identity "console")
|
||||
{:phone-number ""
|
||||
:whisper-identity "console"
|
||||
:name "Console"
|
||||
:photo-path ""}
|
||||
(r/single-cljs (r/get-by-field :contacts :whisper-identity identity))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
|
||||
|
||||
(defn set-contact-identity [db contact-id]
|
||||
(assoc-in db db/contact-identity-path contact-id))
|
||||
|
||||
(defn contact-identity [db]
|
||||
(get-in db db/contact-identity-path))
|
||||
|
||||
(comment
|
||||
|
||||
(r/write #(create-contact {:phone-number "0543072333"
|
||||
:whisper-identity "0x04e43e861a6dd99ad9eee7bd58af89dcaa430188ebec8698de7b7bad54573324fff4ac5cb9bb277af317efd7abfc917b91bf48cc41e40bf70062fd79400016a1f9"
|
||||
:name "Splinter"
|
||||
:photo-path ""}))
|
||||
|
||||
(r/write #(create-contact {:phone-number "0544828649"
|
||||
:whisper-identity "0x0487954e7fa746d8cf787403c2c491aadad540b9bb1f0f7b8184792e91c33b6a394079295f5777ec6d4af9ad5ba24794b3ff1ec8be9ff6a708c85a163733192665"
|
||||
:name "Exodius"
|
||||
:photo-path ""}))
|
||||
|
||||
(r/write #(create-contact {:phone-number "0522222222"
|
||||
:whisper-identity "0x0407c278af94e0b4599645023f5bec03cbdb3973bd0ae33b94c6a5885d9d20e82ff3f3c3584a637ba016af40bac2f711fd6028045756f561e36e4b07d0c2b4e623"
|
||||
:name "Mr. Eagle"
|
||||
:photo-path ""}))
|
||||
|
||||
(r/write #(create-contact {:phone-number "0533333333"
|
||||
:whisper-identity "0x04512f852558ea09d09419019f3f443ec03ff2c1913c48e567723d70e5abf239ed87fb62486b90b85e12de5d327501c1993c9905a69f2ca7e1bfbaab12dd033313"
|
||||
:name "Mr. PiggyBear"
|
||||
:photo-path ""}))
|
||||
|
||||
(contacts-list)
|
||||
|
||||
(:new-group @re-frame.db/app-db)
|
||||
|
||||
)
|
||||
(r/single-cljs (r/get-by-field :contacts :whisper-identity identity)))
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
(ns syng-im.models.discoveries
|
||||
(:require [cljs.core.async :as async :refer [chan put! <! >!]]
|
||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.utils.logging :as log]
|
||||
[syng-im.persistence.realm :as realm]
|
||||
[syng-im.persistence.realm :as r]
|
||||
[syng-im.db :as db]))
|
||||
|
||||
(defn signal-discoveries-updated [db]
|
||||
(update-in db db/updated-discoveries-signal-path (fn [current]
|
||||
(if current
|
||||
(inc current)
|
||||
0))))
|
||||
|
||||
(defn discoveries-updated? [db]
|
||||
(get-in db db/updated-discoveries-signal-path))
|
||||
|
||||
(defn current-tag-updated? [db]
|
||||
(get-in db db/updated-current-tag-signal-path))
|
||||
|
||||
|
||||
|
||||
(defn current-tag [db]
|
||||
(get-in db db/current-tag-path))
|
||||
|
||||
(defn set-current-tag [db tag]
|
||||
(assoc-in db db/current-tag-path tag))
|
||||
|
||||
(defn get-tag [tag]
|
||||
(log/debug "Getting tag: " tag)
|
||||
(-> (r/get-by-field :tag :name tag)
|
||||
(r/single-cljs)))
|
||||
|
||||
(defn decrease-tag-counter [tag]
|
||||
(let [tag (:name tag)
|
||||
tag-object (get-tag tag)]
|
||||
(if tag-object
|
||||
(let [counter (dec (:count tag-object))]
|
||||
(if (= counter 0)
|
||||
(realm/delete tag-object)
|
||||
(realm/create :tag {:name tag
|
||||
:count counter}
|
||||
true))))))
|
||||
|
||||
(defn increase-tag-counter [tag]
|
||||
(let [tag (:name tag)
|
||||
tag-object (get-tag tag)]
|
||||
(if tag-object
|
||||
(realm/create :tag {:name tag
|
||||
:count (inc (:count tag-object))}
|
||||
true))))
|
||||
|
||||
(defn decrease-tags-counter [tags]
|
||||
(doseq [tag tags]
|
||||
(decrease-tag-counter tag)))
|
||||
|
||||
(defn increase-tags-counter [tags]
|
||||
(doseq [tag tags]
|
||||
(increase-tag-counter tag)))
|
||||
|
||||
(defn get-tags [whisper-id]
|
||||
(:tags (-> (r/get-by-field :discoveries :whisper-id whisper-id)
|
||||
(r/single-cljs))))
|
||||
|
||||
(defn- create-discovery [{:keys [name status whisper-id photo location tags last-updated]}]
|
||||
(let [tags (mapv (fn [tag] {:name tag}) tags)
|
||||
discovery {:name name
|
||||
:status status
|
||||
:whisper-id whisper-id
|
||||
:photo photo
|
||||
:location location
|
||||
:tags tags
|
||||
:last-updated last-updated}]
|
||||
(log/debug "Creating discovery: " discovery tags)
|
||||
(realm/create :discoveries discovery true)
|
||||
(increase-tags-counter tags)))
|
||||
|
||||
(defn- update-discovery [{:keys [name status whisper-id photo location tags last-updated]}]
|
||||
(let [old-tags (get-tags whisper-id)
|
||||
tags (mapv (fn [tag] {:name tag}) tags)
|
||||
discovery {:name name
|
||||
:status status
|
||||
:whisper-id whisper-id
|
||||
:photo photo
|
||||
:location location
|
||||
:tags tags
|
||||
:last-updated last-updated}]
|
||||
(decrease-tags-counter old-tags)
|
||||
(realm/create :discoveries discovery true)
|
||||
(increase-tags-counter tags)))
|
||||
|
||||
(defn- discovery-exist? [discoveries discovery]
|
||||
(some #(= (:whisper-id discovery) (:whisper-id %)) discoveries))
|
||||
|
||||
(defn discovery-list []
|
||||
(-> (r/get-all :discoveries)
|
||||
(r/sorted :last-updated :desc)))
|
||||
|
||||
(defn- add-discoveries [discoveries]
|
||||
(realm/write (fn []
|
||||
(let [db-discoveries (.slice (discovery-list) 0)]
|
||||
(dorun (map (fn [discovery]
|
||||
(if (not (discovery-exist? db-discoveries discovery))
|
||||
(create-discovery discovery)
|
||||
(update-discovery discovery)
|
||||
))
|
||||
discoveries))))))
|
||||
|
||||
(defn save-discoveries [discoveries]
|
||||
(add-discoveries discoveries))
|
||||
|
||||
(defn discoveries-by-tag [tag limit]
|
||||
(let [discoveries (-> (r/get-by-filter :discoveries (str "tags.name = '" tag "'"))
|
||||
(r/sorted :last-updated :desc))]
|
||||
(log/debug "Discoveries by tag: " tag)
|
||||
(if (pos? limit)
|
||||
(r/page discoveries 0 limit)
|
||||
discoveries)))
|
||||
|
||||
(defn get-tag-popular [limit]
|
||||
(-> (r/get-all :tag)
|
||||
(r/sorted :count :desc)
|
||||
(r/page 0 limit)))
|
||||
|
|
@ -16,10 +16,6 @@
|
|||
[s]
|
||||
(keywordize-keys (apply hash-map (split s #"[;=]"))))
|
||||
|
||||
(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
|
||||
same-author same-direction]
|
||||
|
@ -55,9 +51,6 @@
|
|||
(update message :content str-to-map)
|
||||
message)))))
|
||||
|
||||
(defn message-by-id [msg-id]
|
||||
(r/single-cljs (r/get-by-field :msgs :msg-id msg-id)))
|
||||
|
||||
(defn update-message! [{:keys [msg-id] :as msg}]
|
||||
(log/debug "update-message!" msg)
|
||||
(r/write
|
||||
|
|
|
@ -6,25 +6,19 @@
|
|||
[syng-im.utils.types :refer [to-edn-string]]
|
||||
[re-frame.db :refer [app-db]]
|
||||
[syng-im.db :as db]
|
||||
[syng-im.persistence.simple-kv-store :as kv]
|
||||
[syng-im.utils.logging :as log]))
|
||||
[syng-im.persistence.simple-kv-store :as kv]))
|
||||
|
||||
(defn set-initialized [db initialized?]
|
||||
(assoc-in db db/protocol-initialized-path initialized?))
|
||||
|
||||
(defn update-identity [db identity]
|
||||
(let [password (get-in db db/identity-password-path)
|
||||
(let [password (:identity-password db)
|
||||
encrypted (password-encrypt password (to-edn-string identity))]
|
||||
(s/put kv/kv-store :identity encrypted)
|
||||
(assoc db :user-identity identity)))
|
||||
|
||||
(defn stored-identity [db]
|
||||
(let [encrypted (s/get kv/kv-store :identity)
|
||||
password (get-in db db/identity-password-path)]
|
||||
password (:identity-password db)]
|
||||
(when encrypted
|
||||
(read-string (password-decrypt password encrypted)))))
|
||||
|
||||
(comment
|
||||
|
||||
(stored-identity @re-frame.db/app-db)
|
||||
)
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
(ns syng-im.models.user-data
|
||||
(:require-macros
|
||||
[natal-shell.async-storage :refer [get-item set-item]])
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.utils.utils :refer [log on-error toast]]))
|
||||
|
||||
(defn save-phone-number [phone-number]
|
||||
(set-item "user-phone-number" phone-number)
|
||||
(dispatch [:set-user-phone-number phone-number]))
|
||||
|
||||
(defn load-phone-number []
|
||||
(get-item "user-phone-number"
|
||||
(fn [error value]
|
||||
(if error
|
||||
(on-error error)
|
||||
(dispatch [:set-user-phone-number (when value
|
||||
(str value))])))))
|
|
@ -0,0 +1,84 @@
|
|||
(ns syng-im.navigation.handlers
|
||||
(:require [re-frame.core :refer [register-handler dispatch debug enrich]]))
|
||||
|
||||
(defn push-view [db view-id]
|
||||
(-> db
|
||||
(update :navigation-stack conj view-id)
|
||||
(assoc :view-id view-id)))
|
||||
|
||||
(defn replace-top-element [stack view-id]
|
||||
(let [stack' (if (pos? (count stack))
|
||||
(pop stack)
|
||||
stack)]
|
||||
(conj stack' view-id)))
|
||||
|
||||
(defn replace-view [db view-id]
|
||||
(-> db
|
||||
(update :navigation-stack replace-top-element view-id)
|
||||
(assoc :view-id view-id)))
|
||||
|
||||
(defmulti preload-data! (fn [_ [_ view-id]] view-id))
|
||||
(defmethod preload-data! :default [db _] db)
|
||||
|
||||
(register-handler :navigate-to
|
||||
(enrich preload-data!)
|
||||
(fn [db [_ view-id]]
|
||||
(push-view db view-id)))
|
||||
|
||||
(register-handler :navigation-replace
|
||||
(fn [db [_ view-id]]
|
||||
(replace-view db view-id)))
|
||||
|
||||
(register-handler :navigate-back
|
||||
(fn [{:keys [navigation-stack] :as db} _]
|
||||
(if (>= 1 (count navigation-stack))
|
||||
db
|
||||
(let [[view-id :as navigation-stack'] (pop navigation-stack)]
|
||||
(-> db
|
||||
(assoc :view-id view-id)
|
||||
(assoc :navigation-stack navigation-stack'))))))
|
||||
|
||||
(register-handler :show-group-new
|
||||
(debug
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(push-view :new-group)
|
||||
(assoc :new-group #{})))))
|
||||
|
||||
(register-handler :show-chat
|
||||
(fn [db [_ chat-id nav-type]]
|
||||
(let [update-view-id-fn (if (= :replace nav-type) replace-view push-view)]
|
||||
(-> db
|
||||
(update-view-id-fn :chat)
|
||||
(assoc :current-chat-id chat-id)))))
|
||||
|
||||
(register-handler :show-contacts
|
||||
(fn [db _]
|
||||
(push-view db :contact-list)))
|
||||
|
||||
(defn clear-new-participants [db]
|
||||
(assoc-in db :new-participants #{}))
|
||||
|
||||
(register-handler :show-remove-participants
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(push-view :remove-participants)
|
||||
clear-new-participants)))
|
||||
|
||||
(register-handler :show-add-participants
|
||||
(fn [db _]
|
||||
(-> db
|
||||
(push-view :add-participants)
|
||||
clear-new-participants)))
|
||||
|
||||
(register-handler :show-profile
|
||||
(debug
|
||||
(fn [db [_ identity]]
|
||||
(let [db (assoc db :contact-identity identity)]
|
||||
(dispatch [:navigate-to :profile])
|
||||
db))))
|
||||
|
||||
(register-handler :show-my-profile
|
||||
(fn [db _]
|
||||
(dispatch [:navigate-to :my-profile])
|
||||
db))
|
|
@ -0,0 +1,11 @@
|
|||
(ns syng-im.navigation.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]))
|
||||
|
||||
(register-sub :view-id
|
||||
(fn [db _]
|
||||
(reaction (@db :view-id))))
|
||||
|
||||
(register-sub :navigation-stack
|
||||
(fn [db _]
|
||||
(reaction (:navigation-stack @db))))
|
|
@ -0,0 +1,58 @@
|
|||
(ns syng-im.new-group.screen
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.react :refer [view
|
||||
text-input
|
||||
text
|
||||
image
|
||||
icon
|
||||
touchable-highlight
|
||||
list-view
|
||||
list-item]]
|
||||
[syng-im.components.styles :refer [color-purple]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.new-group.views.contact :refer [new-group-contact]]
|
||||
[syng-im.new-group.styles :as st]))
|
||||
|
||||
|
||||
(defn new-group-toolbar []
|
||||
(let [group-name (subscribe [:get ::group-name])]
|
||||
(fn []
|
||||
[toolbar
|
||||
{:title "New group chat"
|
||||
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style st/toolbar-icon}
|
||||
:handler #(dispatch [:create-new-group @group-name])}}])))
|
||||
|
||||
(defn group-name-input []
|
||||
(let [group-name (subscribe [:get ::group-name])]
|
||||
(fn []
|
||||
[text-input
|
||||
{:underlineColorAndroid color-purple
|
||||
:style st/group-name-input
|
||||
:autoFocus true
|
||||
:placeholder "Group Name"
|
||||
:onChangeText #(dispatch [:set ::group-name %])
|
||||
:onSubmitEditing #(dispatch [:set ::group-name nil])}
|
||||
@group-name])))
|
||||
|
||||
(defn new-group []
|
||||
(let [contacts (subscribe [:all-contacts])]
|
||||
(fn []
|
||||
(let [contacts-ds (to-datasource @contacts)]
|
||||
[view st/new-group-container
|
||||
[new-group-toolbar]
|
||||
[view st/chat-name-container
|
||||
[text {:style st/chat-name-text} "Chat name"]
|
||||
[group-name-input]
|
||||
[text {:style st/members-text} "Members"]
|
||||
[touchable-highlight {:on-press (fn [])}
|
||||
[view st/add-container
|
||||
[icon :add_gray st/add-icon]
|
||||
[text {:style st/add-text} "Add members"]]]
|
||||
[list-view
|
||||
{:dataSource contacts-ds
|
||||
:renderRow (fn [row _ _]
|
||||
(list-item [new-group-contact row]))
|
||||
:style st/contacts-list}]]]))))
|
|
@ -0,0 +1,67 @@
|
|||
(ns syng-im.new-group.styles
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
title-font
|
||||
color-white
|
||||
color-purple
|
||||
text1-color
|
||||
text2-color
|
||||
toolbar-background1]]))
|
||||
|
||||
(def toolbar-icon
|
||||
{:width 20
|
||||
:height 18})
|
||||
|
||||
(def new-group-container
|
||||
{:flex 1
|
||||
:flexDirection :column
|
||||
:backgroundColor color-white})
|
||||
|
||||
(def chat-name-container
|
||||
{:marginHorizontal 16})
|
||||
|
||||
(def chat-name-text
|
||||
{:marginTop 24
|
||||
:marginBottom 16
|
||||
:color text2-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20})
|
||||
|
||||
(def group-name-input
|
||||
{:marginLeft -4
|
||||
:fontSize 14
|
||||
:fontFamily font
|
||||
:color text1-color})
|
||||
|
||||
(def members-text
|
||||
{:marginTop 24
|
||||
:marginBottom 16
|
||||
:color text2-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20})
|
||||
|
||||
(def add-container
|
||||
{:flexDirection :row
|
||||
:marginBottom 16})
|
||||
|
||||
(def add-icon
|
||||
{:marginVertical 19
|
||||
:marginHorizontal 3
|
||||
:width 17
|
||||
:height 17})
|
||||
|
||||
(def add-text
|
||||
{:marginTop 18
|
||||
:marginLeft 32
|
||||
:color text2-color
|
||||
:fontFamily font
|
||||
:fontSize 14
|
||||
:lineHeight 20})
|
||||
|
||||
(def contacts-list
|
||||
{:backgroundColor :white})
|
||||
|
||||
(def contact-container
|
||||
{:flexDirection :row
|
||||
:height 56})
|
|
@ -0,0 +1,19 @@
|
|||
(ns syng-im.new-group.views.contact
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view]]
|
||||
[syng-im.contacts.views.contact-inner :refer [contact-inner-view]]
|
||||
[syng-im.components.item-checkbox :refer [item-checkbox]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.new-group.styles :as st]))
|
||||
|
||||
(defn new-group-contact [{:keys [whisper-identity] :as contact}]
|
||||
(let [checked (r/atom false)]
|
||||
(fn []
|
||||
[view st/contact-container
|
||||
[item-checkbox
|
||||
{:onToggle (fn [checked?]
|
||||
(reset! checked checked?)
|
||||
(dispatch [:select-for-new-group whisper-identity checked?]))
|
||||
:checked @checked
|
||||
:size 30}]
|
||||
[contact-inner-view contact]])))
|
|
@ -0,0 +1,24 @@
|
|||
(ns syng-im.participants.styles)
|
||||
|
||||
(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})
|
||||
|
||||
(def participant-container
|
||||
{:flexDirection :row
|
||||
:marginTop 5
|
||||
:marginBottom 5
|
||||
:paddingLeft 15
|
||||
:paddingRight 15
|
||||
:height 75})
|
|
@ -0,0 +1,19 @@
|
|||
(ns syng-im.participants.views.contact
|
||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||
[syng-im.components.react :refer [view]]
|
||||
[syng-im.contacts.views.contact-inner :refer [contact-inner-view]]
|
||||
[syng-im.components.item-checkbox :refer [item-checkbox]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.participants.styles :as st]))
|
||||
|
||||
(defn participant-contact [{:keys [whisper-identity] :as contact}]
|
||||
;; todo must be moved to handlers
|
||||
(let [checked (r/atom false)]
|
||||
(fn [{:keys [whisper-identity] :as contact}]
|
||||
[view st/participant-container
|
||||
[item-checkbox {:onToggle (fn [checked?]
|
||||
(reset! checked checked?)
|
||||
(dispatch [:select-new-participant whisper-identity checked?]))
|
||||
:checked @checked
|
||||
:size 30}]
|
||||
[contact-inner-view contact]])))
|
|
@ -0,0 +1,30 @@
|
|||
(ns syng-im.participants.views.create
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.react :refer [view list-view list-item]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.participants.views.contact :refer [participant-contact]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.participants.styles :as st]))
|
||||
|
||||
(defn new-participants-toolbar []
|
||||
[toolbar
|
||||
{:title "Add Participants"
|
||||
:action {:image {:source res/v ;; {:uri "icon_search"}
|
||||
:style st/new-participant-image}
|
||||
:handler #(dispatch [:add-new-participants])}}])
|
||||
|
||||
(defn new-participants-row
|
||||
[row _ _]
|
||||
(list-item [participant-contact row]))
|
||||
|
||||
(defn new-participants []
|
||||
(let [contacts (subscribe [:all-new-contacts])]
|
||||
(fn []
|
||||
(let [contacts-ds (to-datasource @contacts)]
|
||||
[view st/participants-container
|
||||
[new-participants-toolbar]
|
||||
[list-view {:dataSource contacts-ds
|
||||
:renderRow new-participants-row
|
||||
:style st/participants-list}]]))))
|
|
@ -0,0 +1,33 @@
|
|||
(ns syng-im.participants.views.remove
|
||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.components.react :refer [view text-input text image
|
||||
touchable-highlight list-view
|
||||
list-item]]
|
||||
[syng-im.components.toolbar :refer [toolbar]]
|
||||
[syng-im.utils.listview :refer [to-datasource]]
|
||||
[syng-im.participants.views.contact
|
||||
:refer [participant-contact]]
|
||||
[reagent.core :as r]
|
||||
[syng-im.participants.styles :as st]))
|
||||
|
||||
(defn remove-participants-toolbar []
|
||||
[toolbar
|
||||
{:title "Remove Participants"
|
||||
:action {:handler #(dispatch [:remove-selected-participants])
|
||||
:image {:source res/trash-icon ;; {:uri "icon_search"}
|
||||
:style st/remove-participants-image}}}])
|
||||
|
||||
(defn remove-participants-row
|
||||
[row _ _]
|
||||
(r/as-element [participant-contact row]))
|
||||
|
||||
(defn remove-participants []
|
||||
(let [contacts (subscribe [:current-chat-contacts])]
|
||||
(fn []
|
||||
(let [contacts-ds (to-datasource @contacts)]
|
||||
[view st/participants-container
|
||||
[remove-participants-toolbar]
|
||||
[list-view {:dataSource contacts-ds
|
||||
:renderRow remove-participants-row
|
||||
:style st/participants-list}]]))))
|
|
@ -44,28 +44,28 @@
|
|||
:properties {:chat-id "string"
|
||||
:name "string"
|
||||
:group-chat {:type "bool"
|
||||
:indexed true}
|
||||
:is-active "bool"
|
||||
:timestamp "int"
|
||||
:contacts {:type "list"
|
||||
:objectType "chat-contact"}
|
||||
:indexed true}
|
||||
:is-active "bool"
|
||||
:timestamp "int"
|
||||
:contacts {:type "list"
|
||||
:objectType "chat-contact"}
|
||||
:last-msg-id "string"}}
|
||||
{:name :tag
|
||||
:primaryKey :name
|
||||
:properties {:name "string"
|
||||
:count {:type "int"
|
||||
:optional true
|
||||
:default 0}}}
|
||||
{:name :discoveries
|
||||
:primaryKey :whisper-id
|
||||
:properties {:name "string"
|
||||
:status "string"
|
||||
:whisper-id "string"
|
||||
:photo "string"
|
||||
:location "string"
|
||||
:tags {:type "list"
|
||||
:objectType "tag"}
|
||||
:last-updated "date"}}]})
|
||||
{:name :tag
|
||||
:primaryKey :name
|
||||
:properties {:name "string"
|
||||
:count {:type "int"
|
||||
:optional true
|
||||
:default 0}}}
|
||||
{:name :discoveries
|
||||
:primaryKey :whisper-id
|
||||
:properties {:name "string"
|
||||
:status "string"
|
||||
:whisper-id "string"
|
||||
:photo "string"
|
||||
:location "string"
|
||||
:tags {:type "list"
|
||||
:objectType "tag"}
|
||||
:last-updated "date"}}]})
|
||||
|
||||
(def realm (js/Realm. (clj->js opts)))
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
(ns syng-im.profile.screen
|
||||
(:require-macros [syng-im.utils.views :refer [defview]])
|
||||
(:require [clojure.string :as s]
|
||||
[re-frame.core :refer [subscribe dispatch]]
|
||||
[syng-im.components.react :refer [view
|
||||
text
|
||||
image
|
||||
icon
|
||||
scroll-view
|
||||
touchable-highlight
|
||||
touchable-opacity]]
|
||||
[syng-im.resources :as res]
|
||||
[syng-im.profile.styles :as st]))
|
||||
|
||||
(defn user-photo [{:keys [photo-path]}]
|
||||
[image {:source (if (s/blank? photo-path)
|
||||
res/user-no-photo
|
||||
{:uri photo-path})
|
||||
:style st/user-photo}])
|
||||
|
||||
(defn user-online [{:keys [online]}]
|
||||
(when online
|
||||
[view st/user-online-container
|
||||
[view st/user-online-dot-left]
|
||||
[view st/user-online-dot-right]]))
|
||||
|
||||
(defn profile-property-view [{:keys [name value]}]
|
||||
[view st/profile-property-view-container
|
||||
[view st/profile-property-view-sub-container
|
||||
[text {:style st/profile-property-view-label} name]
|
||||
[text {:style st/profile-property-view-value} value]]])
|
||||
|
||||
(defn message-user [identity]
|
||||
(when identity
|
||||
(dispatch [:show-chat identity :push])))
|
||||
|
||||
(defview profile []
|
||||
[{:keys [name whisper-identity phone-number]} [:contact]]
|
||||
[scroll-view {:style st/profile}
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
:on-press #(dispatch [:navigate-back])}
|
||||
[view st/back-btn-container
|
||||
[icon :back st/back-btn-icon]]]
|
||||
[view st/status-block
|
||||
[view st/user-photo-container
|
||||
[user-photo {}]
|
||||
[user-online {:online true}]]
|
||||
[text {:style st/user-name} name]
|
||||
[text {:style st/status} "!not implemented"]
|
||||
[view st/btns-container
|
||||
[touchable-highlight {:onPress #(message-user whisper-identity)}
|
||||
[view st/message-btn
|
||||
[text {:style st/message-btn-text} "Message"]]]
|
||||
[touchable-highlight {:onPress (fn []
|
||||
;; TODO not implemented
|
||||
)}
|
||||
[view st/more-btn
|
||||
[icon :more_vertical_blue st/more-btn-image]]]]]
|
||||
[view st/profile-properties-container
|
||||
[profile-property-view {:name "Username"
|
||||
:value name}]
|
||||
[profile-property-view {:name "Phone number"
|
||||
:value phone-number}]
|
||||
[profile-property-view {:name "Email"
|
||||
:value "!not implemented"}]
|
||||
[view st/report-user-container
|
||||
[touchable-opacity {}
|
||||
[text {:style st/report-user-text} "REPORT USER"]]]]])
|
||||
|
||||
(defview my-profile []
|
||||
[username [:get :username]
|
||||
phone-number [:get :phone-number]
|
||||
email [:get :email]
|
||||
status [:get :status]]
|
||||
[scroll-view {:style st/profile}
|
||||
[touchable-highlight {:style st/back-btn-touchable
|
||||
:on-press #(dispatch [:navigate-back])}
|
||||
[view st/back-btn-container
|
||||
[icon :back st/back-btn-icon]]]
|
||||
[touchable-highlight {:style st/actions-btn-touchable
|
||||
:on-press (fn []
|
||||
;; TODO not implemented
|
||||
)}
|
||||
[view st/actions-btn-container
|
||||
[icon :dots st/actions-btn-icon]]]
|
||||
[view st/status-block
|
||||
[view st/user-photo-container
|
||||
[user-photo {}]
|
||||
[user-online {:online true}]]
|
||||
[text {:style st/user-name} username]
|
||||
[text {:style st/status} status]]
|
||||
[view st/profile-properties-container
|
||||
[profile-property-view {:name "Username"
|
||||
:value username}]
|
||||
[profile-property-view {:name "Phone number"
|
||||
:value phone-number}]
|
||||
[profile-property-view {:name "Email"
|
||||
:value email}]]])
|
|
@ -1,4 +1,4 @@
|
|||
(ns syng-im.components.profile-styles
|
||||
(ns syng-im.profile.styles
|
||||
(:require [syng-im.components.styles :refer [font
|
||||
color-light-blue-transparent
|
||||
color-white
|
|
@ -1,204 +1,27 @@
|
|||
(ns syng-im.subs
|
||||
(:require-macros [reagent.ratom :refer [reaction]])
|
||||
(:require [re-frame.core :refer [register-sub]]
|
||||
[syng-im.db :as db]
|
||||
[syng-im.components.discovery.subs :as discovery]
|
||||
[syng-im.models.chat :refer [current-chat-id
|
||||
chat-updated?]]
|
||||
[syng-im.models.chats :refer [chats-list
|
||||
chats-updated?
|
||||
chat-by-id]]
|
||||
[syng-im.models.messages :refer [get-messages]]
|
||||
[syng-im.models.contacts :refer [contacts-list
|
||||
[syng-im.models.chats :refer [chats-list chat-by-id]]
|
||||
[syng-im.models.contacts :refer [get-contacts
|
||||
contacts-list-exclude
|
||||
contacts-list-include
|
||||
contact-identity
|
||||
contact-by-identity]]
|
||||
[syng-im.models.commands :refer [get-commands
|
||||
get-chat-command
|
||||
get-chat-command-content
|
||||
get-chat-command-request
|
||||
parse-command-request]]
|
||||
[syng-im.handlers.suggestions :refer [get-suggestions
|
||||
typing-command?]]
|
||||
[syng-im.handlers.content-suggestions :refer [get-content-suggestions]]))
|
||||
|
||||
;; -- Chat --------------------------------------------------------------
|
||||
|
||||
(register-sub :get-chat-messages
|
||||
(fn [db _]
|
||||
(let [chat-id (current-chat-id @db)]
|
||||
(reaction (get-in @db [:chats chat-id :messages])))))
|
||||
|
||||
(register-sub :get-current-chat-id
|
||||
(fn [db _]
|
||||
(reaction (current-chat-id @db))))
|
||||
|
||||
(register-sub :get-suggestions
|
||||
(fn [db _]
|
||||
(let [input-text (->> (current-chat-id @db)
|
||||
db/chat-input-text-path
|
||||
(get-in @db)
|
||||
(reaction))]
|
||||
(reaction (get-suggestions @db @input-text)))))
|
||||
|
||||
(register-sub :typing-command?
|
||||
(fn [db _]
|
||||
(reaction (typing-command? @db))))
|
||||
|
||||
(register-sub :get-content-suggestions
|
||||
(fn [db _]
|
||||
(let [command (reaction (get-chat-command @db))
|
||||
text (reaction (get-chat-command-content @db))]
|
||||
(reaction (get-content-suggestions @db @command @text)))))
|
||||
|
||||
(register-sub :get-commands
|
||||
(fn [db _]
|
||||
(reaction (get-commands @db))))
|
||||
|
||||
(register-sub :get-chat-input-text
|
||||
(fn [db _]
|
||||
(reaction (get-in @db (db/chat-input-text-path (current-chat-id @db))))))
|
||||
|
||||
(register-sub :get-chat-staged-commands
|
||||
(fn [db _]
|
||||
(reaction (get-in @db (db/chat-staged-commands-path (current-chat-id @db))))))
|
||||
|
||||
(register-sub :get-chat-command
|
||||
(fn [db _]
|
||||
(reaction (get-chat-command @db))))
|
||||
|
||||
(register-sub :get-chat-command-content
|
||||
(fn [db _]
|
||||
(reaction (get-chat-command-content @db))))
|
||||
|
||||
(register-sub :chat-command-request
|
||||
(fn [db _]
|
||||
(reaction (get-chat-command-request @db))))
|
||||
syng-im.chat.subs
|
||||
syng-im.navigation.subs
|
||||
syng-im.discovery.subs
|
||||
syng-im.contacts.subs))
|
||||
|
||||
;; -- Chats list --------------------------------------------------------------
|
||||
|
||||
(register-sub :get-chats
|
||||
(fn [db _]
|
||||
(let [chats-updated (reaction (chats-updated? @db))]
|
||||
(reaction
|
||||
(let [_ @chats-updated]
|
||||
(chats-list))))))
|
||||
|
||||
(register-sub :get-current-chat
|
||||
(fn [db _]
|
||||
(let [current-chat-id (current-chat-id @db)]
|
||||
(reaction (get-in @db [:chats current-chat-id])))))
|
||||
|
||||
|
||||
(register-sub :get
|
||||
(fn [db [_ k]]
|
||||
(reaction (k @db))))
|
||||
|
||||
;; -- User data --------------------------------------------------------------
|
||||
|
||||
(register-sub :username
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :username))))
|
||||
|
||||
(register-sub :phone-number
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :phone-number))))
|
||||
|
||||
(register-sub :email
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :email))))
|
||||
|
||||
(register-sub :status
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :status))))
|
||||
|
||||
(register-sub
|
||||
:get-user-identity
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :user-identity))))
|
||||
|
||||
(register-sub
|
||||
:get-loading
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :loading))))
|
||||
|
||||
(register-sub
|
||||
:signed-up
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :signed-up))))
|
||||
|
||||
(register-sub
|
||||
:show-actions
|
||||
(fn [db _]
|
||||
(reaction (get-in @db db/show-actions-path))))
|
||||
|
||||
(register-sub
|
||||
:get-contacts
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(get @db :contacts))))
|
||||
|
||||
(register-sub :all-contacts
|
||||
(fn [db _]
|
||||
(reaction
|
||||
(contacts-list))))
|
||||
|
||||
(register-sub :contact
|
||||
(fn [db _]
|
||||
(let [identity (reaction (get-in @db db/contact-identity-path))]
|
||||
(reaction (contact-by-identity @identity)))))
|
||||
|
||||
(register-sub :all-new-contacts
|
||||
(fn [db _]
|
||||
(let [current-chat-id (reaction (current-chat-id @db))
|
||||
chat (reaction (when-let [chat-id @current-chat-id]
|
||||
(chat-by-id chat-id)))]
|
||||
(reaction
|
||||
(when @chat
|
||||
(let [current-participants (->> @chat
|
||||
:contacts
|
||||
(map :identity))]
|
||||
(contacts-list-exclude current-participants)))))))
|
||||
|
||||
(register-sub :current-chat-contacts
|
||||
(fn [db _]
|
||||
(let [current-chat-id (reaction (current-chat-id @db))
|
||||
chat (reaction (when-let [chat-id @current-chat-id]
|
||||
(chat-by-id chat-id)))]
|
||||
(reaction
|
||||
(when @chat
|
||||
(let [current-participants (->> @chat
|
||||
:contacts
|
||||
(map :identity))]
|
||||
(contacts-list-include current-participants)))))))
|
||||
|
||||
(register-sub :view-id
|
||||
(fn [db _]
|
||||
(reaction (@db :view-id))))
|
||||
|
||||
(register-sub :chat
|
||||
(fn [db [_ k]]
|
||||
(-> @db
|
||||
(get-in [:chats (current-chat-id @db) k])
|
||||
(reaction))))
|
||||
|
||||
(register-sub :navigation-stack
|
||||
(fn [db _]
|
||||
(reaction (:navigation-stack @db))))
|
||||
(reaction (:signed-up @db))))
|
||||
|
||||
(register-sub :db
|
||||
(fn [db _] (reaction @db)))
|
||||
|
||||
(register-sub :chat-properties
|
||||
(fn [db [_ properties]]
|
||||
(->> properties
|
||||
(map (fn [k]
|
||||
[k (-> @db
|
||||
(get-in [:chats (:current-chat-id @db) k])
|
||||
(reaction))]))
|
||||
(into {}))))
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue