Merge pull request #58 from status-im/feature-discover
Feature discover
Former-commit-id: bda5ce32ab
This commit is contained in:
commit
3c7c91b745
|
@ -4,6 +4,7 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 82 B |
Binary file not shown.
After Width: | Height: | Size: 249 B |
|
@ -8,9 +8,9 @@
|
||||||
[reagent "0.5.1" :exclusions [cljsjs/react]]
|
[reagent "0.5.1" :exclusions [cljsjs/react]]
|
||||||
[re-frame "0.6.0"]
|
[re-frame "0.6.0"]
|
||||||
[prismatic/schema "1.0.4"]
|
[prismatic/schema "1.0.4"]
|
||||||
^{:voom {:repo "git@github.com:status-im/status-lib.git"
|
^{:voom {:repo "https://github.com/status-im/status-lib.git"
|
||||||
:branch "master"}}
|
:branch "feature-discover"}}
|
||||||
[syng-im/protocol "0.1.1-20160430_080316-gf359cb7"]
|
[syng-im/protocol "0.1.1-20160506_171115-ge2c95c1"]
|
||||||
[natal-shell "0.1.6"]]
|
[natal-shell "0.1.6"]]
|
||||||
:plugins [[lein-cljsbuild "1.1.1"]
|
:plugins [[lein-cljsbuild "1.1.1"]
|
||||||
[lein-figwheel "0.5.0-2"]]
|
[lein-figwheel "0.5.0-2"]]
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
[syng-im.subs]
|
[syng-im.subs]
|
||||||
[syng-im.components.react :refer [navigator app-registry]]
|
[syng-im.components.react :refer [navigator app-registry]]
|
||||||
[syng-im.components.contact-list.contact-list :refer [contact-list]]
|
[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.chat :refer [chat]]
|
||||||
[syng-im.components.chats.chats-list :refer [chats-list]]
|
[syng-im.components.chats.chats-list :refer [chats-list]]
|
||||||
[syng-im.components.chats.new-group :refer [new-group]]
|
[syng-im.components.chats.new-group :refer [new-group]]
|
||||||
|
@ -37,6 +39,8 @@
|
||||||
view-id (subscribe [:view-id])]
|
view-id (subscribe [:view-id])]
|
||||||
(fn []
|
(fn []
|
||||||
(case (if @signed-up @view-id :chat)
|
(case (if @signed-up @view-id :chat)
|
||||||
|
:discovery [discovery]
|
||||||
|
:discovery-tag [discovery-tag]
|
||||||
:add-participants [new-participants]
|
:add-participants [new-participants]
|
||||||
:remove-participants [remove-participants]
|
:remove-participants [remove-participants]
|
||||||
:chat-list [chats-list]
|
:chat-list [chats-list]
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
(ns syng-im.components.carousel
|
||||||
|
(:require [syng-im.components.react :refer [android?
|
||||||
|
view
|
||||||
|
scroll-view
|
||||||
|
touchable-without-feedback
|
||||||
|
text]]
|
||||||
|
[syng-im.components.carousel.styles :as st]
|
||||||
|
[syng-im.utils.logging :as log]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn window-page-width []
|
||||||
|
(.-width (.get (.. js/React -Dimensions) "window")))
|
||||||
|
|
||||||
|
(def defaults {:gap 10
|
||||||
|
:sneak 10
|
||||||
|
:pageStyle {}
|
||||||
|
:scrollThreshold 20})
|
||||||
|
|
||||||
|
(defn get-active-page [data]
|
||||||
|
(get data :activePage 0))
|
||||||
|
|
||||||
|
(defn get-sneak [data]
|
||||||
|
(get data :sneak (:sneak defaults)))
|
||||||
|
|
||||||
|
(defn get-gap [data]
|
||||||
|
(get data :gap (:gap defaults)))
|
||||||
|
|
||||||
|
(defn compute-page-width
|
||||||
|
([gap sneak]
|
||||||
|
(compute-page-width (window-page-width) gap sneak))
|
||||||
|
([window-page-width gap sneak]
|
||||||
|
(- window-page-width (+ (* 2 gap) (* 2 sneak)))))
|
||||||
|
|
||||||
|
(defn get-page-width [data]
|
||||||
|
(get data :pageWidth (compute-page-width (get-gap data) (get-sneak data))))
|
||||||
|
|
||||||
|
(defn get-page-style [data]
|
||||||
|
(let [data-style (get data :pageStyle {})]
|
||||||
|
(merge (:pageStyle defaults) data-style)))
|
||||||
|
|
||||||
|
(defn get-scroll-threshold [data]
|
||||||
|
(get data :scrollThreshold (:scrollThreshold defaults)))
|
||||||
|
|
||||||
|
(defn apply-props [component props]
|
||||||
|
(let [sneak (get-sneak props)
|
||||||
|
page-width (get-page-width props)
|
||||||
|
style (get-page-style props)
|
||||||
|
gap (quot (- (- (window-page-width) (* 2 sneak)) page-width) 2)]
|
||||||
|
(reagent.core/set-state component {:sneak sneak
|
||||||
|
:pageWidth page-width
|
||||||
|
:pageStyle style
|
||||||
|
:gap gap})))
|
||||||
|
|
||||||
|
(defn scroll-to [component x y]
|
||||||
|
(.scrollTo (.-scrollView component) (clj->js {:y y
|
||||||
|
:x x})))
|
||||||
|
|
||||||
|
(defn get-current-position [event]
|
||||||
|
(.-x (.-contentOffset (.-nativeEvent event))))
|
||||||
|
|
||||||
|
(defn go-to-page [component page]
|
||||||
|
(let [props (reagent.core/props component)
|
||||||
|
state (reagent.core/state component)
|
||||||
|
page-width (get-page-width state)
|
||||||
|
gap (get-gap state)
|
||||||
|
page-position (* page (+ page-width gap))]
|
||||||
|
(log/debug "go-to-page: props-page-width=" page-width "; gap=" gap
|
||||||
|
"; page-position=" page-position)
|
||||||
|
(scroll-to component page-position 0)
|
||||||
|
(reagent.core/set-state component {:activePage page})
|
||||||
|
(when (:onPageChange props)
|
||||||
|
((:onPageChange props) page))))
|
||||||
|
|
||||||
|
(defn on-scroll-end [event component starting-position]
|
||||||
|
(let [props (reagent.core/props component)
|
||||||
|
state (reagent.core/state component)
|
||||||
|
scroll-threshold (get-scroll-threshold props)
|
||||||
|
current-page (get-active-page state)
|
||||||
|
current-position (get-current-position event)
|
||||||
|
direction (cond
|
||||||
|
(> current-position (+ starting-position scroll-threshold)) 1
|
||||||
|
(< current-position (- starting-position scroll-threshold)) -1
|
||||||
|
:else 0)
|
||||||
|
new-page (+ current-page direction)
|
||||||
|
]
|
||||||
|
(log/debug state "on-scroll-end: starting position=" starting-position
|
||||||
|
"; current-position=" current-position "; direction=" direction
|
||||||
|
"; current-page=" current-page "; new-page=" new-page)
|
||||||
|
(if (not= current-page new-page)
|
||||||
|
(go-to-page component new-page)
|
||||||
|
(scroll-to component starting-position 0))))
|
||||||
|
|
||||||
|
(defn component-will-mount [component new-args]
|
||||||
|
(let [props (reagent.core/props component)]
|
||||||
|
(log/debug "component-will-mount: new-args="new-args)
|
||||||
|
(apply-props component props)))
|
||||||
|
|
||||||
|
(defn component-did-mount [component]
|
||||||
|
(let [props (reagent.core/props component)
|
||||||
|
initial-page (.-initialPage props)]
|
||||||
|
(log/debug "component-did-mount: initial-page="initial-page)
|
||||||
|
(when (pos? initial-page)
|
||||||
|
(go-to-page component initial-page))))
|
||||||
|
|
||||||
|
(defn component-will-update [component new-argv]
|
||||||
|
(log/debug "component-will-update: "))
|
||||||
|
|
||||||
|
(defn component-did-update [component old-argv]
|
||||||
|
(log/debug "component-did-update"))
|
||||||
|
|
||||||
|
(defn component-will-receive-props [component new-argv]
|
||||||
|
(log/debug "component-will-receive-props: new-argv=" new-argv)
|
||||||
|
(apply-props component new-argv))
|
||||||
|
|
||||||
|
(defn get-event-width [event]
|
||||||
|
(.-width (.-layout (.-nativeEvent event))))
|
||||||
|
|
||||||
|
(defn on-layout-change [event component]
|
||||||
|
(let [state (reagent.core/state component)
|
||||||
|
page-width (compute-page-width (get-event-width event) (get-gap state) (get-sneak state))
|
||||||
|
state-page-width (get-page-width state)
|
||||||
|
active-page (get-active-page state)
|
||||||
|
gap (get-gap state)
|
||||||
|
page-position (* active-page (+ page-width gap))]
|
||||||
|
(log/debug "Layout changed: " " page-width=" page-width "; state-page-width=" state-page-width)
|
||||||
|
(if (not= page-width state-page-width)
|
||||||
|
(do
|
||||||
|
(reagent.core/set-state component {:pageWidth page-width})
|
||||||
|
(.setState component {:layout (.-layout (.-nativeEvent event))})
|
||||||
|
)
|
||||||
|
(scroll-to component page-position 0))))
|
||||||
|
|
||||||
|
(defn get-pages [component data children]
|
||||||
|
(let [page-width (get-page-width data)
|
||||||
|
page-style (get-page-style data)
|
||||||
|
gap (get-gap data)
|
||||||
|
margin (quot gap 2)]
|
||||||
|
(doall (map-indexed (fn [index child]
|
||||||
|
(let [page-index index
|
||||||
|
touchable-data {:key index
|
||||||
|
:onPress #(go-to-page component page-index)}]
|
||||||
|
[touchable-without-feedback touchable-data
|
||||||
|
[view {:style [(st/page page-width margin)
|
||||||
|
page-style]
|
||||||
|
:onLayout #(log/debug "view onLayout" %)}
|
||||||
|
|
||||||
|
child]])) children))))
|
||||||
|
|
||||||
|
(defn reagent-render [data children]
|
||||||
|
(let [starting-position (atom 0)
|
||||||
|
component (reagent.core/current-component)
|
||||||
|
state (reagent.core/state component)
|
||||||
|
sneak (get-sneak state)
|
||||||
|
gap (get-gap state)]
|
||||||
|
(log/debug "reagent-render: " data state)
|
||||||
|
[view {:style st/scroll-view-container}
|
||||||
|
[scroll-view {:contentContainerStyle (st/content-container sneak gap)
|
||||||
|
:automaticallyAdjustContentInsets false
|
||||||
|
:bounces false
|
||||||
|
:decelerationRate 0.9
|
||||||
|
:horizontal true
|
||||||
|
:onLayout #(on-layout-change % component)
|
||||||
|
:onScrollBeginDrag #(reset! starting-position (get-current-position %))
|
||||||
|
:onScrollEndDrag #(on-scroll-end % component @starting-position)
|
||||||
|
:showsHorizontalScrollIndicator false
|
||||||
|
:ref #(set! (.-scrollView component) %)}
|
||||||
|
(get-pages component state children)]]))
|
||||||
|
|
||||||
|
(defn carousel [data children]
|
||||||
|
(let [component-data {:component-did-mount component-did-mount
|
||||||
|
:component-will-mount component-will-mount
|
||||||
|
:component-will-receive-props component-will-receive-props
|
||||||
|
:component-will-update component-will-update
|
||||||
|
:component-did-update component-did-update
|
||||||
|
:display-name "carousel"
|
||||||
|
:reagent-render reagent-render}]
|
||||||
|
(log/debug "Creating carousel component: " data)
|
||||||
|
(reagent.core/create-class component-data)))
|
|
@ -0,0 +1,24 @@
|
||||||
|
(ns syng-im.components.carousel.styles
|
||||||
|
(:require [syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
chat-background
|
||||||
|
online-color
|
||||||
|
selected-message-color
|
||||||
|
separator-color
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
toolbar-background1]]))
|
||||||
|
|
||||||
|
(def scroll-view-container
|
||||||
|
{:flex 1})
|
||||||
|
|
||||||
|
(defn content-container [sneak gap]
|
||||||
|
{:paddingLeft (+ sneak (quot gap 2))
|
||||||
|
:paddingRight (+ sneak (quot gap 2))})
|
||||||
|
|
||||||
|
(defn page [page-width margin]
|
||||||
|
{:width page-width
|
||||||
|
:justifyContent "center"
|
||||||
|
:marginLeft margin
|
||||||
|
:marginRight margin})
|
|
@ -177,6 +177,7 @@
|
||||||
[list-view {:renderRow (message-row contacts' group-chat)
|
[list-view {:renderRow (message-row contacts' group-chat)
|
||||||
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
:renderScrollComponent #(invertible-scroll-view (js->clj %))
|
||||||
:onEndReached #(dispatch [:load-more-messages])
|
:onEndReached #(dispatch [:load-more-messages])
|
||||||
|
:enableEmptySections true
|
||||||
:dataSource (to-datasource2 @messages)}]))))
|
:dataSource (to-datasource2 @messages)}]))))
|
||||||
|
|
||||||
(defn chat []
|
(defn chat []
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
(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.resources :as res]
|
||||||
|
[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]
|
||||||
|
(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"
|
||||||
|
: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"))
|
||||||
|
)
|
|
@ -0,0 +1,23 @@
|
||||||
|
(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"])))
|
|
@ -0,0 +1,44 @@
|
||||||
|
(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}]]))
|
|
@ -0,0 +1,24 @@
|
||||||
|
(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.resources :as res]
|
||||||
|
[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 res/user-no-photo}]
|
||||||
|
]
|
||||||
|
]))
|
|
@ -0,0 +1,35 @@
|
||||||
|
(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}]
|
||||||
|
))
|
|
@ -0,0 +1,60 @@
|
||||||
|
(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.resources :as res]
|
||||||
|
[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}]
|
||||||
|
]))))
|
|
@ -0,0 +1,44 @@
|
||||||
|
(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)))
|
|
@ -0,0 +1,175 @@
|
||||||
|
(ns syng-im.components.discovery.styles
|
||||||
|
(:require [syng-im.components.styles :refer [font
|
||||||
|
title-font
|
||||||
|
color-white
|
||||||
|
chat-background
|
||||||
|
online-color
|
||||||
|
selected-message-color
|
||||||
|
separator-color
|
||||||
|
text1-color
|
||||||
|
text2-color
|
||||||
|
toolbar-background1]]))
|
||||||
|
|
||||||
|
;; common
|
||||||
|
|
||||||
|
(def row-separator
|
||||||
|
{:borderBottomWidth 1
|
||||||
|
:borderBottomColor "#eff2f3"})
|
||||||
|
|
||||||
|
(def row
|
||||||
|
{:flexDirection "row"})
|
||||||
|
|
||||||
|
(def column
|
||||||
|
{:flexDirection "column"})
|
||||||
|
|
||||||
|
;; discovery.cljs
|
||||||
|
|
||||||
|
(def discovery-search-input
|
||||||
|
{:flex 1
|
||||||
|
:marginLeft 18
|
||||||
|
:lineHeight 42
|
||||||
|
:fontSize 14
|
||||||
|
:fontFamily "Avenir-Roman"
|
||||||
|
:color "#9CBFC0"})
|
||||||
|
|
||||||
|
(def discovery-title
|
||||||
|
{:color "#000000de"
|
||||||
|
:alignSelf "center"
|
||||||
|
:textAlign "center"
|
||||||
|
:fontFamily "sans-serif"
|
||||||
|
:fontSize 16})
|
||||||
|
|
||||||
|
(def discovery-toolbar
|
||||||
|
{:backgroundColor "#eef2f5"
|
||||||
|
:elevation 0})
|
||||||
|
|
||||||
|
(def discovery-subtitle
|
||||||
|
{:color "#8f838c93"
|
||||||
|
:fontFamily "sans-serif-medium"
|
||||||
|
:fontSize 14})
|
||||||
|
|
||||||
|
(def section-spacing
|
||||||
|
{:paddingLeft 30
|
||||||
|
:paddingTop 15
|
||||||
|
:paddingBottom 15})
|
||||||
|
|
||||||
|
;; discovery_popular.cljs
|
||||||
|
|
||||||
|
(def carousel-page-style
|
||||||
|
{:borderRadius 1
|
||||||
|
:shadowColor "black"
|
||||||
|
:shadowRadius 1
|
||||||
|
:shadowOpacity 0.8
|
||||||
|
:elevation 2
|
||||||
|
:marginBottom 10})
|
||||||
|
|
||||||
|
;; discovery_populat_list.cljs
|
||||||
|
|
||||||
|
(def tag-name
|
||||||
|
{:color "#7099e6"
|
||||||
|
:fontFamily "sans-serif-medium"
|
||||||
|
:fontSize 14
|
||||||
|
:paddingRight 5
|
||||||
|
:paddingBottom 2
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"})
|
||||||
|
|
||||||
|
(def tag-name-container
|
||||||
|
{:flexDirection "column"
|
||||||
|
:backgroundColor "#eef2f5"
|
||||||
|
:borderRadius 5
|
||||||
|
:padding 4})
|
||||||
|
|
||||||
|
(def tag-count
|
||||||
|
{:color "#838c93"
|
||||||
|
:fontFamily "sans-serif"
|
||||||
|
:fontSize 12
|
||||||
|
:paddingRight 5
|
||||||
|
:paddingBottom 2
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"})
|
||||||
|
|
||||||
|
(def tag-count-container
|
||||||
|
{:flex 0.2
|
||||||
|
:flexDirection "column"
|
||||||
|
:alignItems "flex-end"
|
||||||
|
:paddingTop 10
|
||||||
|
:paddingRight 9})
|
||||||
|
|
||||||
|
(def popular-list-container
|
||||||
|
{:flex 1
|
||||||
|
:backgroundColor "white"
|
||||||
|
:paddingLeft 10
|
||||||
|
:paddingTop 16})
|
||||||
|
|
||||||
|
(def popular-list
|
||||||
|
{:backgroundColor "white"
|
||||||
|
:paddingTop 13})
|
||||||
|
|
||||||
|
;; discover_popular_list_item.cjls
|
||||||
|
|
||||||
|
(def popular-list-item
|
||||||
|
{:flexDirection "row"
|
||||||
|
:paddingTop 10
|
||||||
|
:paddingBottom 10})
|
||||||
|
|
||||||
|
(def popular-list-item-status
|
||||||
|
{:color "black"
|
||||||
|
:fontFamily "sans-serif"
|
||||||
|
:lineHeight 22
|
||||||
|
:fontSize 14})
|
||||||
|
|
||||||
|
(def popular-list-item-name
|
||||||
|
{:color "black"
|
||||||
|
:fontFamily "sans-serif-medium"
|
||||||
|
:fontSize 14
|
||||||
|
:lineHeight 24})
|
||||||
|
|
||||||
|
(def popular-list-item-name-container
|
||||||
|
{:flex 0.8
|
||||||
|
:flexDirection "column"})
|
||||||
|
|
||||||
|
(def popular-list-item-avatar-container
|
||||||
|
{:flex 0.2
|
||||||
|
:flexDirection "column"
|
||||||
|
:alignItems "center"
|
||||||
|
:paddingTop 5})
|
||||||
|
|
||||||
|
(def popular-list-item-avatar
|
||||||
|
{:resizeMode "contain"
|
||||||
|
:borderRadius 150
|
||||||
|
:width 40
|
||||||
|
:height 40})
|
||||||
|
|
||||||
|
;; discovery_recent
|
||||||
|
|
||||||
|
(def recent-list
|
||||||
|
{:backgroundColor "white"
|
||||||
|
:paddingLeft 15})
|
||||||
|
|
||||||
|
;; discovery_tag
|
||||||
|
|
||||||
|
(def discovery-tag-container
|
||||||
|
{:flex 1
|
||||||
|
:backgroundColor "#eef2f5"})
|
||||||
|
|
||||||
|
(def tag-title
|
||||||
|
{:color "#7099e6"
|
||||||
|
:fontFamily "sans-serif-medium"
|
||||||
|
:fontSize 14
|
||||||
|
:paddingRight 5
|
||||||
|
:paddingBottom 2})
|
||||||
|
|
||||||
|
(def tag-title-container
|
||||||
|
{:backgroundColor "#eef2f5"
|
||||||
|
:flexWrap :wrap
|
||||||
|
:borderRadius 5
|
||||||
|
:padding 4})
|
||||||
|
|
||||||
|
(def icon-back
|
||||||
|
{:width 8
|
||||||
|
:height 14})
|
||||||
|
|
||||||
|
(def icon-search
|
||||||
|
{:width 17
|
||||||
|
:height 17})
|
|
@ -0,0 +1,48 @@
|
||||||
|
(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))))))
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
content])
|
content])
|
||||||
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
(def toolbar-android (r/adapt-react-class (.-ToolbarAndroid js/React)))
|
||||||
(def list-view (r/adapt-react-class (.-ListView js/React)))
|
(def list-view (r/adapt-react-class (.-ListView js/React)))
|
||||||
|
(def 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)))
|
(def text-input-class (r/adapt-react-class (.-TextInput js/React)))
|
||||||
(defn text-input [props text]
|
(defn text-input [props text]
|
||||||
[text-input-class (merge
|
[text-input-class (merge
|
||||||
|
|
|
@ -18,37 +18,44 @@
|
||||||
[reagent.core :as r]
|
[reagent.core :as r]
|
||||||
[syng-im.navigation :refer [nav-pop]]))
|
[syng-im.navigation :refer [nav-pop]]))
|
||||||
|
|
||||||
(defn toolbar [{:keys [navigator title nav-action action background-color]}]
|
(defn toolbar [{:keys [navigator title nav-action action background-color content style]}]
|
||||||
[view {:style {:flexDirection "row"
|
(let [style (merge {:flexDirection "row"
|
||||||
:backgroundColor (or background-color toolbar-background1)
|
:backgroundColor (or background-color toolbar-background1)
|
||||||
:height 56
|
:height 56
|
||||||
:elevation 2}}
|
:elevation 2} style)]
|
||||||
(if nav-action
|
[view {:style style}
|
||||||
[touchable-highlight {:on-press (:handler nav-action)}
|
(if nav-action
|
||||||
|
[touchable-highlight {:on-press (:handler nav-action)}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}
|
||||||
|
[image (:image nav-action)]]]
|
||||||
|
[touchable-highlight {:on-press #(nav-pop navigator)}
|
||||||
|
[view {:width 56
|
||||||
|
:height 56}
|
||||||
|
[image {:source {:uri "icon_back"}
|
||||||
|
:style {:marginTop 21
|
||||||
|
:marginLeft 23
|
||||||
|
:width 8
|
||||||
|
:height 14}}]]])
|
||||||
|
(if content
|
||||||
|
[view {:style {:flex 1
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}}
|
||||||
|
content]
|
||||||
|
[view {:style {:flex 1
|
||||||
|
:alignItems "center"
|
||||||
|
:justifyContent "center"}}
|
||||||
|
[text {:style {:marginTop -2.5
|
||||||
|
:color text1-color
|
||||||
|
:fontSize 16
|
||||||
|
:fontFamily font}}
|
||||||
|
title]])
|
||||||
|
[touchable-highlight {:on-press (:handler action)}
|
||||||
[view {:width 56
|
[view {:width 56
|
||||||
:height 56
|
:height 56
|
||||||
:alignItems "center"
|
:alignItems "center"
|
||||||
:justifyContent "center"}
|
:justifyContent "center"}
|
||||||
[image (:image nav-action)]]]
|
[image (:image action)]]]]))
|
||||||
[touchable-highlight {:on-press #(nav-pop navigator)}
|
|
||||||
[view {:width 56
|
|
||||||
:height 56}
|
|
||||||
[image {:source {:uri "icon_back"}
|
|
||||||
:style {:marginTop 21
|
|
||||||
:marginLeft 23
|
|
||||||
:width 8
|
|
||||||
:height 14}}]]])
|
|
||||||
[view {:style {:flex 1
|
|
||||||
:alignItems "center"
|
|
||||||
:justifyContent "center"}}
|
|
||||||
[text {:style {:marginTop -2.5
|
|
||||||
:color text1-color
|
|
||||||
:fontSize 16
|
|
||||||
:fontFamily font}}
|
|
||||||
title]]
|
|
||||||
[touchable-highlight {:on-press (:handler action)}
|
|
||||||
[view {:width 56
|
|
||||||
:height 56
|
|
||||||
:alignItems "center"
|
|
||||||
:justifyContent "center"}
|
|
||||||
[image (:image action)]]]])
|
|
||||||
|
|
|
@ -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 :chat-list)
|
(def default-view :discovery)
|
||||||
|
|
||||||
;; 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!"
|
||||||
|
@ -21,8 +21,9 @@
|
||||||
:new-participants #{}
|
:new-participants #{}
|
||||||
:signed-up false
|
:signed-up false
|
||||||
:view-id default-view
|
:view-id default-view
|
||||||
:navigation-stack (list default-view)})
|
:navigation-stack (list default-view)
|
||||||
|
:name "My Name"
|
||||||
|
:current-tag nil})
|
||||||
|
|
||||||
(def protocol-initialized-path [:protocol-initialized])
|
(def protocol-initialized-path [:protocol-initialized])
|
||||||
(def identity-password-path [:identity-password])
|
(def identity-password-path [:identity-password])
|
||||||
|
@ -47,3 +48,8 @@
|
||||||
(def show-actions-path [:show-actions])
|
(def show-actions-path [:show-actions])
|
||||||
(def new-group-path [:new-group])
|
(def new-group-path [:new-group])
|
||||||
(def new-participants-path [:new-participants])
|
(def new-participants-path [:new-participants])
|
||||||
|
(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])
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
apply-staged-commands
|
apply-staged-commands
|
||||||
check-suggestion]]
|
check-suggestion]]
|
||||||
[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.models.chats :refer [chat-exists?
|
[syng-im.models.chats :refer [chat-exists?
|
||||||
create-chat
|
create-chat
|
||||||
chat-add-participants
|
chat-add-participants
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
(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.resources :as res]
|
||||||
|
[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)))
|
||||||
|
|
|
@ -45,12 +45,27 @@
|
||||||
:name "string"
|
:name "string"
|
||||||
:group-chat {:type "bool"
|
:group-chat {:type "bool"
|
||||||
:indexed true}
|
:indexed true}
|
||||||
:is-active "bool"
|
:is-active "bool"
|
||||||
:timestamp "int"
|
:timestamp "int"
|
||||||
:contacts {:type "list"
|
:contacts {:type "list"
|
||||||
:objectType "chat-contact"}
|
:objectType "chat-contact"}
|
||||||
:last-msg-id "string"}}]})
|
: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"}}]})
|
||||||
|
|
||||||
(def realm (js/Realm. (clj->js opts)))
|
(def realm (js/Realm. (clj->js opts)))
|
||||||
|
|
||||||
|
@ -84,6 +99,10 @@
|
||||||
value))]
|
value))]
|
||||||
query))
|
query))
|
||||||
|
|
||||||
|
(defn get-by-filter [schema-name filter]
|
||||||
|
(-> (.objects realm (name schema-name))
|
||||||
|
(.filtered filter)))
|
||||||
|
|
||||||
(defn get-by-field [schema-name field value]
|
(defn get-by-field [schema-name field value]
|
||||||
(let [q (to-query schema-name :eq field value)]
|
(let [q (to-query schema-name :eq field value)]
|
||||||
(.filtered (.objects realm (name schema-name)) q)))
|
(.filtered (.objects realm (name schema-name)) q)))
|
||||||
|
|
|
@ -40,4 +40,6 @@
|
||||||
(dispatch [:you-removed-from-group from group-id msg-id]))
|
(dispatch [:you-removed-from-group from group-id msg-id]))
|
||||||
:participant-left-group (let [{:keys [group-id from msg-id]} event]
|
:participant-left-group (let [{:keys [group-id from msg-id]} event]
|
||||||
(dispatch [:participant-left-group from group-id msg-id]))
|
(dispatch [:participant-left-group from group-id msg-id]))
|
||||||
|
:discover-response (let [{:keys [from payload]} event]
|
||||||
|
(dispatch [:discovery-response-received from payload]))
|
||||||
(log/info "Don't know how to handle" event-type)))})
|
(log/info "Don't know how to handle" event-type)))})
|
||||||
|
|
|
@ -16,5 +16,6 @@
|
||||||
(def add-icon (js/require "./images/add.png"))
|
(def add-icon (js/require "./images/add.png"))
|
||||||
(def trash-icon (js/require "./images/trash.png"))
|
(def trash-icon (js/require "./images/trash.png"))
|
||||||
(def leave-icon (js/require "./images/leave.png"))
|
(def leave-icon (js/require "./images/leave.png"))
|
||||||
|
|
||||||
(def icon-close-gray (js/require "./images/icon_close_gray.png"))
|
(def icon-close-gray (js/require "./images/icon_close_gray.png"))
|
||||||
|
(def menu (js/require "./images/ic_menu_black_24dp_1x.png"))
|
||||||
|
(def search (js.require "./images/ic_search_black_24dp_1x.png"))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
(:require-macros [reagent.ratom :refer [reaction]])
|
(:require-macros [reagent.ratom :refer [reaction]])
|
||||||
(:require [re-frame.core :refer [register-sub]]
|
(:require [re-frame.core :refer [register-sub]]
|
||||||
[syng-im.db :as db]
|
[syng-im.db :as db]
|
||||||
|
[syng-im.components.discovery.subs :as discovery]
|
||||||
[syng-im.models.chat :refer [current-chat-id
|
[syng-im.models.chat :refer [current-chat-id
|
||||||
chat-updated?]]
|
chat-updated?]]
|
||||||
[syng-im.models.chats :refer [chats-list
|
[syng-im.models.chats :refer [chats-list
|
||||||
|
@ -75,6 +76,8 @@
|
||||||
(let [current-chat-id (current-chat-id @db)]
|
(let [current-chat-id (current-chat-id @db)]
|
||||||
(reaction (get-in @db [:chats current-chat-id])))))
|
(reaction (get-in @db [:chats current-chat-id])))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; -- User data --------------------------------------------------------------
|
;; -- User data --------------------------------------------------------------
|
||||||
|
|
||||||
;; (register-sub
|
;; (register-sub
|
||||||
|
|
Loading…
Reference in New Issue