From 23cf56a72ee8673cbb7fa6ab3af3e9a7e785b857 Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Wed, 24 Apr 2019 22:32:06 +0300 Subject: [PATCH] Allow to fetch more history in public chats (up to 30 days) --- src/status_im/chat/db.cljs | 37 +++++--- src/status_im/chat/subs.cljs | 29 +++++- src/status_im/events.cljs | 18 ++++ src/status_im/ui/screens/chat/actions.cljs | 12 +-- src/status_im/ui/screens/chat/views.cljs | 104 +++++++++++++-------- test/cljs/status_im/test/chat/db.cljs | 20 +++- translations/en.json | 6 +- 7 files changed, 168 insertions(+), 58 deletions(-) diff --git a/src/status_im/chat/db.cljs b/src/status_im/chat/db.cljs index d8d6c4f8c8a2..41a872e4bb54 100644 --- a/src/status_im/chat/db.cljs +++ b/src/status_im/chat/db.cljs @@ -6,7 +6,8 @@ [status-im.chat.commands.input :as commands.input] [status-im.group-chats.db :as group-chats.db] [status-im.utils.gfycat.core :as gfycat] - [status-im.transport.partitioned-topic :as topic])) + [status-im.transport.partitioned-topic :as topic] + [status-im.mailserver.core :as mailserver])) (defn group-chat-name [{:keys [public? name]}] @@ -86,10 +87,14 @@ (defn datemark? [{:keys [type]}] (= type :datemark)) +(defn gap? [{:keys [type]}] + (= type :gap)) + (defn transform-message [messages message-statuses referenced-messages] (fn [{:keys [message-id timestamp-str] :as reference}] - (if (datemark? reference) + (if (or (datemark? reference) + (gap? reference)) reference (let [{:keys [content] :as message} (get messages message-id) {:keys [response-to response-to-v2]} content @@ -141,18 +146,31 @@ (defn messages-with-datemarks-and-statuses "Converts message groups into sequence of messages interspersed with datemarks, with correct user statuses associated into message" - [message-groups messages message-statuses referenced-messages messages-gaps] + [message-groups messages message-statuses referenced-messages messages-gaps + {:keys [highest-request-to lowest-request-from]} all-loaded? public?] (transduce (comp (mapcat add-datemark) (map (transform-message messages message-statuses referenced-messages))) - (completing - (fn [{:keys [messages datemark-reference previous-message gaps]} - message] + (fn + ([] + (let [acc {:messages (list) + :previous-message nil + :gaps messages-gaps}] + (if (and + public? + all-loaded? + (< (- highest-request-to lowest-request-from) + mailserver/max-gaps-range)) + (update acc :messages conj {:type :gap + :value (str :first-gap) + :first-gap? true}) + acc))) + ([{:keys [messages datemark-reference previous-message gaps]} message] (let [new-datemark? (datemark? message) {:keys [gaps-number gap]} (check-gap gaps previous-message message) - add-gap? (pos? gaps-number)] + add-gap? (pos? gaps-number)] {:messages (cond-> messages add-gap? @@ -172,13 +190,10 @@ :gaps (if add-gap? (drop gaps-number gaps) gaps)})) - (fn [{:keys [messages gaps]}] + ([{:keys [messages gaps]}] (cond-> messages (seq gaps) (add-gap {:ids (map :id gaps)})))) - {:messages (list) - :previous-message nil - :gaps messages-gaps} message-groups)) (defn- set-previous-message-info [stream] diff --git a/src/status_im/chat/subs.cljs b/src/status_im/chat/subs.cljs index d286b8842e19..a50e9965e724 100644 --- a/src/status_im/chat/subs.cljs +++ b/src/status_im/chat/subs.cljs @@ -178,6 +178,25 @@ (fn [[gaps chat-id]] (sort-by :from (vals (get gaps chat-id))))) +(re-frame/reg-sub + :chats/range + :<- [:get-in [:mailserver/ranges]] + :<- [:chats/current-chat-id] + (fn [[ranges chat-id]] + (get ranges chat-id))) + +(re-frame/reg-sub + :chats/all-loaded? + :<- [:chats/current-chat] + (fn [chat] + (:all-loaded? chat))) + +(re-frame/reg-sub + :chats/public? + :<- [:chats/current-chat] + (fn [chat] + (:public? chat))) + (re-frame/reg-sub :chats/current-chat-messages-stream :<- [:chats/current-chat-messages] @@ -185,9 +204,15 @@ :<- [:chats/current-chat-message-statuses] :<- [:chats/current-chat-referenced-messages] :<- [:chats/messages-gaps] - (fn [[messages message-groups message-statuses referenced-messages messages-gaps]] + :<- [:chats/range] + :<- [:chats/all-loaded?] + :<- [:chats/public?] + (fn [[messages message-groups message-statuses referenced-messages + messages-gaps range all-loaded? public?]] (-> (chat.db/sort-message-groups message-groups messages) - (chat.db/messages-with-datemarks-and-statuses messages message-statuses referenced-messages messages-gaps) + (chat.db/messages-with-datemarks-and-statuses + messages message-statuses referenced-messages + messages-gaps range all-loaded? public?) chat.db/messages-stream))) (re-frame/reg-sub diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 4c5f0b07fa2e..2b5900e5f028 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -758,6 +758,24 @@ :topic topic :chat-id chat-id})))) +(handlers/register-handler-fx + :chat.ui/fetch-more + (fn [{:keys [db] :as cofx}] + (let [chat-id (:current-chat-id db) + + {:keys [lowest-request-from]} + (get-in db [:mailserver/ranges chat-id]) + + topic (chat.db/topic-by-current-chat db) + gaps [{:id :first-gap + :to lowest-request-from + :from (- lowest-request-from mailserver/one-day)}]] + (mailserver/fill-the-gap + cofx + {:gaps gaps + :topic topic + :chat-id chat-id})))) + (handlers/register-handler-fx :chat.ui/remove-chat-pressed (fn [_ [_ chat-id]] diff --git a/src/status_im/ui/screens/chat/actions.cljs b/src/status_im/ui/screens/chat/actions.cljs index 75fc5b8e217a..109b1b97c440 100644 --- a/src/status_im/ui/screens/chat/actions.cljs +++ b/src/status_im/ui/screens/chat/actions.cljs @@ -45,24 +45,24 @@ [(view-profile chat-id) (clear-history) (fetch-history chat-id) - (fetch-history48-60 chat-id) - (fetch-history84-96 chat-id) + #_(fetch-history48-60 chat-id) + #_(fetch-history84-96 chat-id) (delete-chat chat-id false)]) (defn- group-chat-actions [chat-id] [(group-info chat-id) (clear-history) (fetch-history chat-id) - (fetch-history48-60 chat-id) - (fetch-history84-96 chat-id) + #_(fetch-history48-60 chat-id) + #_(fetch-history84-96 chat-id) (delete-chat chat-id true)]) (defn- public-chat-actions [chat-id] [(share-chat chat-id) (clear-history) (fetch-history chat-id) - (fetch-history48-60 chat-id) - (fetch-history84-96 chat-id) + #_(fetch-history48-60 chat-id) + #_(fetch-history84-96 chat-id) (delete-chat chat-id false)]) (defn actions [group-chat? chat-id public?] diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs index 211ff091cbd8..5e2114628a9d 100644 --- a/src/status_im/ui/screens/chat/views.cljs +++ b/src/status_im/ui/screens/chat/views.cljs @@ -26,7 +26,8 @@ [status-im.ui.screens.chat.styles.main :as style] [status-im.ui.screens.chat.toolbar-content :as toolbar-content] [status-im.utils.platform :as platform] - [status-im.utils.utils :as utils]) + [status-im.utils.utils :as utils] + [status-im.utils.datetime :as datetime]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) (defn add-contact-bar [public-key] @@ -71,44 +72,64 @@ [message-datemark/chat-datemark-mobile value]) (defview gap - [ids idx list-ref in-progress? connected?] - [react/view {:align-self :stretch - :margin-top 24 - :margin-bottom 24 - :height 48 - :align-items :center - :justify-content :center - :border-color colors/gray-light - :border-top-width 1 - :border-bottom-width 1 - :background-color :white} - [react/touchable-highlight - {:on-press (when (and connected? (not in-progress?)) - #(do - (when @list-ref - (.scrollToIndex @list-ref #js {:index (max 0 (dec idx)) - :viewOffset 20 - :viewPosition 0.5})) - (re-frame/dispatch [:chat.ui/fill-gaps ids])))} - [react/view {:flex 1 - :align-items :center - :justify-content :center} - (if in-progress? - [react/activity-indicator] - [react/text - {:style {:color (if connected? - colors/blue - colors/gray)}} - (i18n/label :t/fetch-messages)])]]]) + [ids idx list-ref in-progress? connected? range first-gap? intro-loading?] + (when-not (and first-gap? intro-loading?) + [react/view {:align-self :stretch + :margin-top 24 + :margin-bottom 24 + :height 48 + :align-items :center + :justify-content :center + :border-color colors/gray-light + :border-top-width 1 + :border-bottom-width 1 + :background-color :white} + [react/touchable-highlight + {:on-press (when (and connected? (not in-progress?)) + #(do + (when @list-ref + (.scrollToIndex @list-ref #js {:index (max 0 (dec idx)) + :viewOffset 20 + :viewPosition 0.5})) + (if first-gap? + (re-frame/dispatch [:chat.ui/fetch-more]) + (re-frame/dispatch [:chat.ui/fill-gaps ids]))))} + [react/view {:style {:flex 1 + :align-items :center + :justify-content :center + :text-align :center}} + (if in-progress? + [react/activity-indicator] + [react/nested-text + {:style {:text-align :center + :color (if connected? + colors/blue + colors/gray)}} + (i18n/label (if first-gap? + :t/load-more-messages + :t/fetch-messages)) + (when first-gap? + [{:style {:typography :caption + :color colors/gray}} + (str "\n" + (i18n/label :t/load-messages-before + {:date (datetime/timestamp->long-date + (* 1000 (:lowest-request-from range)))}))])])]]])) -(defview gap-wrapper [{:keys [ids]} idx list-ref] - (letsubs [in-progress? [:chats/fetching-gap-in-progress? ids] - connected? [:mailserver/connected?]] - [gap ids idx list-ref in-progress? connected?])) +(defview gap-wrapper [{:keys [gaps first-gap?]} idx list-ref] + (letsubs [in-progress? [:chats/fetching-gap-in-progress? + (if first-gap? + [:first-gap] + (:ids gaps))] + connected? [:mailserver/connected?] + range [:chats/range] + intro-status [:chats/current-chat-intro-status]] + [gap (:ids gaps) idx list-ref in-progress? + connected? range first-gap? (= intro-status :loading)])) (defmethod message-row :gap [{:keys [row idx list-ref]}] - [gap-wrapper (:gaps row) idx list-ref]) + [gap-wrapper row idx list-ref]) (defmethod message-row :default [{:keys [group-chat current-public-key modal? row]}] @@ -182,7 +203,8 @@ universal-link]} no-messages] (letsubs [intro-status [:chats/current-chat-intro-status] height [:chats/content-layout-height] - input-height [:chats/current-chat-ui-prop :input-height]] + input-height [:chats/current-chat-ui-prop :input-height] + {:keys [:lowest-request-from :highest-request-to]} [:chats/range]] (let [icon-text (if public? chat-id name) intro-name (if public? chat-name name)] ;; TODO This when check ought to be unnecessary but for now it prevents @@ -226,7 +248,15 @@ (when public? [react/nested-text {:style (merge style/intro-header-description {:margin-bottom 36})} - (i18n/label :t/empty-chat-description-public) + (let [quiet-hours (quot (- highest-request-to lowest-request-from) + (* 60 60)) + quiet-time (if (<= quiet-hours 24) + (i18n/label :t/quiet-hours + {:quiet-hours quiet-hours}) + (i18n/label :t/quiet-days + {:quiet-days (quot quiet-hours 24)}))] + (i18n/label :t/empty-chat-description-public + {:quiet-hours quiet-time})) [{:style {:color colors/blue} :on-press #(list-selection/open-share {:message diff --git a/test/cljs/status_im/test/chat/db.cljs b/test/cljs/status_im/test/chat/db.cljs index 861faab0b578..8c2530eb205a 100644 --- a/test/cljs/status_im/test/chat/db.cljs +++ b/test/cljs/status_im/test/chat/db.cljs @@ -132,7 +132,25 @@ nil nil nil - nil)))) + nil + nil + false + false)))) + (testing "empty state pub-chat" + (is (= + [{:type :gap + :value ":first-gap" + :first-gap? true}] + (db/messages-with-datemarks-and-statuses + nil + nil + nil + nil + nil + {:lowest-request-from 10 + :highest-request-to 30} + true + true)))) (testing "simple case" (is (= '({:whisper-timestamp 40 diff --git a/translations/en.json b/translations/en.json index d9229bf274ec..4bf9e6bba4b1 100644 --- a/translations/en.json +++ b/translations/en.json @@ -283,7 +283,9 @@ "wallet-set-up-title": "Set up your wallet", "loading": "Loading... ", "empty-chat-description": "There are no messages \nin this chat yet", - "empty-chat-description-public": "It's been quiet here for the last 24h. Start the conversation or ", + "empty-chat-description-public": "It's been quiet here for the last {{quiet-hours}}. Start the conversation or ", + "quiet-hours": "{{quiet-hours}} hours", + "quiet-days": "{{quiet-days}} days", "empty-chat-description-public-share-this": "share this chat.", "camera-access-error": "To grant the required camera permission, please go to your system settings and make sure that Status > Camera is selected.", "wallet-invalid-address": "Invalid address: \n {{data}}", @@ -1000,6 +1002,8 @@ "mailserver-format": "enode://{enode-id}:{password}@{ip-address}:{port}", "bootnode-format": "enode://{enode-id}@{ip-address}:{port}", "fetch-messages": "↓ Fetch messages", + "load-more-messages": "↓ Fetch more messages", + "load-messages-before": "before {{date}}", "open-dapp-store": "Discover ÐApps", "browsed-websites": "Browsed websites will appear here." }