[feature] search chats
Signed-off-by: Igor Mandrigin <i@mandrigin.ru>
This commit is contained in:
parent
4f89073ae8
commit
6b6847a1ba
|
@ -5,30 +5,48 @@
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:search/filter
|
:search/filter
|
||||||
(fn [db]
|
(fn [db]
|
||||||
(get-in db [:ui/search :filter] "")))
|
(get-in db [:ui/search :filter])))
|
||||||
|
|
||||||
(defn filter-chats
|
(defn extract-browser-attributes
|
||||||
[[chats search-filter]]
|
[browser]
|
||||||
(if (empty? search-filter)
|
(let [{:keys [browser-id name]} (val browser)]
|
||||||
chats
|
[browser-id name]))
|
||||||
(let [search-filter (string/lower-case search-filter)]
|
|
||||||
(keep #(let [{:keys [name random-name tags]} (val %)]
|
(defn extract-chat-attributes [chat]
|
||||||
(when (some (fn [s]
|
(let [{:keys [name random-name tags]} (val chat)]
|
||||||
(when s
|
(into [name random-name] tags)))
|
||||||
(string/includes? (string/lower-case s)
|
|
||||||
search-filter)))
|
(defn apply-filter
|
||||||
(into [name random-name] tags))
|
"extract-attributes-fn is a function that take an element from the collection
|
||||||
%))
|
and returns a vector of attributes which are strings
|
||||||
chats))))
|
apply-filter returns the elements for which at least one attribute includes
|
||||||
|
the search-filter
|
||||||
|
apply-filter returns nil if the search-filter is empty or if there is no element
|
||||||
|
that match the filter"
|
||||||
|
[search-filter coll extract-attributes-fn]
|
||||||
|
(when (not-empty search-filter)
|
||||||
|
(let [search-filter (string/lower-case search-filter)
|
||||||
|
results (filter (fn [element]
|
||||||
|
(some (fn [s]
|
||||||
|
(when (string? s)
|
||||||
|
(string/includes? (string/lower-case s)
|
||||||
|
search-filter)))
|
||||||
|
(extract-attributes-fn element)))
|
||||||
|
coll)]
|
||||||
|
(when (not-empty results)
|
||||||
|
(sort-by #(-> % second :timestamp) >
|
||||||
|
(into {} results))))))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:search/filtered-active-chats
|
:search/filtered-chats
|
||||||
:<- [:chats/active-chats]
|
:<- [:chats/active-chats]
|
||||||
:<- [:search/filter]
|
:<- [:search/filter]
|
||||||
filter-chats)
|
(fn [[chats search-filter]]
|
||||||
|
(apply-filter search-filter chats extract-chat-attributes)))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:search/filtered-home-items
|
:search/filtered-browsers
|
||||||
:<- [:search/filtered-active-chats]
|
:<- [:browser/browsers]
|
||||||
(fn [active-chats]
|
:<- [:search/filter]
|
||||||
(sort-by #(-> % second :timestamp) > active-chats)))
|
(fn [[browsers search-filter]]
|
||||||
|
(apply-filter search-filter browsers extract-browser-attributes)))
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
:flex-direction :row
|
:flex-direction :row
|
||||||
:align-items :center
|
:align-items :center
|
||||||
:background-color colors/white
|
:background-color colors/white
|
||||||
:height 52})
|
:height 64})
|
||||||
|
|
||||||
(defn settings-item-icon [icon-color]
|
(defn settings-item-icon [icon-color]
|
||||||
{:background-color (colors/alpha icon-color 0.1)
|
{:background-color (colors/alpha icon-color 0.1)
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
[flat-list {:data [{:title \"\" :subtitle \"\"}] :render-fn render}]
|
[flat-list {:data [{:title \"\" :subtitle \"\"}] :render-fn render}]
|
||||||
|
|
||||||
[section-list {:sections [{:title :key :unik :data {:title \"\" :subtitle \"\"}}] :render-fn render}]
|
[section-list {:sections [{:title \"\" :key :unik :data {:title \"\" :subtitle \"\"}}] :render-fn render}]
|
||||||
|
|
||||||
or with a per-section `render-fn`
|
or with a per-section `render-fn`
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@
|
||||||
(and action-fn text)
|
(and action-fn text)
|
||||||
(or (nil? accessibility-label) (keyword? accessibility-label))]}
|
(or (nil? accessibility-label) (keyword? accessibility-label))]}
|
||||||
[react/touchable-highlight
|
[react/touchable-highlight
|
||||||
(cond-> {:on-press action-fn
|
{:on-press action-fn
|
||||||
:accessibility-label accessibility-label
|
:accessibility-label accessibility-label
|
||||||
:disabled (not active?)})
|
:disabled (not active?)}
|
||||||
[react/view styles/settings-item
|
[react/view styles/settings-item
|
||||||
(if icon
|
(if icon
|
||||||
[react/view (styles/settings-item-icon icon-color)
|
[react/view (styles/settings-item-icon icon-color)
|
||||||
|
@ -218,12 +218,16 @@
|
||||||
|
|
||||||
(defn section-list
|
(defn section-list
|
||||||
"A wrapper for SectionList.
|
"A wrapper for SectionList.
|
||||||
|
To render something on empty sections, use renderSectionFooter and conditionaly
|
||||||
|
render on empty data
|
||||||
See https://facebook.github.io/react-native/docs/sectionlist.html"
|
See https://facebook.github.io/react-native/docs/sectionlist.html"
|
||||||
[{:keys [sections render-section-header-fn] :as props
|
[{:keys [sections render-section-header-fn render-section-footer-fn] :as props
|
||||||
:or {render-section-header-fn default-render-section-header}}]
|
:or {render-section-header-fn default-render-section-header}}]
|
||||||
[section-list-class
|
[section-list-class
|
||||||
(merge (base-list-props props)
|
(merge (base-list-props props)
|
||||||
props
|
props
|
||||||
|
(when render-section-footer-fn
|
||||||
|
{:renderSectionFooter (wrap-render-section-header-fn render-section-footer-fn)})
|
||||||
{:sections (clj->js (map wrap-per-section-render-fn sections))
|
{:sections (clj->js (map wrap-per-section-render-fn sections))
|
||||||
:renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)})])
|
:renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)})])
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@
|
||||||
(views/defview chat-list-view [loading?]
|
(views/defview chat-list-view [loading?]
|
||||||
(views/letsubs [search-filter [:search/filter]
|
(views/letsubs [search-filter [:search/filter]
|
||||||
logging-in? [:get :accounts/login]
|
logging-in? [:get :accounts/login]
|
||||||
filtered-home-items [:search/filtered-home-items]]
|
{:keys [all-home-items chats]} [:home-items]]
|
||||||
{:component-did-mount
|
{:component-did-mount
|
||||||
(fn [this]
|
(fn [this]
|
||||||
(let [[_ loading?] (.. this -props -argv)]
|
(let [[_ loading?] (.. this -props -argv)]
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
[icons/icon :main-icons/add {:style {:tint-color :white}}])]]]]
|
[icons/icon :main-icons/add {:style {:tint-color :white}}])]]]]
|
||||||
[react/scroll-view {:enableArrayScrollingOptimization true}
|
[react/scroll-view {:enableArrayScrollingOptimization true}
|
||||||
[react/view
|
[react/view
|
||||||
(for [[index chat] (map-indexed vector filtered-home-items)]
|
(for [[index chat] (map-indexed vector (or all-home-items chats))]
|
||||||
^{:key (first chat)}
|
^{:key (first chat)}
|
||||||
[chat-list-item chat])]]]))
|
[chat-list-item chat])]]]))
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns status-im.ui.screens.home.styles
|
(ns status-im.ui.screens.home.styles
|
||||||
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
||||||
(:require [status-im.ui.components.colors :as colors]))
|
(:require [status-im.ui.components.colors :as colors]
|
||||||
|
[status-im.utils.platform :as platform]))
|
||||||
|
|
||||||
(defn toolbar []
|
(defn toolbar []
|
||||||
{:background-color colors/white})
|
{:background-color colors/white})
|
||||||
|
@ -94,6 +95,40 @@
|
||||||
:ios {:font-size 15
|
:ios {:font-size 15
|
||||||
:height 24}})
|
:height 24}})
|
||||||
|
|
||||||
|
(def search-input-height 56)
|
||||||
|
|
||||||
|
(def search-container
|
||||||
|
{:height search-input-height
|
||||||
|
:flex-direction :row
|
||||||
|
:padding-horizontal 16
|
||||||
|
:background-color colors/white
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center})
|
||||||
|
|
||||||
|
(def search-input-container
|
||||||
|
{:background-color colors/gray-lighter
|
||||||
|
:flex 1
|
||||||
|
:flex-direction :row
|
||||||
|
:height 36
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center
|
||||||
|
:border-radius 8})
|
||||||
|
|
||||||
|
(def search-input
|
||||||
|
(merge {:flex 1
|
||||||
|
:font-size 15}
|
||||||
|
(when platform/android?
|
||||||
|
{:line-height 22
|
||||||
|
:margin 0
|
||||||
|
:padding 0})))
|
||||||
|
|
||||||
|
(def filter-section-title
|
||||||
|
{:font-size 15
|
||||||
|
:margin-left 16
|
||||||
|
:margin-top 14
|
||||||
|
:margin-bottom 4
|
||||||
|
:color colors/gray})
|
||||||
|
|
||||||
(def status-container
|
(def status-container
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:top 16
|
:top 16
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
(ns status-im.ui.screens.home.subs
|
(ns status-im.ui.screens.home.subs
|
||||||
(:require [re-frame.core :as re-frame]))
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[status-im.utils.platform :as platform]))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:home-items
|
:home-items
|
||||||
:<- [:chats/active-chats]
|
:<- [:chats/active-chats]
|
||||||
:<- [:browser/browsers]
|
:<- [:browser/browsers]
|
||||||
(fn [[chats browsers]]
|
:<- [:search/filter]
|
||||||
(sort-by #(-> % second :timestamp) > (merge chats browsers))))
|
:<- [:search/filtered-chats]
|
||||||
|
:<- [:search/filtered-browsers]
|
||||||
|
(fn [[chats browsers search-filter filtered-chats filtered-browsers]]
|
||||||
|
(if (or (nil? search-filter)
|
||||||
|
(and platform/desktop? (empty? search-filter)))
|
||||||
|
{:all-home-items
|
||||||
|
(sort-by #(-> % second :timestamp) >
|
||||||
|
(merge chats browsers))}
|
||||||
|
{:search-filter search-filter
|
||||||
|
:chats filtered-chats
|
||||||
|
:browsers filtered-browsers})))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:chain-sync-state
|
:chain-sync-state
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
(ns status-im.ui.screens.home.views
|
(ns status-im.ui.screens.home.views
|
||||||
(:require-macros [status-im.utils.views :as views])
|
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im.i18n :as i18n]
|
||||||
|
[status-im.react-native.resources :as resources]
|
||||||
|
[status-im.ui.components.animation :as animation]
|
||||||
|
[status-im.ui.components.colors :as colors]
|
||||||
|
[status-im.ui.components.common.common :as components.common]
|
||||||
|
[status-im.ui.components.connectivity.view :as connectivity]
|
||||||
|
[status-im.ui.components.icons.vector-icons :as icons]
|
||||||
[status-im.ui.components.list.views :as list]
|
[status-im.ui.components.list.views :as list]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.toolbar.view :as toolbar]
|
[status-im.ui.components.status-bar.view :as status-bar]
|
||||||
[status-im.ui.components.toolbar.actions :as toolbar.actions]
|
[status-im.ui.components.toolbar.actions :as toolbar.actions]
|
||||||
[status-im.ui.components.connectivity.view :as connectivity]
|
[status-im.ui.components.toolbar.view :as toolbar]
|
||||||
[status-im.ui.components.colors :as colors]
|
|
||||||
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
|
||||||
[status-im.ui.screens.home.styles :as styles]
|
[status-im.ui.screens.home.styles :as styles]
|
||||||
|
[status-im.ui.screens.home.views.inner-item :as inner-item]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.react-native.resources :as resources]
|
[status-im.utils.utils :as utils])
|
||||||
[status-im.ui.components.common.common :as components.common]
|
(:require-macros [status-im.utils.views :as views]))
|
||||||
[status-im.ui.components.icons.vector-icons :as icons]
|
|
||||||
[status-im.utils.datetime :as time]
|
|
||||||
[status-im.ui.components.react :as components]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.ui.components.status-bar.view :as status-bar]))
|
|
||||||
|
|
||||||
(defn- toolbar [show-welcome? show-sync-state sync-state latest-block-number logged-in?]
|
(defn- toolbar [show-welcome? show-sync-state sync-state latest-block-number logged-in?]
|
||||||
(when-not (and show-welcome?
|
(when-not (and show-welcome?
|
||||||
|
@ -44,8 +45,8 @@
|
||||||
(assoc-in [:icon-opts :accessibility-label] :new-chat-button))]]
|
(assoc-in [:icon-opts :accessibility-label] :new-chat-button))]]
|
||||||
platform/ios?
|
platform/ios?
|
||||||
[react/view {:style styles/spinner-container}
|
[react/view {:style styles/spinner-container}
|
||||||
[components/activity-indicator {:color colors/blue
|
[react/activity-indicator {:color colors/blue
|
||||||
:animating true}]])]))
|
:animating true}]])]))
|
||||||
|
|
||||||
(defn- home-action-button [logged-in?]
|
(defn- home-action-button [logged-in?]
|
||||||
[react/view styles/action-button-container
|
[react/view styles/action-button-container
|
||||||
|
@ -53,8 +54,8 @@
|
||||||
:on-press (when logged-in? #(re-frame/dispatch [:navigate-to :new]))}
|
:on-press (when logged-in? #(re-frame/dispatch [:navigate-to :new]))}
|
||||||
[react/view styles/action-button
|
[react/view styles/action-button
|
||||||
(if-not logged-in?
|
(if-not logged-in?
|
||||||
[components/activity-indicator {:color :white
|
[react/activity-indicator {:color :white
|
||||||
:animating true}]
|
:animating true}]
|
||||||
[icons/icon :main-icons/add {:color :white}])]]])
|
[icons/icon :main-icons/add {:color :white}])]]])
|
||||||
|
|
||||||
(defn home-list-item [[home-item-id home-item]]
|
(defn home-list-item [[home-item-id home-item]]
|
||||||
|
@ -88,15 +89,178 @@
|
||||||
[react/i18n-text {:style styles/welcome-text-description
|
[react/i18n-text {:style styles/welcome-text-description
|
||||||
:key :welcome-to-status-description}]]]))
|
:key :welcome-to-status-description}]]]))
|
||||||
|
|
||||||
(views/defview chats-list []
|
(defn search-input
|
||||||
(views/letsubs [home-items [:home-items]]
|
[search-filter {:keys [on-cancel on-focus on-change]}]
|
||||||
(if (empty? home-items)
|
(let [input-is-focused? (reagent/atom false)
|
||||||
[react/view styles/no-chats
|
input-ref (reagent/atom nil)]
|
||||||
[react/i18n-text {:style styles/no-chats-text :key :no-recent-chats}]]
|
(fn [search-filter]
|
||||||
[list/flat-list {:data home-items
|
(let [show-cancel? (or @input-is-focused?
|
||||||
:key-fn first
|
search-filter)]
|
||||||
:render-fn (fn [home-item]
|
[react/view {:style styles/search-container}
|
||||||
[home-list-item home-item])}])))
|
[react/view {:style styles/search-input-container}
|
||||||
|
[icons/icon :main-icons/search {:color colors/gray
|
||||||
|
:container-style {:margin-left 6
|
||||||
|
:margin-right 2}}]
|
||||||
|
[react/text-input {:placeholder (i18n/label :t/search)
|
||||||
|
:blur-on-submit true
|
||||||
|
:multiline false
|
||||||
|
:ref #(reset! input-ref %)
|
||||||
|
:style styles/search-input
|
||||||
|
:default-value search-filter
|
||||||
|
:on-focus
|
||||||
|
#(do
|
||||||
|
(when on-focus
|
||||||
|
(on-focus search-filter))
|
||||||
|
(reset! input-is-focused? true))
|
||||||
|
:on-change
|
||||||
|
(fn [e]
|
||||||
|
(let [native-event (.-nativeEvent e)
|
||||||
|
text (.-text native-event)]
|
||||||
|
(when on-change
|
||||||
|
(on-change text))))}]]
|
||||||
|
(when show-cancel?
|
||||||
|
[react/touchable-highlight
|
||||||
|
{:on-press #(do
|
||||||
|
(when on-cancel
|
||||||
|
(on-cancel))
|
||||||
|
(.blur @input-ref)
|
||||||
|
(reset! input-is-focused? false))
|
||||||
|
:style {:margin-left 16}}
|
||||||
|
[react/text {:style {:color colors/blue
|
||||||
|
:font-size 15}}
|
||||||
|
(i18n/label :t/cancel)]])]))))
|
||||||
|
|
||||||
|
(defonce search-input-state
|
||||||
|
(reagent/atom {:show? false
|
||||||
|
:height (animation/create-value 0)}))
|
||||||
|
|
||||||
|
(defn show-search!
|
||||||
|
[]
|
||||||
|
(swap! search-input-state assoc :show? true)
|
||||||
|
(animation/start
|
||||||
|
(animation/timing (:height @search-input-state)
|
||||||
|
{:toValue styles/search-input-height
|
||||||
|
:duration 350
|
||||||
|
:easing (.out (animation/easing)
|
||||||
|
(.-quad (animation/easing)))})))
|
||||||
|
|
||||||
|
(defn hide-search!
|
||||||
|
[]
|
||||||
|
(utils/set-timeout
|
||||||
|
#(swap! search-input-state assoc :show? false)
|
||||||
|
350)
|
||||||
|
(animation/start
|
||||||
|
(animation/timing (:height @search-input-state)
|
||||||
|
{:toValue 0
|
||||||
|
:duration 350
|
||||||
|
:easing (.in (animation/easing)
|
||||||
|
(.-quad (animation/easing)))})))
|
||||||
|
|
||||||
|
(defn animated-search-input
|
||||||
|
[search-filter]
|
||||||
|
(reagent/create-class
|
||||||
|
{:component-will-unmount
|
||||||
|
#(do (swap! search-input-state assoc :show? false)
|
||||||
|
(animation/set-value (:height @search-input-state) 0))
|
||||||
|
:reagent-render
|
||||||
|
(fn [search-filter]
|
||||||
|
(let [{:keys [show? height]} @search-input-state]
|
||||||
|
(when (or show?
|
||||||
|
search-filter)
|
||||||
|
[react/animated-view
|
||||||
|
{:style {:height height}}
|
||||||
|
[search-input search-filter
|
||||||
|
{:on-cancel #(do
|
||||||
|
(re-frame/dispatch [:search/filter-changed nil])
|
||||||
|
(hide-search!))
|
||||||
|
:on-focus (fn [search-filter]
|
||||||
|
(when-not search-filter
|
||||||
|
(re-frame/dispatch [:search/filter-changed ""])))
|
||||||
|
:on-change (fn [text]
|
||||||
|
(re-frame/dispatch [:search/filter-changed text]))}]])))}))
|
||||||
|
|
||||||
|
(defn home-empty-view
|
||||||
|
[]
|
||||||
|
[react/view styles/no-chats
|
||||||
|
[react/i18n-text {:style styles/no-chats-text :key :no-recent-chats}]])
|
||||||
|
|
||||||
|
(defn home-filtered-items-list
|
||||||
|
[chats browsers]
|
||||||
|
[list/section-list
|
||||||
|
{:sections [{:title :t/chats
|
||||||
|
:data chats}
|
||||||
|
{:title :t/browsers
|
||||||
|
:data browsers}
|
||||||
|
{:title :t/messages
|
||||||
|
:data []}]
|
||||||
|
:key-fn first
|
||||||
|
;; true by default on iOS
|
||||||
|
:stickySectionHeadersEnabled false
|
||||||
|
:render-section-header-fn
|
||||||
|
(fn [{:keys [title data]}]
|
||||||
|
[react/view {:style {:height 40}}
|
||||||
|
[react/text {:style styles/filter-section-title}
|
||||||
|
(i18n/label title)]])
|
||||||
|
:render-section-footer-fn
|
||||||
|
(fn [{:keys [title data]}]
|
||||||
|
(when (empty? data)
|
||||||
|
[list/big-list-item
|
||||||
|
{:text (i18n/label (if (= title "messages")
|
||||||
|
:t/messages-search-coming-soon
|
||||||
|
:t/no-result))
|
||||||
|
:text-color colors/gray
|
||||||
|
:hide-chevron? true
|
||||||
|
:action-fn #()
|
||||||
|
:icon (case title
|
||||||
|
"messages" :main-icons/private-chat
|
||||||
|
"browsers" :main-icons/browser
|
||||||
|
"chats" :main-icons/message)
|
||||||
|
:icon-color colors/gray}]))
|
||||||
|
:render-fn (fn [home-item]
|
||||||
|
[home-list-item home-item])}])
|
||||||
|
|
||||||
|
(defn home-items-view
|
||||||
|
[search-filter chats browsers all-home-items]
|
||||||
|
(let [previous-touch (reagent/atom nil)
|
||||||
|
scrolling-from-top? (reagent/atom true)]
|
||||||
|
(fn [search-filter chats browsers all-home-items]
|
||||||
|
(if (not-empty search-filter)
|
||||||
|
[home-filtered-items-list chats browsers]
|
||||||
|
[react/view
|
||||||
|
(merge {:style {:flex 1}}
|
||||||
|
(when (and @scrolling-from-top?
|
||||||
|
(not (:show? @search-input-state)))
|
||||||
|
{:on-start-should-set-responder-capture
|
||||||
|
(fn [event]
|
||||||
|
(println :start)
|
||||||
|
(let [current-position (.-pageY (.-nativeEvent event))
|
||||||
|
current-timestamp (.-timestamp (.-nativeEvent event))]
|
||||||
|
(reset! previous-touch
|
||||||
|
[current-position current-timestamp]))
|
||||||
|
|
||||||
|
false)
|
||||||
|
:on-move-should-set-responder
|
||||||
|
(fn [event]
|
||||||
|
(let [current-position (.-pageY (.-nativeEvent event))
|
||||||
|
current-timestamp (.-timestamp (.-nativeEvent event))
|
||||||
|
[previous-position previous-timestamp] @previous-touch]
|
||||||
|
(when (and previous-position
|
||||||
|
(> 100 (- current-timestamp previous-timestamp))
|
||||||
|
(< 10 (- current-position
|
||||||
|
previous-position)))
|
||||||
|
(show-search!)))
|
||||||
|
false)}))
|
||||||
|
[list/flat-list {:data all-home-items
|
||||||
|
:key-fn first
|
||||||
|
:end-fill-color colors/white
|
||||||
|
:on-scroll-begin-drag
|
||||||
|
(fn [e]
|
||||||
|
(reset! scrolling-from-top?
|
||||||
|
;; check if scrolling up from top of list
|
||||||
|
(zero? (.-y (.-contentOffset (.-nativeEvent e))))))
|
||||||
|
:render-fn
|
||||||
|
(fn [home-item]
|
||||||
|
[home-list-item home-item])}]]))))
|
||||||
|
|
||||||
(views/defview home [loading?]
|
(views/defview home [loading?]
|
||||||
(views/letsubs [show-welcome? [:get-in [:accounts/create :show-welcome?]]
|
(views/letsubs [show-welcome? [:get-in [:accounts/create :show-welcome?]]
|
||||||
|
@ -105,7 +269,8 @@
|
||||||
sync-state [:chain-sync-state]
|
sync-state [:chain-sync-state]
|
||||||
latest-block-number [:latest-block-number]
|
latest-block-number [:latest-block-number]
|
||||||
rpc-network? [:current-network-uses-rpc?]
|
rpc-network? [:current-network-uses-rpc?]
|
||||||
network-initialized? [:current-network-initialized?]]
|
network-initialized? [:current-network-initialized?]
|
||||||
|
{:keys [search-filter chats browsers all-home-items]} [:home-items]]
|
||||||
{:component-did-mount
|
{:component-did-mount
|
||||||
(fn [this]
|
(fn [this]
|
||||||
(let [[_ loading?] (.. this -props -argv)]
|
(let [[_ loading?] (.. this -props -argv)]
|
||||||
|
@ -115,21 +280,29 @@
|
||||||
100))))}
|
100))))}
|
||||||
[react/view styles/container
|
[react/view styles/container
|
||||||
[status-bar/status-bar {:type :main}]
|
[status-bar/status-bar {:type :main}]
|
||||||
[react/view (assoc styles/container :background-color :white)
|
[react/keyboard-avoiding-view {:style (assoc styles/container :background-color :white)}
|
||||||
[toolbar show-welcome? (and network-initialized? (not rpc-network?)) sync-state latest-block-number (not logging-in?)]
|
[toolbar show-welcome? (and network-initialized? (not rpc-network?))
|
||||||
|
sync-state latest-block-number (not logging-in?)]
|
||||||
(cond show-welcome?
|
(cond show-welcome?
|
||||||
[welcome view-id]
|
[welcome view-id]
|
||||||
|
|
||||||
loading?
|
loading?
|
||||||
[react/view {:style {:flex 1
|
[react/view {:style {:flex 1
|
||||||
:justify-content :center
|
:justify-content :center
|
||||||
:align-items :center}}
|
:align-items :center}}
|
||||||
[connectivity/connectivity-view]
|
[connectivity/connectivity-view]
|
||||||
[components/activity-indicator {:flex 1
|
[react/activity-indicator {:flex 1
|
||||||
:animating true}]]
|
:animating true}]]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[react/view {:style {:flex 1}}
|
[react/view {:style {:flex 1
|
||||||
|
:z-index -1}}
|
||||||
[connectivity/connectivity-view]
|
[connectivity/connectivity-view]
|
||||||
[chats-list]])
|
[animated-search-input search-filter]
|
||||||
|
(if (and (not search-filter)
|
||||||
|
(empty? all-home-items))
|
||||||
|
[home-empty-view]
|
||||||
|
[home-items-view search-filter chats browsers all-home-items])])
|
||||||
(when platform/android?
|
(when platform/android?
|
||||||
[home-action-button (not logging-in?)])]]))
|
[home-action-button (not logging-in?)])]]))
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,32 @@
|
||||||
:random-name "random-name4"
|
:random-name "random-name4"
|
||||||
:tags #{"tag4"}}}]
|
:tags #{"tag4"}}}]
|
||||||
(testing "no search filter"
|
(testing "no search filter"
|
||||||
(is (= 4 (count (search.subs/filter-chats [chats ""])))))
|
(is (= 0
|
||||||
|
(count (search.subs/apply-filter ""
|
||||||
|
chats
|
||||||
|
search.subs/extract-chat-attributes)))))
|
||||||
(testing "searching for a specific tag"
|
(testing "searching for a specific tag"
|
||||||
(is (= 1 (count (search.subs/filter-chats [chats "tag2"])))))
|
(is (= 1
|
||||||
|
(count (search.subs/apply-filter "tag2"
|
||||||
|
chats
|
||||||
|
search.subs/extract-chat-attributes)))))
|
||||||
(testing "searching for a partial tag"
|
(testing "searching for a partial tag"
|
||||||
(is (= 3 (count (search.subs/filter-chats [chats "tag"])))))
|
(is (= 3
|
||||||
|
(count (search.subs/apply-filter "tag"
|
||||||
|
chats
|
||||||
|
search.subs/extract-chat-attributes)))))
|
||||||
(testing "searching for a specific random-name"
|
(testing "searching for a specific random-name"
|
||||||
(is (= 1 (count (search.subs/filter-chats [chats "random-name1"])))))
|
(is (= 1
|
||||||
|
(count (search.subs/apply-filter "random-name1"
|
||||||
|
chats
|
||||||
|
search.subs/extract-chat-attributes)))))
|
||||||
(testing "searching for a partial random-name"
|
(testing "searching for a partial random-name"
|
||||||
(is (= 4 (count (search.subs/filter-chats [chats "random-name"])))))
|
(is (= 4
|
||||||
|
(count (search.subs/apply-filter "random-name"
|
||||||
|
chats
|
||||||
|
search.subs/extract-chat-attributes)))))
|
||||||
(testing "searching for a specific chat name"
|
(testing "searching for a specific chat name"
|
||||||
(is (= 1 (count (search.subs/filter-chats [chats "name4"])))))))
|
(is (= 1
|
||||||
|
(count (search.subs/apply-filter "name4"
|
||||||
|
chats
|
||||||
|
search.subs/extract-chat-attributes)))))))
|
||||||
|
|
|
@ -248,6 +248,7 @@
|
||||||
"desktop-alpha-release-warning": "Thanks for trying Status Desktop! This is an early alpha release focused on chat, and is missing several features found in the mobile client and may contain bugs and other issues. Please note that this is an alpha release and we advise you that using this app should be done for testing purposes only and you assume the full responsibility for all risks concerning your data and funds. Status makes no claims of security or integrity of funds in these builds.",
|
"desktop-alpha-release-warning": "Thanks for trying Status Desktop! This is an early alpha release focused on chat, and is missing several features found in the mobile client and may contain bugs and other issues. Please note that this is an alpha release and we advise you that using this app should be done for testing purposes only and you assume the full responsibility for all risks concerning your data and funds. Status makes no claims of security or integrity of funds in these builds.",
|
||||||
"delete-message": "Delete message",
|
"delete-message": "Delete message",
|
||||||
"browser": "Browser",
|
"browser": "Browser",
|
||||||
|
"browsers": "Browsers",
|
||||||
"sign-message": "Sign Message",
|
"sign-message": "Sign Message",
|
||||||
"reorder-groups": "Reorder groups",
|
"reorder-groups": "Reorder groups",
|
||||||
"currency-display-name-rub": "Russia Ruble",
|
"currency-display-name-rub": "Russia Ruble",
|
||||||
|
@ -743,7 +744,11 @@
|
||||||
"your-data-belongs-to-you-description": "Status can’t help you recover your account if you lose your recovery phrase. You are in charge of the security of your data, and backing up your recovery phrase is the best safeguard.",
|
"your-data-belongs-to-you-description": "Status can’t help you recover your account if you lose your recovery phrase. You are in charge of the security of your data, and backing up your recovery phrase is the best safeguard.",
|
||||||
"transactions-filter-title": "Filter history",
|
"transactions-filter-title": "Filter history",
|
||||||
"view-profile": "View profile",
|
"view-profile": "View profile",
|
||||||
|
"search": "Search",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
|
"messages": "Messages",
|
||||||
|
"messages-search-coming-soon": "Searching message history coming soon",
|
||||||
|
"no-result": "No results",
|
||||||
"here-is-your-passphrase": "Here is your passphrase, *write this down and keep this safe!* You will need it to recover your account.",
|
"here-is-your-passphrase": "Here is your passphrase, *write this down and keep this safe!* You will need it to recover your account.",
|
||||||
"currency-display-name-ttd": "Trinidad and Tobago Dollar",
|
"currency-display-name-ttd": "Trinidad and Tobago Dollar",
|
||||||
"wallet-assets": "Assets",
|
"wallet-assets": "Assets",
|
||||||
|
|
Loading…
Reference in New Issue