Merge pull request #64 from status-im/commands-button
Commands button. Phone number validation. Drawer and Profile views.
After Width: | Height: | Size: 347 B |
After Width: | Height: | Size: 366 B |
After Width: | Height: | Size: 162 B |
After Width: | Height: | Size: 274 B |
After Width: | Height: | Size: 242 B |
After Width: | Height: | Size: 129 B |
After Width: | Height: | Size: 444 B |
After Width: | Height: | Size: 500 B |
After Width: | Height: | Size: 219 B |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 775 B |
After Width: | Height: | Size: 291 B |
After Width: | Height: | Size: 892 B |
After Width: | Height: | Size: 960 B |
After Width: | Height: | Size: 413 B |
|
@ -15,6 +15,7 @@
|
||||||
[syng-im.components.chats.new-group :refer [new-group]]
|
[syng-im.components.chats.new-group :refer [new-group]]
|
||||||
[syng-im.components.chat.new-participants :refer [new-participants]]
|
[syng-im.components.chat.new-participants :refer [new-participants]]
|
||||||
[syng-im.components.chat.remove-participants :refer [remove-participants]]
|
[syng-im.components.chat.remove-participants :refer [remove-participants]]
|
||||||
|
[syng-im.components.profile :refer [profile]]
|
||||||
[syng-im.utils.logging :as log]
|
[syng-im.utils.logging :as log]
|
||||||
[syng-im.utils.utils :refer [toast]]
|
[syng-im.utils.utils :refer [toast]]
|
||||||
[syng-im.navigation :as nav]
|
[syng-im.navigation :as nav]
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
;; this listener and handle application's closing
|
;; this listener and handle application's closing
|
||||||
;; in handlers
|
;; in handlers
|
||||||
(let [stack (subscribe [:navigation-stack])]
|
(let [stack (subscribe [:navigation-stack])]
|
||||||
(when (< 1 (count stack))
|
(when (< 1 (count @stack))
|
||||||
(dispatch [:navigate-back])
|
(dispatch [:navigate-back])
|
||||||
true)))]
|
true)))]
|
||||||
(add-event-listener "hardwareBackPress" new-listener)))
|
(add-event-listener "hardwareBackPress" new-listener)))
|
||||||
|
@ -46,7 +47,8 @@
|
||||||
:chat-list [chats-list]
|
:chat-list [chats-list]
|
||||||
:new-group [new-group]
|
:new-group [new-group]
|
||||||
:contact-list [contact-list]
|
:contact-list [contact-list]
|
||||||
:chat [chat]))))
|
:chat [chat]
|
||||||
|
:profile [profile]))))
|
||||||
|
|
||||||
(defn init []
|
(defn init []
|
||||||
(dispatch-sync [:initialize-db])
|
(dispatch-sync [:initialize-db])
|
||||||
|
|
|
@ -96,9 +96,9 @@
|
||||||
subtitle])]]])
|
subtitle])]]])
|
||||||
|
|
||||||
(defn actions-list-view []
|
(defn actions-list-view []
|
||||||
(let [{:keys [group-chat active]}
|
(let [{:keys [group-chat chat-id]}
|
||||||
(subscribe [:chat-properties [:group-chat :name :contacts :active]])]
|
(subscribe [:chat-properties [:group-chat :chat-id]])]
|
||||||
(when-let [actions (when (and @group-chat @active)
|
(when-let [actions (if @group-chat
|
||||||
[{:title "Add Contact to chat"
|
[{:title "Add Contact to chat"
|
||||||
:icon :menu_group
|
:icon :menu_group
|
||||||
:icon-style {:width 25
|
:icon-style {:width 25
|
||||||
|
@ -123,7 +123,12 @@
|
||||||
:icon :settings
|
:icon :settings
|
||||||
:icon-style {:width 20
|
:icon-style {:width 20
|
||||||
:height 13}
|
:height 13}
|
||||||
:handler (fn [])}])]
|
:handler (fn [])}]
|
||||||
|
[{:title "Profile"
|
||||||
|
:icon :menu_group
|
||||||
|
:icon-style {:width 25
|
||||||
|
:height 19}
|
||||||
|
:handler #(dispatch [:show-profile @chat-id])}])]
|
||||||
[view st/actions-wrapper
|
[view st/actions-wrapper
|
||||||
[view st/actions-separator]
|
[view st/actions-separator]
|
||||||
[view st/actions-view
|
[view st/actions-view
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
(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}]]])))))
|
|
@ -0,0 +1,54 @@
|
||||||
|
(ns syng-im.components.chat.content-suggestions-styles
|
||||||
|
(:require [syng-im.components.styles :refer [font
|
||||||
|
color-light-blue-transparent
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
color-blue-transparent
|
||||||
|
selected-message-color
|
||||||
|
online-color
|
||||||
|
separator-color
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
text3-color]]))
|
||||||
|
|
||||||
|
(def suggestion-height 56)
|
||||||
|
|
||||||
|
(def suggestion-container
|
||||||
|
{:flexDirection :column
|
||||||
|
:paddingLeft 16
|
||||||
|
:backgroundColor color-white})
|
||||||
|
|
||||||
|
(def suggestion-sub-container
|
||||||
|
{:height suggestion-height
|
||||||
|
:borderBottomWidth 1
|
||||||
|
:borderBottomColor separator-color})
|
||||||
|
|
||||||
|
(def value-text
|
||||||
|
{:marginTop 9
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:color text1-color})
|
||||||
|
|
||||||
|
(def description-text
|
||||||
|
{:marginTop 1.5
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:color text2-color})
|
||||||
|
|
||||||
|
(defn suggestions-container [suggestions-count]
|
||||||
|
{:flexDirection :row
|
||||||
|
:marginVertical 1
|
||||||
|
:marginHorizontal 0
|
||||||
|
:height (min 150 (* suggestion-height suggestions-count))
|
||||||
|
:backgroundColor color-white
|
||||||
|
:borderRadius 5})
|
||||||
|
|
||||||
|
(def drag-down-touchable
|
||||||
|
{:height 22
|
||||||
|
:alignItems :center
|
||||||
|
:justifyContent :center})
|
||||||
|
|
||||||
|
(def drag-down-icon
|
||||||
|
{:width 16
|
||||||
|
:height 16})
|
|
@ -7,13 +7,8 @@
|
||||||
chat-background
|
chat-background
|
||||||
color-black]]))
|
color-black]]))
|
||||||
|
|
||||||
(def money-input
|
(def command-input-and-suggestions-container
|
||||||
{:flex 1
|
{:flexDirection :column})
|
||||||
:marginLeft 8
|
|
||||||
:lineHeight 42
|
|
||||||
:fontSize 32
|
|
||||||
:fontFamily font
|
|
||||||
:color :black})
|
|
||||||
|
|
||||||
(def command-input-container
|
(def command-input-container
|
||||||
{:flexDirection :row
|
{:flexDirection :row
|
||||||
|
|
|
@ -6,5 +6,4 @@
|
||||||
|
|
||||||
(defn money-input-view [command]
|
(defn money-input-view [command]
|
||||||
[simple-command-input-view command
|
[simple-command-input-view command
|
||||||
{:keyboardType :numeric
|
{:keyboardType :numeric}])
|
||||||
:style st/money-input}])
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
(ns syng-im.components.chat.input.phone
|
(ns syng-im.components.chat.input.phone
|
||||||
(:require
|
(:require
|
||||||
[syng-im.components.chat.input.simple-command
|
[syng-im.components.chat.input.simple-command
|
||||||
:refer [simple-command-input-view]]))
|
:refer [simple-command-input-view]]
|
||||||
|
[syng-im.utils.phone-number :refer [valid-mobile-number?]]))
|
||||||
|
|
||||||
(defn phone-input-view [command]
|
(defn phone-input-view [command]
|
||||||
[simple-command-input-view command {:keyboardType :phone-pad}])
|
[simple-command-input-view command {:keyboardType :phone-pad}
|
||||||
|
:validator valid-mobile-number?])
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
(ns syng-im.components.chat.input.simple-command
|
(ns syng-im.components.chat.input.simple-command
|
||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.components.react :refer [view
|
[syng-im.components.react :refer [view
|
||||||
image
|
|
||||||
icon
|
icon
|
||||||
text
|
text
|
||||||
text-input
|
text-input
|
||||||
touchable-highlight]]
|
touchable-highlight]]
|
||||||
[syng-im.resources :as res]
|
[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.components.chat.input.input-styles :as st]))
|
||||||
|
|
||||||
(defn cancel-command-input []
|
(defn cancel-command-input []
|
||||||
|
@ -19,23 +19,31 @@
|
||||||
(dispatch [:stage-command])
|
(dispatch [:stage-command])
|
||||||
(cancel-command-input))
|
(cancel-command-input))
|
||||||
|
|
||||||
(defn simple-command-input-view [command input-options]
|
(defn valid? [message validator]
|
||||||
|
(if validator
|
||||||
|
(validator message)
|
||||||
|
(pos? (count message))))
|
||||||
|
|
||||||
|
(defn simple-command-input-view [command input-options & {:keys [validator]}]
|
||||||
(let [message-atom (subscribe [:get-chat-command-content])]
|
(let [message-atom (subscribe [:get-chat-command-content])]
|
||||||
(fn [command input-options]
|
(fn [command input-options & {:keys [validator]}]
|
||||||
(let [message @message-atom]
|
(let [message @message-atom]
|
||||||
|
[view st/command-input-and-suggestions-container
|
||||||
|
[content-suggestions-view]
|
||||||
[view st/command-input-container
|
[view st/command-input-container
|
||||||
[view (st/command-text-container command)
|
[view (st/command-text-container command)
|
||||||
[text {:style st/command-text} (:text command)]]
|
[text {:style st/command-text} (:text command)]]
|
||||||
[text-input (merge {:style st/command-input
|
[text-input (merge {:style st/command-input
|
||||||
:autoFocus true
|
:autoFocus true
|
||||||
:onChangeText set-input-message
|
:onChangeText set-input-message
|
||||||
:onSubmitEditing send-command}
|
:onSubmitEditing (fn []
|
||||||
|
(when (valid? message validator)
|
||||||
|
(send-command)))}
|
||||||
input-options)
|
input-options)
|
||||||
message]
|
message]
|
||||||
(if (pos? (count message))
|
(if (valid? message validator)
|
||||||
[touchable-highlight {:on-press send-command}
|
[touchable-highlight {:on-press send-command}
|
||||||
[view st/send-container [icon :send st/send-icon]]]
|
[view st/send-container [icon :send st/send-icon]]]
|
||||||
[touchable-highlight {:on-press cancel-command-input}
|
[touchable-highlight {:on-press cancel-command-input}
|
||||||
[view st/cancel-container
|
[view st/cancel-container
|
||||||
[image {:source res/icon-close-gray
|
[icon :close-gray st/cancel-icon]]])]]))))
|
||||||
:style st/cancel-icon}]]])]))))
|
|
||||||
|
|
|
@ -18,24 +18,39 @@
|
||||||
(dispatch [:send-group-chat-msg chat-id input-message])
|
(dispatch [:send-group-chat-msg chat-id input-message])
|
||||||
(dispatch [:send-chat-msg]))))
|
(dispatch [:send-chat-msg]))))
|
||||||
|
|
||||||
|
(defn message-valid? [staged-commands message]
|
||||||
|
(or (and (pos? (count message))
|
||||||
|
(not= "!" message))
|
||||||
|
(pos? (count staged-commands))))
|
||||||
|
|
||||||
|
(defn try-send [chat staged-commands message]
|
||||||
|
(when (message-valid? staged-commands message)
|
||||||
|
(send chat message)))
|
||||||
|
|
||||||
(defn plain-message-input-view []
|
(defn plain-message-input-view []
|
||||||
(let [chat (subscribe [:get-current-chat])
|
(let [chat (subscribe [:get-current-chat])
|
||||||
input-message-atom (subscribe [:get-chat-input-text])
|
input-message-atom (subscribe [:get-chat-input-text])
|
||||||
staged-commands-atom (subscribe [:get-chat-staged-commands])]
|
staged-commands-atom (subscribe [:get-chat-staged-commands])
|
||||||
|
typing-command? (subscribe [:typing-command?])]
|
||||||
(fn []
|
(fn []
|
||||||
(let [input-message @input-message-atom]
|
(let [input-message @input-message-atom]
|
||||||
[view st/input-container
|
[view st/input-container
|
||||||
[suggestions-view]
|
[suggestions-view]
|
||||||
[view st/input-view
|
[view st/input-view
|
||||||
[icon :list st/list-icon]
|
[touchable-highlight {:on-press #(dispatch [:switch-command-suggestions])
|
||||||
|
:style st/switch-commands-touchable}
|
||||||
|
[view nil
|
||||||
|
(if @typing-command?
|
||||||
|
[icon :close-gray st/close-icon]
|
||||||
|
[icon :list st/list-icon])]]
|
||||||
[text-input {:style st/message-input
|
[text-input {:style st/message-input
|
||||||
:autoFocus (pos? (count @staged-commands-atom))
|
:autoFocus (pos? (count @staged-commands-atom))
|
||||||
:onChangeText set-input-message
|
:onChangeText set-input-message
|
||||||
:onSubmitEditing #(send @chat input-message)}
|
:onSubmitEditing #(try-send @chat @staged-commands-atom
|
||||||
|
input-message)}
|
||||||
input-message]
|
input-message]
|
||||||
[icon :smile st/smile-icon]
|
[icon :smile st/smile-icon]
|
||||||
(when (or (pos? (count input-message))
|
(when (message-valid? @staged-commands-atom input-message)
|
||||||
(pos? (count @staged-commands-atom)))
|
|
||||||
[touchable-highlight {:on-press #(send @chat input-message)}
|
[touchable-highlight {:on-press #(send @chat input-message)}
|
||||||
[view st/send-container
|
[view st/send-container
|
||||||
[icon :send st/send-icon]]])]]))))
|
[icon :send st/send-icon]]])]]))))
|
||||||
|
|
|
@ -12,17 +12,22 @@
|
||||||
:height 56
|
:height 56
|
||||||
:backgroundColor color-white})
|
:backgroundColor color-white})
|
||||||
|
|
||||||
|
(def switch-commands-touchable
|
||||||
|
{:width 56
|
||||||
|
:height 56
|
||||||
|
:alignItems :center
|
||||||
|
:justifyContent :center})
|
||||||
|
|
||||||
(def list-icon
|
(def list-icon
|
||||||
{:marginTop 22
|
{:width 13
|
||||||
:marginRight 6
|
:height 12})
|
||||||
:marginBottom 6
|
|
||||||
:marginLeft 21
|
(def close-icon
|
||||||
:width 13
|
{:width 12
|
||||||
:height 12})
|
:height 12})
|
||||||
|
|
||||||
(def message-input
|
(def message-input
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:marginLeft 16
|
|
||||||
:marginTop -2
|
:marginTop -2
|
||||||
:padding 0
|
:padding 0
|
||||||
:fontSize 14
|
:fontSize 14
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
(:require [re-frame.core :refer [subscribe dispatch]]
|
(:require [re-frame.core :refer [subscribe dispatch]]
|
||||||
[syng-im.components.react :refer [view
|
[syng-im.components.react :refer [view
|
||||||
text
|
text
|
||||||
|
icon
|
||||||
touchable-highlight
|
touchable-highlight
|
||||||
list-view
|
list-view
|
||||||
list-item]]
|
list-item]]
|
||||||
|
@ -16,12 +17,15 @@
|
||||||
(defn suggestion-list-item [suggestion]
|
(defn suggestion-list-item [suggestion]
|
||||||
[touchable-highlight
|
[touchable-highlight
|
||||||
{:onPress #(set-command-input (keyword (:command suggestion)))}
|
{:onPress #(set-command-input (keyword (:command suggestion)))}
|
||||||
[view st/suggestion-item-container
|
[view st/suggestion-container
|
||||||
|
[view st/suggestion-sub-container
|
||||||
[view (st/suggestion-background suggestion)
|
[view (st/suggestion-background suggestion)
|
||||||
[text {:style st/suggestion-text}
|
[text {:style st/suggestion-text}
|
||||||
(:text suggestion)]]
|
(:text suggestion)]]
|
||||||
[text {:style st/suggestion-description}
|
[text {:style st/value-text}
|
||||||
(:description suggestion)]]])
|
(:text suggestion)]
|
||||||
|
[text {:style st/description-text}
|
||||||
|
(:description suggestion)]]]])
|
||||||
|
|
||||||
(defn render-row [row _ _]
|
(defn render-row [row _ _]
|
||||||
(list-item [suggestion-list-item (js->clj row :keywordize-keys true)]))
|
(list-item [suggestion-list-item (js->clj row :keywordize-keys true)]))
|
||||||
|
@ -31,8 +35,14 @@
|
||||||
(fn []
|
(fn []
|
||||||
(let [suggestions @suggestions-atom]
|
(let [suggestions @suggestions-atom]
|
||||||
(when (seq suggestions)
|
(when (seq suggestions)
|
||||||
[view (st/suggestions-container suggestions)
|
[view nil
|
||||||
|
[touchable-highlight {:style st/drag-down-touchable
|
||||||
|
:onPress (fn []
|
||||||
|
;; TODO hide suggestions?
|
||||||
|
)}
|
||||||
|
[view nil
|
||||||
|
[icon :drag_down st/drag-down-icon]]]
|
||||||
|
[view (st/suggestions-container (count suggestions))
|
||||||
[list-view {:dataSource (to-datasource suggestions)
|
[list-view {:dataSource (to-datasource suggestions)
|
||||||
:enableEmptySections true
|
:enableEmptySections true
|
||||||
:renderRow render-row
|
:renderRow render-row}]]])))))
|
||||||
:style {}}]])))))
|
|
||||||
|
|
|
@ -1,44 +1,69 @@
|
||||||
(ns syng-im.components.chat.suggestions-styles
|
(ns syng-im.components.chat.suggestions-styles
|
||||||
(:require [syng-im.components.styles :refer [font color-white]]))
|
(:require [syng-im.components.styles :refer [font
|
||||||
|
color-light-blue-transparent
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
color-blue-transparent
|
||||||
|
selected-message-color
|
||||||
|
online-color
|
||||||
|
separator-color
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
text3-color]]))
|
||||||
|
|
||||||
(def suggestion-item-container
|
(def suggestion-height 88)
|
||||||
{:flexDirection :row
|
|
||||||
:marginVertical 1
|
(def suggestion-container
|
||||||
:marginHorizontal 0
|
{:flexDirection :column
|
||||||
:height 40
|
:paddingLeft 16
|
||||||
:backgroundColor color-white})
|
:backgroundColor color-white})
|
||||||
|
|
||||||
|
(def suggestion-sub-container
|
||||||
|
{:height suggestion-height
|
||||||
|
:borderBottomWidth 1
|
||||||
|
:borderBottomColor separator-color})
|
||||||
|
|
||||||
(defn suggestion-background
|
(defn suggestion-background
|
||||||
[{:keys [color]}]
|
[{:keys [color]}]
|
||||||
{:flexDirection :column
|
{:alignSelf :flex-start
|
||||||
:position :absolute
|
:marginTop 10
|
||||||
:top 10
|
:height 24
|
||||||
:left 60
|
|
||||||
:backgroundColor color
|
:backgroundColor color
|
||||||
:borderRadius 10})
|
:borderRadius 50})
|
||||||
|
|
||||||
(def suggestion-text
|
(def suggestion-text
|
||||||
{:marginTop -2
|
{:marginTop 2.5
|
||||||
:marginHorizontal 10
|
:marginHorizontal 12
|
||||||
:fontSize 14
|
:fontSize 12
|
||||||
:fontFamily font
|
:fontFamily font
|
||||||
:color color-white})
|
:color color-white})
|
||||||
|
|
||||||
(def suggestion-description
|
(def value-text
|
||||||
{:flex 1
|
{:marginTop 6
|
||||||
:position :absolute
|
|
||||||
:top 7
|
|
||||||
:left 190
|
|
||||||
:lineHeight 18
|
|
||||||
:fontSize 14
|
:fontSize 14
|
||||||
:fontFamily font
|
:fontFamily font
|
||||||
:color :black})
|
:color text1-color})
|
||||||
|
|
||||||
(defn suggestions-container
|
(def description-text
|
||||||
[suggestions]
|
{:marginTop 2
|
||||||
|
:fontSize 12
|
||||||
|
:fontFamily font
|
||||||
|
:color text2-color})
|
||||||
|
|
||||||
|
(defn suggestions-container [suggestions-count]
|
||||||
{:flexDirection :row
|
{:flexDirection :row
|
||||||
:marginVertical 1
|
:marginVertical 1
|
||||||
:marginHorizontal 0
|
:marginHorizontal 0
|
||||||
:height (min 105 (* 42 (count suggestions)))
|
:height (min 168 (* suggestion-height suggestions-count))
|
||||||
:backgroundColor color-white
|
:backgroundColor color-white
|
||||||
:borderRadius 5})
|
:borderRadius 5})
|
||||||
|
|
||||||
|
(def drag-down-touchable
|
||||||
|
{:height 22
|
||||||
|
:alignItems :center
|
||||||
|
:justifyContent :center})
|
||||||
|
|
||||||
|
(def drag-down-icon
|
||||||
|
{:width 16
|
||||||
|
:height 16})
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[syng-im.components.chats.chat-list-item :refer [chat-list-item]]
|
[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
|
[syng-im.components.action-button :refer [action-button
|
||||||
action-button-item]]
|
action-button-item]]
|
||||||
[syng-im.components.styles :refer [font
|
[syng-im.components.styles :refer [font
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
[toolbar {:nav-action {:image {:source {:uri "icon_hamburger"}
|
[toolbar {:nav-action {:image {:source {:uri "icon_hamburger"}
|
||||||
:style {:width 16
|
:style {:width 16
|
||||||
:height 12}}
|
:height 12}}
|
||||||
:handler (fn [])}
|
:handler open-drawer}
|
||||||
:title "Chats"
|
:title "Chats"
|
||||||
:action {:image {:source {:uri "icon_search"}
|
:action {:image {:source {:uri "icon_search"}
|
||||||
:style {:width 17
|
:style {:width 17
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
(let [chats @chats
|
(let [chats @chats
|
||||||
_ (log/debug "chats=" chats)
|
_ (log/debug "chats=" chats)
|
||||||
datasource (to-realm-datasource chats)]
|
datasource (to-realm-datasource chats)]
|
||||||
|
[drawer-view {:navigator navigator}
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor "white"}}
|
||||||
[chats-list-toolbar]
|
[chats-list-toolbar]
|
||||||
|
@ -62,8 +64,8 @@
|
||||||
[action-button-item {:title "New Group Chat"
|
[action-button-item {:title "New Group Chat"
|
||||||
:buttonColor "#1abc9c"
|
:buttonColor "#1abc9c"
|
||||||
:onPress (fn []
|
:onPress (fn []
|
||||||
(dispatch [:show-group-new navigator]))}
|
(dispatch [:show-group-new]))}
|
||||||
[icon {:name "person-stalker"
|
[icon {:name "person-stalker"
|
||||||
:style {:fontSize 20
|
:style {:fontSize 20
|
||||||
:height 22
|
:height 22
|
||||||
:color "white"}}]]]]))))
|
:color "white"}}]]]]]))))
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
(ns syng-im.components.contact-list.contact
|
(ns syng-im.components.contact-list.contact
|
||||||
(:require [syng-im.components.react :refer [view text image touchable-highlight]]
|
(: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.resources :as res]
|
||||||
[syng-im.navigation :as nav]
|
|
||||||
[syng-im.components.contact-list.contact-inner :refer [contact-inner-view]]))
|
[syng-im.components.contact-list.contact-inner :refer [contact-inner-view]]))
|
||||||
|
|
||||||
(defn show-chat [navigator whisper-identity]
|
(defn show-chat [navigator whisper-identity]
|
||||||
(nav/nav-push navigator {:view-id :chat}))
|
(dispatch [:show-chat whisper-identity navigator :push]))
|
||||||
|
|
||||||
(defn contact-view [{:keys [navigator contact]}]
|
(defn contact-view [{:keys [navigator contact]}]
|
||||||
(let [{:keys [whisper-identity]} contact]
|
(let [{:keys [whisper-identity]} contact]
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
(fn []
|
(fn []
|
||||||
(let [contacts-ds (get-data-source @contacts)]
|
(let [contacts-ds (get-data-source @contacts)]
|
||||||
[view {:style {:flex 1
|
[view {:style {:flex 1
|
||||||
:backgroundColor "white"}}
|
:backgroundColor color-white}}
|
||||||
[contact-list-toolbar navigator]
|
[contact-list-toolbar navigator]
|
||||||
(when contacts-ds
|
(when contacts-ds
|
||||||
[list-view {:dataSource contacts-ds
|
[list-view {:dataSource contacts-ds
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
(ns syng-im.components.drawer
|
||||||
|
(:require [clojure.string :as s]
|
||||||
|
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[reagent.core :as r]
|
||||||
|
[syng-im.components.react :refer [android?
|
||||||
|
view
|
||||||
|
text
|
||||||
|
image
|
||||||
|
navigator
|
||||||
|
toolbar-android
|
||||||
|
drawer-layout-android
|
||||||
|
touchable-opacity]]
|
||||||
|
[syng-im.resources :as res]
|
||||||
|
[syng-im.components.drawer-styles :as st]))
|
||||||
|
|
||||||
|
(defonce drawer-atom (atom))
|
||||||
|
|
||||||
|
(defn open-drawer []
|
||||||
|
(.openDrawer @drawer-atom))
|
||||||
|
|
||||||
|
(defn close-drawer []
|
||||||
|
(.closeDrawer @drawer-atom))
|
||||||
|
|
||||||
|
(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 menu-item [{:keys [name handler]}]
|
||||||
|
[touchable-opacity {:style st/menu-item-touchable
|
||||||
|
:onPress (fn []
|
||||||
|
(close-drawer)
|
||||||
|
(handler))}
|
||||||
|
[text {:style st/menu-item-text}
|
||||||
|
name]])
|
||||||
|
|
||||||
|
(defn drawer-menu [navigator]
|
||||||
|
[view st/drawer-menu
|
||||||
|
[view st/user-photo-container
|
||||||
|
[user-photo {}]]
|
||||||
|
[view st/name-container
|
||||||
|
[text {:style st/name-text}
|
||||||
|
"Status"]]
|
||||||
|
[view st/menu-items-container
|
||||||
|
[menu-item {:name "Profile"
|
||||||
|
:handler (fn []
|
||||||
|
(dispatch [:show-profile navigator]))}]
|
||||||
|
[menu-item {:name "Settings"
|
||||||
|
:handler (fn []
|
||||||
|
;; TODO not implemented
|
||||||
|
)}]
|
||||||
|
[menu-item {:name "Discovery"
|
||||||
|
:handler (fn []
|
||||||
|
(dispatch [:navigate-to :discovery]))}]
|
||||||
|
[menu-item {:name "Contacts"
|
||||||
|
:handler (fn []
|
||||||
|
(dispatch [:show-contacts navigator]))}]
|
||||||
|
[menu-item {:name "Invite friends"
|
||||||
|
:handler (fn []
|
||||||
|
;; TODO not implemented
|
||||||
|
)}]
|
||||||
|
[menu-item {:name "FAQ"
|
||||||
|
:handler (fn [])}]]
|
||||||
|
[view st/switch-users-container
|
||||||
|
[touchable-opacity {:onPress (fn []
|
||||||
|
(close-drawer)
|
||||||
|
;; TODO not implemented
|
||||||
|
)}
|
||||||
|
[text {:style st/switch-users-text}
|
||||||
|
"Switch users"]]]])
|
||||||
|
|
||||||
|
(defn drawer-view [{:keys [navigator]} items]
|
||||||
|
[drawer-layout-android {:drawerWidth 300
|
||||||
|
:drawerPosition js/React.DrawerLayoutAndroid.positions.Left
|
||||||
|
:render-navigation-view #(r/as-element [drawer-menu navigator])
|
||||||
|
:ref (fn [drawer]
|
||||||
|
(reset! drawer-atom drawer))}
|
||||||
|
items])
|
|
@ -0,0 +1,64 @@
|
||||||
|
(ns syng-im.components.drawer-styles
|
||||||
|
(:require [syng-im.components.styles :refer [font
|
||||||
|
color-light-blue-transparent
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
color-blue-transparent
|
||||||
|
selected-message-color
|
||||||
|
online-color
|
||||||
|
separator-color
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
text3-color]]))
|
||||||
|
|
||||||
|
(def user-photo
|
||||||
|
{:borderRadius 50
|
||||||
|
:width 64
|
||||||
|
:height 64})
|
||||||
|
|
||||||
|
(def menu-item-touchable
|
||||||
|
{:height 48
|
||||||
|
:paddingLeft 16
|
||||||
|
:paddingTop 14})
|
||||||
|
|
||||||
|
(def menu-item-text
|
||||||
|
{:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:lineHeight 21
|
||||||
|
:color text1-color})
|
||||||
|
|
||||||
|
(def drawer-menu
|
||||||
|
{:flex 1
|
||||||
|
:backgroundColor color-white
|
||||||
|
:flexDirection :column})
|
||||||
|
|
||||||
|
(def user-photo-container
|
||||||
|
{:marginTop 40
|
||||||
|
:alignItems :center
|
||||||
|
:justifyContent :center})
|
||||||
|
|
||||||
|
(def name-container
|
||||||
|
{:marginTop 20
|
||||||
|
:alignItems :center})
|
||||||
|
|
||||||
|
(def name-text
|
||||||
|
{:marginTop -2.5
|
||||||
|
:color text1-color
|
||||||
|
:fontSize 16})
|
||||||
|
|
||||||
|
(def menu-items-container
|
||||||
|
{:flex 1
|
||||||
|
:marginTop 80
|
||||||
|
:alignItems :stretch
|
||||||
|
:flexDirection :column})
|
||||||
|
|
||||||
|
(def switch-users-container
|
||||||
|
{:paddingVertical 36
|
||||||
|
:alignItems :center})
|
||||||
|
|
||||||
|
(def switch-users-text
|
||||||
|
{:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:lineHeight 21
|
||||||
|
:color text3-color})
|
|
@ -0,0 +1,76 @@
|
||||||
|
(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/profile-back-button-touchable
|
||||||
|
:on-press #(dispatch [:navigate-back])}
|
||||||
|
[view st/profile-back-button-container
|
||||||
|
[icon :back st/profile-back-button-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"]]]]])))
|
|
@ -0,0 +1,154 @@
|
||||||
|
(ns syng-im.components.profile-styles
|
||||||
|
(:require [syng-im.components.styles :refer [font
|
||||||
|
color-light-blue-transparent
|
||||||
|
color-white
|
||||||
|
color-black
|
||||||
|
color-blue
|
||||||
|
color-blue-transparent
|
||||||
|
selected-message-color
|
||||||
|
online-color
|
||||||
|
separator-color
|
||||||
|
text1-color
|
||||||
|
text2-color]]))
|
||||||
|
|
||||||
|
(def user-photo
|
||||||
|
{:borderRadius 50
|
||||||
|
:width 64
|
||||||
|
:height 64})
|
||||||
|
|
||||||
|
(def user-online-container
|
||||||
|
{:position :absolute
|
||||||
|
:top 44
|
||||||
|
:left 44
|
||||||
|
:width 24
|
||||||
|
:height 24
|
||||||
|
:borderRadius 50
|
||||||
|
:backgroundColor online-color
|
||||||
|
:borderWidth 2
|
||||||
|
:borderColor color-white})
|
||||||
|
|
||||||
|
(def user-online-dot
|
||||||
|
{:position :absolute
|
||||||
|
:top 8
|
||||||
|
:left 5
|
||||||
|
:width 4
|
||||||
|
:height 4
|
||||||
|
:borderRadius 50
|
||||||
|
:backgroundColor color-white})
|
||||||
|
|
||||||
|
(def user-online-dot-left
|
||||||
|
(assoc user-online-dot :left 5))
|
||||||
|
|
||||||
|
(def user-online-dot-right
|
||||||
|
(assoc user-online-dot :left 11))
|
||||||
|
|
||||||
|
(def profile-property-view-container
|
||||||
|
{:height 85
|
||||||
|
:paddingHorizontal 16})
|
||||||
|
|
||||||
|
(def profile-property-view-sub-container
|
||||||
|
{:borderBottomWidth 1
|
||||||
|
:borderBottomColor separator-color})
|
||||||
|
|
||||||
|
(def profile-property-view-label
|
||||||
|
{:marginTop 16
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:color text2-color})
|
||||||
|
|
||||||
|
(def profile-property-view-value
|
||||||
|
{:marginTop 11
|
||||||
|
:height 40
|
||||||
|
:fontSize 16
|
||||||
|
:fontFamily font
|
||||||
|
:color text1-color})
|
||||||
|
|
||||||
|
(def profile
|
||||||
|
{:flex 1
|
||||||
|
:backgroundColor color-white
|
||||||
|
:flexDirection :column})
|
||||||
|
|
||||||
|
(def profile-back-button-touchable
|
||||||
|
{:position :absolute})
|
||||||
|
|
||||||
|
(def profile-back-button-container
|
||||||
|
{:width 56
|
||||||
|
:height 56})
|
||||||
|
|
||||||
|
(def profile-back-button-icon
|
||||||
|
{:marginTop 21
|
||||||
|
:marginLeft 23
|
||||||
|
:width 8
|
||||||
|
:height 14})
|
||||||
|
|
||||||
|
(def status-block
|
||||||
|
{:alignSelf :center
|
||||||
|
:alignItems :center
|
||||||
|
:width 249})
|
||||||
|
|
||||||
|
(def user-photo-container
|
||||||
|
{:marginTop 26})
|
||||||
|
|
||||||
|
(def user-name
|
||||||
|
{:marginTop 20
|
||||||
|
:fontSize 18
|
||||||
|
:fontFamily font
|
||||||
|
:color text1-color})
|
||||||
|
|
||||||
|
(def status
|
||||||
|
{:marginTop 10
|
||||||
|
:fontFamily font
|
||||||
|
:fontSize 14
|
||||||
|
:lineHeight 20
|
||||||
|
:textAlign :center
|
||||||
|
:color text2-color})
|
||||||
|
|
||||||
|
(def btns-container
|
||||||
|
{:marginTop 18
|
||||||
|
:flexDirection :row})
|
||||||
|
|
||||||
|
(def message-btn
|
||||||
|
{:height 40
|
||||||
|
:justifyContent :center
|
||||||
|
:backgroundColor color-blue
|
||||||
|
:paddingLeft 25
|
||||||
|
:paddingRight 25
|
||||||
|
:borderRadius 50})
|
||||||
|
|
||||||
|
(def message-btn-text
|
||||||
|
{:marginTop -2.5
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:color color-white})
|
||||||
|
|
||||||
|
(def more-btn
|
||||||
|
{:marginLeft 10
|
||||||
|
:width 40
|
||||||
|
:height 40
|
||||||
|
:alignItems :center
|
||||||
|
:justifyContent :center
|
||||||
|
:backgroundColor color-blue-transparent
|
||||||
|
:padding 8
|
||||||
|
:borderRadius 50})
|
||||||
|
|
||||||
|
(def more-btn-image
|
||||||
|
{:width 4
|
||||||
|
:height 16})
|
||||||
|
|
||||||
|
(def profile-properties-container
|
||||||
|
{:marginTop 20
|
||||||
|
:alignItems :stretch
|
||||||
|
:flexDirection :column})
|
||||||
|
|
||||||
|
(def report-user-container
|
||||||
|
{:marginTop 50
|
||||||
|
:marginBottom 43
|
||||||
|
:alignItems :center})
|
||||||
|
|
||||||
|
(def report-user-text
|
||||||
|
{:fontSize 14
|
||||||
|
:fontFamily font
|
||||||
|
:lineHeight 21
|
||||||
|
:color text2-color
|
||||||
|
;; IOS:
|
||||||
|
:letterSpacing 0.5})
|
|
@ -26,6 +26,8 @@
|
||||||
:placeholder "Type"}
|
:placeholder "Type"}
|
||||||
props)
|
props)
|
||||||
text])
|
text])
|
||||||
|
(def drawer-layout-android (r/adapt-react-class (.-DrawerLayoutAndroid js/React)))
|
||||||
|
(def touchable-opacity (r/adapt-react-class (.-TouchableOpacity js/React)))
|
||||||
|
|
||||||
|
|
||||||
(defn icon [n style]
|
(defn icon [n style]
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
(def title-font "sans-serif-medium")
|
(def title-font "sans-serif-medium")
|
||||||
|
|
||||||
(def color-blue "#7099e6")
|
(def color-blue "#7099e6")
|
||||||
|
(def color-blue-transparent "#7099e632")
|
||||||
(def color-black "#000000de")
|
(def color-black "#000000de")
|
||||||
(def color-purple "#a187d5")
|
(def color-purple "#a187d5")
|
||||||
(def color-gray "#838c93de")
|
(def color-gray "#838c93de")
|
||||||
|
@ -16,8 +17,9 @@
|
||||||
|
|
||||||
(def text1-color color-black)
|
(def text1-color color-black)
|
||||||
(def text2-color color-gray)
|
(def text2-color color-gray)
|
||||||
|
(def text3-color color-blue)
|
||||||
(def online-color color-blue)
|
(def online-color color-blue)
|
||||||
(def new-messages-count-color "#7099e632")
|
(def new-messages-count-color color-blue-transparent)
|
||||||
(def chat-background color-light-gray)
|
(def chat-background color-light-gray)
|
||||||
(def selected-message-color "#E4E9ED")
|
(def selected-message-color "#E4E9ED")
|
||||||
(def separator-color "#0000001f")
|
(def separator-color "#0000001f")
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
toolbar-background1]]
|
toolbar-background1]]
|
||||||
[syng-im.components.realm :refer [list-view]]
|
[syng-im.components.realm :refer [list-view]]
|
||||||
[syng-im.utils.listview :refer [to-realm-datasource]]
|
[syng-im.utils.listview :refer [to-realm-datasource]]
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]))
|
||||||
[syng-im.navigation :refer [nav-pop]]))
|
|
||||||
|
|
||||||
(defn toolbar [{:keys [navigator title nav-action action background-color content style]}]
|
(defn toolbar [{:keys [navigator title nav-action action background-color content style]}]
|
||||||
(let [style (merge {:flexDirection "row"
|
(let [style (merge {:flexDirection "row"
|
||||||
|
@ -31,7 +30,7 @@
|
||||||
:alignItems "center"
|
:alignItems "center"
|
||||||
:justifyContent "center"}
|
:justifyContent "center"}
|
||||||
[image (:image nav-action)]]]
|
[image (:image nav-action)]]]
|
||||||
[touchable-highlight {:on-press #(nav-pop navigator)}
|
[touchable-highlight {:on-press #(dispatch [:navigate-back])}
|
||||||
[view {:width 56
|
[view {:width 56
|
||||||
:height 56}
|
:height 56}
|
||||||
[image {:source {:uri "icon_back"}
|
[image {:source {:uri "icon_back"}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
;; schema of app-db
|
;; schema of app-db
|
||||||
(def schema {:greeting s/Str})
|
(def schema {:greeting s/Str})
|
||||||
|
|
||||||
(def default-view :discovery)
|
(def default-view :chat-list)
|
||||||
|
|
||||||
;; initial state of app-db
|
;; initial state of app-db
|
||||||
(def app-db {:greeting "Hello Clojure in iOS and Android!"
|
(def app-db {:greeting "Hello Clojure in iOS and Android!"
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
(def protocol-initialized-path [:protocol-initialized])
|
(def protocol-initialized-path [:protocol-initialized])
|
||||||
(def identity-password-path [:identity-password])
|
(def identity-password-path [:identity-password])
|
||||||
|
(def contact-identity-path [:contact-identity])
|
||||||
(def current-chat-id-path [:current-chat-id])
|
(def current-chat-id-path [:current-chat-id])
|
||||||
(def updated-chats-signal-path [:chats-updated-signal])
|
(def updated-chats-signal-path [:chats-updated-signal])
|
||||||
(defn updated-chat-signal-path [chat-id]
|
(defn updated-chat-signal-path [chat-id]
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
(:require
|
(:require
|
||||||
[re-frame.core :refer [register-handler after dispatch debug enrich]]
|
[re-frame.core :refer [register-handler after dispatch debug enrich]]
|
||||||
[schema.core :as s :include-macros true]
|
[schema.core :as s :include-macros true]
|
||||||
|
[syng-im.persistence.simple-kv-store :as kv]
|
||||||
|
[syng-im.protocol.state.storage :as storage]
|
||||||
[syng-im.db :as db :refer [app-db schema]]
|
[syng-im.db :as db :refer [app-db schema]]
|
||||||
[syng-im.protocol.api :refer [init-protocol]]
|
[syng-im.protocol.api :refer [init-protocol]]
|
||||||
[syng-im.protocol.protocol-handler :refer [make-handler]]
|
[syng-im.protocol.protocol-handler :refer [make-handler]]
|
||||||
|
@ -27,7 +29,8 @@
|
||||||
get-command-handler
|
get-command-handler
|
||||||
load-commands
|
load-commands
|
||||||
apply-staged-commands
|
apply-staged-commands
|
||||||
check-suggestion]]
|
check-suggestion
|
||||||
|
switch-command-suggestions]]
|
||||||
[syng-im.handlers.sign-up :as sign-up-service]
|
[syng-im.handlers.sign-up :as sign-up-service]
|
||||||
[syng-im.components.discovery.handlers :as discovery]
|
[syng-im.components.discovery.handlers :as discovery]
|
||||||
[syng-im.models.chats :refer [chat-exists?
|
[syng-im.models.chats :refer [chat-exists?
|
||||||
|
@ -76,7 +79,9 @@
|
||||||
;; -- Common --------------------------------------------------------------
|
;; -- Common --------------------------------------------------------------
|
||||||
|
|
||||||
(register-handler :initialize-db
|
(register-handler :initialize-db
|
||||||
(fn [_ _] app-db))
|
(fn [_ _]
|
||||||
|
(assoc app-db
|
||||||
|
:signed-up (storage/get kv/kv-store :signed-up))))
|
||||||
|
|
||||||
(register-handler :set-loading
|
(register-handler :set-loading
|
||||||
(fn [db [_ value]]
|
(fn [db [_ value]]
|
||||||
|
@ -445,13 +450,23 @@
|
||||||
(fn [db [_ value]]
|
(fn [db [_ value]]
|
||||||
(contacts/load-syng-contacts db)))
|
(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)))
|
||||||
|
|
||||||
;; -- Chats --------------------------------------------------------------
|
;; -- Chats --------------------------------------------------------------
|
||||||
|
|
||||||
(register-handler :show-chat
|
(register-handler :show-chat
|
||||||
(fn [db [action chat-id navigator nav-type]]
|
(fn [db [action chat-id navigator nav-type]]
|
||||||
(log/debug action "chat-id" chat-id)
|
(log/debug action "chat-id" chat-id)
|
||||||
(let [db (set-current-chat-id db chat-id)]
|
(let [db (-> db
|
||||||
(dispatch [:navigate-to navigator {:view-id :chat} nav-type])
|
(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)))
|
db)))
|
||||||
|
|
||||||
(register-handler :init-console-chat
|
(register-handler :init-console-chat
|
||||||
|
@ -474,6 +489,10 @@
|
||||||
(register-handler :set-chat-input-text
|
(register-handler :set-chat-input-text
|
||||||
((enrich update-command) update-text))
|
((enrich update-command) update-text))
|
||||||
|
|
||||||
|
(register-handler :switch-command-suggestions
|
||||||
|
(fn [db [_]]
|
||||||
|
(switch-command-suggestions db)))
|
||||||
|
|
||||||
(register-handler :set-chat-command
|
(register-handler :set-chat-command
|
||||||
(fn [db [_ command-key]]
|
(fn [db [_ command-key]]
|
||||||
;; todo what is going on there?!
|
;; todo what is going on there?!
|
||||||
|
@ -552,9 +571,9 @@
|
||||||
db)))
|
db)))
|
||||||
|
|
||||||
(register-handler :show-group-new
|
(register-handler :show-group-new
|
||||||
(fn [db [action navigator]]
|
(fn [db [action]]
|
||||||
(log/debug action)
|
(log/debug action)
|
||||||
(nav-push navigator {:view-id :new-group})
|
(dispatch [:navigate-to :new-group])
|
||||||
(clear-new-group db)))
|
(clear-new-group db)))
|
||||||
|
|
||||||
(register-handler :select-for-new-group
|
(register-handler :select-for-new-group
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
(ns syng-im.handlers.content-suggestions
|
||||||
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.db :as db]
|
||||||
|
[syng-im.utils.logging :as log]
|
||||||
|
[clojure.string :as s]))
|
||||||
|
|
||||||
|
(def suggestions
|
||||||
|
{:phone [{:value "89171111111"
|
||||||
|
:description "Number format 1"}
|
||||||
|
{:value "+79171111111"
|
||||||
|
:description "Number format 2"}
|
||||||
|
{:value "9171111111"
|
||||||
|
:description "Number format 3"}]})
|
||||||
|
|
||||||
|
(defn get-content-suggestions [db command text]
|
||||||
|
(or (when command
|
||||||
|
(when-let [command-suggestions ((:command command) suggestions)]
|
||||||
|
(filterv (fn [s]
|
||||||
|
(and (.startsWith (:value s) (or text ""))
|
||||||
|
(not= (:value s) text)))
|
||||||
|
command-suggestions)))
|
||||||
|
[]))
|
|
@ -1,7 +1,9 @@
|
||||||
(ns syng-im.handlers.suggestions
|
(ns syng-im.handlers.suggestions
|
||||||
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
(:require [re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
[syng-im.db :as db]
|
[syng-im.db :as db]
|
||||||
[syng-im.models.chat :refer [current-chat-id]]
|
[syng-im.models.chat :refer [current-chat-id
|
||||||
|
set-chat-input-text
|
||||||
|
get-chat-input-text]]
|
||||||
[syng-im.models.commands :refer [commands
|
[syng-im.models.commands :refer [commands
|
||||||
suggestions
|
suggestions
|
||||||
get-commands
|
get-commands
|
||||||
|
@ -62,3 +64,10 @@
|
||||||
[suggestion] (filter #(= suggestion-text' (:text %))
|
[suggestion] (filter #(= suggestion-text' (:text %))
|
||||||
(get-commands db))]
|
(get-commands db))]
|
||||||
suggestion)))
|
suggestion)))
|
||||||
|
|
||||||
|
(defn typing-command? [db]
|
||||||
|
(let [text (get-chat-input-text db)]
|
||||||
|
(suggestion? text)))
|
||||||
|
|
||||||
|
(defn switch-command-suggestions [db]
|
||||||
|
(set-chat-input-text db (if (typing-command? db) nil "!")))
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
(defn set-chat-input-text [db text]
|
(defn set-chat-input-text [db text]
|
||||||
(assoc-in db (db/chat-input-text-path (current-chat-id 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
|
(comment
|
||||||
|
|
||||||
(swap! re-frame.db/app-db (fn [db]
|
(swap! re-frame.db/app-db (fn [db]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns syng-im.models.contacts
|
(ns syng-im.models.contacts
|
||||||
(:require [cljs.core.async :as async :refer [chan put! <! >!]]
|
(:require [cljs.core.async :as async :refer [chan put! <! >!]]
|
||||||
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
|
||||||
|
[syng-im.db :as db]
|
||||||
[syng-im.utils.utils :refer [log toast]]
|
[syng-im.utils.utils :refer [log toast]]
|
||||||
[syng-im.persistence.realm :as realm]
|
[syng-im.persistence.realm :as realm]
|
||||||
[syng-im.persistence.realm :as r]
|
[syng-im.persistence.realm :as r]
|
||||||
|
@ -106,7 +107,20 @@
|
||||||
(r/sorted :name :asc))))
|
(r/sorted :name :asc))))
|
||||||
|
|
||||||
(defn contact-by-identity [identity]
|
(defn contact-by-identity [identity]
|
||||||
(r/single-cljs (r/get-by-field :contacts :whisper-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
|
(comment
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,17 @@
|
||||||
[syng-im.models.messages :refer [get-messages]]
|
[syng-im.models.messages :refer [get-messages]]
|
||||||
[syng-im.models.contacts :refer [contacts-list
|
[syng-im.models.contacts :refer [contacts-list
|
||||||
contacts-list-exclude
|
contacts-list-exclude
|
||||||
contacts-list-include]]
|
contacts-list-include
|
||||||
|
contact-identity
|
||||||
|
contact-by-identity]]
|
||||||
[syng-im.models.commands :refer [get-commands
|
[syng-im.models.commands :refer [get-commands
|
||||||
get-chat-command
|
get-chat-command
|
||||||
get-chat-command-content
|
get-chat-command-content
|
||||||
get-chat-command-request
|
get-chat-command-request
|
||||||
parse-command-request]]
|
parse-command-request]]
|
||||||
[syng-im.handlers.suggestions :refer [get-suggestions]]))
|
[syng-im.handlers.suggestions :refer [get-suggestions
|
||||||
|
typing-command?]]
|
||||||
|
[syng-im.handlers.content-suggestions :refer [get-content-suggestions]]))
|
||||||
|
|
||||||
;; -- Chat --------------------------------------------------------------
|
;; -- Chat --------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -38,6 +42,16 @@
|
||||||
(reaction))]
|
(reaction))]
|
||||||
(reaction (get-suggestions @db @input-text)))))
|
(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
|
(register-sub :get-commands
|
||||||
(fn [db _]
|
(fn [db _]
|
||||||
(reaction (get-commands @db))))
|
(reaction (get-commands @db))))
|
||||||
|
@ -120,6 +134,11 @@
|
||||||
(reaction
|
(reaction
|
||||||
(contacts-list))))
|
(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
|
(register-sub :all-new-contacts
|
||||||
(fn [db _]
|
(fn [db _]
|
||||||
(let [current-chat-id (reaction (current-chat-id @db))
|
(let [current-chat-id (reaction (current-chat-id @db))
|
||||||
|
|
|
@ -7,3 +7,9 @@
|
||||||
|
|
||||||
(defn format-phone-number [number]
|
(defn format-phone-number [number]
|
||||||
(str (.getNumber (js/PhoneNumber. number country-code "international"))))
|
(str (.getNumber (js/PhoneNumber. number country-code "international"))))
|
||||||
|
|
||||||
|
(defn valid-mobile-number? [number]
|
||||||
|
(when (string? number)
|
||||||
|
(let [number-obj (js/PhoneNumber. number country-code "international")]
|
||||||
|
(and (.isValid number-obj)
|
||||||
|
(.isMobile number-obj)))))
|
||||||
|
|