feat: undo delete with toast (#14618)

This commit is contained in:
yqrashawn 2023-01-10 10:02:23 +08:00 committed by GitHub
parent 6f10ff4d3e
commit 02a1c3597f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 382 additions and 195 deletions

View File

@ -206,58 +206,60 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return (
(def react-native-reanimated
#js
{:default #js
{:createAnimatedComponent identity
:eq nil
:greaterOrEq nil
:greaterThan nil
:lessThan nil
:lessOrEq nil
:add nil
:diff nil
:divide nil
:sub nil
:multiply nil
:abs nil
:min nil
:max nil
:neq nil
:and nil
:or nil
:not nil
:set nil
:startClock nil
:stopClock nil
:Value nil
:Clock nil
:debug nil
:log nil
:event nil
:cond nil
:block nil
:interpolateNode nil
:call nil
:timing nil
:onChange nil
:View #js {}
:Image #js {}
:ScrollView #js {}
:Text #js {}
:Extrapolate #js {:CLAMP nil}
:Code #js {}}
:EasingNode #js
{:bezier identity
:linear identity}
:clockRunning nil
:useSharedValue (fn [])
:useAnimatedStyle (fn [])
:withTiming (fn [])
:withDelay (fn [])
:Easing #js {:bezier identity}
:Keyframe (fn [])
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
{:default #js
{:createAnimatedComponent identity
:eq nil
:greaterOrEq nil
:greaterThan nil
:lessThan nil
:lessOrEq nil
:add nil
:diff nil
:divide nil
:sub nil
:multiply nil
:abs nil
:min nil
:max nil
:neq nil
:and nil
:or nil
:not nil
:set nil
:startClock nil
:stopClock nil
:Value nil
:Clock nil
:debug nil
:log nil
:event nil
:cond nil
:block nil
:interpolateNode nil
:call nil
:timing nil
:onChange nil
:View #js {}
:Image #js {}
:ScrollView #js {}
:Text #js {}
:Extrapolate #js {:CLAMP nil}
:Code #js {}}
:EasingNode #js
{:bezier identity
:linear identity}
:clockRunning nil
:useSharedValue (fn [])
:useAnimatedStyle (fn [])
:withTiming (fn [])
:withDelay (fn [])
:Easing #js {:bezier identity}
:Keyframe (fn [])
:enableLayoutAnimations (fn [])
:SlideOutUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:SlideInUp js/__STATUS_MOBILE_JS_IDENTITY_PROXY__
:LinearTransition js/__STATUS_MOBILE_JS_IDENTITY_PROXY__})
(def react-native-gesture-handler
#js
{:default #js {}

View File

@ -8,14 +8,14 @@
[react-native.core :as rn]))
(def ^:private themes
{:container {:light {:background-color colors/white-opa-70}
:dark {:background-color colors/neutral-80-opa-70}}
:text {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:icon {:light {:color colors/neutral-100}
:dark {:color colors/white}}
:action-container {:light {:background-color :colors/neutral-80-opa-5}
:dark {:background-color :colors/white-opa-5}}})
{:container {:dark {:background-color colors/white-opa-70}
:light {:background-color colors/neutral-80-opa-70}}
:text {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:icon {:dark {:color colors/neutral-100}
:light {:color colors/white}}
:action-container {:dark {:background-color :colors/neutral-80-opa-5}
:light {:background-color :colors/white-opa-5}}})
(defn- merge-theme-style
[component-key styles]
@ -23,7 +23,9 @@
(defn toast-action-container
[{:keys [on-press style]} & children]
[rn/touchable-highlight {:on-press on-press}
[rn/touchable-highlight
{:on-press on-press
:underlay-color :transparent}
[into
[rn/view
{:style (merge
@ -40,7 +42,8 @@
(defn toast-undo-action
[duration on-press]
[toast-action-container {:on-press on-press}
[toast-action-container
{:on-press on-press :accessibility-label :toast-undo-action}
[rn/view {:style {:margin-right 5}}
[count-down-circle/circle-timer {:duration duration}]]
[text/text
@ -63,7 +66,10 @@
[rn/view {:style {:padding 2}} left]
[rn/view {:style {:padding 4 :flex 1}}
[text/text
{:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})}
{:size :paragraph-2
:weight :medium
:style (merge-theme-style :text {})
:accessibility-label :toast-content}
middle]]
(when right right)]])

View File

@ -101,4 +101,4 @@
[f]
(let [fn-ref (use-ref f)]
(oops/oset! fn-ref "current" f)
(use-effect-once (fn [] #((oops/oget fn-ref "current"))))))
(use-effect-once (fn [] (fn [] (oops/ocall! fn-ref "current"))))))

View File

@ -12,10 +12,13 @@
cancelAnimation
SlideInUp
SlideOutUp
LinearTransition)]
LinearTransition
enableLayoutAnimations)]
[clojure.string :as string]
[reagent.core :as reagent]))
(enableLayoutAnimations true)
;; Animations
(def slide-in-up-animation SlideInUp)
(def slide-out-up-animation SlideOutUp)

View File

@ -1,8 +1,8 @@
(ns status-im.chat.models.message-list
(:require ["functional-red-black-tree" :as rb-tree]
[status-im.constants :as constants]
[utils.re-frame :as rf]
[utils.datetime :as datetime]))
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
(defn- add-datemark
[{:keys [whisper-timestamp] :as msg}]
@ -20,6 +20,7 @@
from
outgoing
whisper-timestamp
deleted?
deleted-for-me?
albumize?]}]
(-> {:whisper-timestamp whisper-timestamp
@ -29,6 +30,7 @@
(or
(= constants/message-type-private-group-system-message
message-type)
deleted?
deleted-for-me?))
:clock-value clock-value
:type :message

View File

@ -26,6 +26,11 @@
(.damping 20)
(.stiffness 300)))
(defn toast
[id]
(let [toast-opts (rf/sub [:toasts/toast id])]
[quo/toast toast-opts]))
(defn container
[id]
(let [dismissed-locally? (reagent/atom false)
@ -35,13 +40,11 @@
(fn []
[:f>
(fn []
(let [toast-opts (rf/sub [:toasts/toast id])
duration (get toast-opts :duration 3000)
on-dismissed #((get toast-opts :on-dismissed identity) id)
translate-y (reanimated/use-shared-value 0)
(let [duration (or (rf/sub [:toasts/toast-cursor id :duration]) 3000)
on-dismissed #((or (rf/sub [:toasts/toast-cursor id :on-dismissed]) identity) id)
create-timer (fn []
(reset! timer (utils.utils/set-timeout #(do (close!) (on-dismissed))
duration)))
(reset! timer (utils.utils/set-timeout close! duration)))
translate-y (reanimated/use-shared-value 0)
pan
(->
(gesture/gesture-pan)
@ -84,7 +87,7 @@
:style (reanimated/apply-animations-to-style
{:transform [{:translateY translate-y}]}
style/each-toast-container)}
[quo/toast toast-opts]]]))])))
[toast id]]]))])))
(defn toasts
[]
@ -92,6 +95,4 @@
[into
[rn/view
{:style style/outmost-transparent-container}]
(->> toasts-ordered
reverse
(map (fn [id] ^{:key id} [container id])))]))
(map (fn [id] ^{:key id} [container id]) toasts-ordered)]))

View File

@ -1,6 +1,6 @@
(ns status-im2.contexts.chat.messages.content.deleted.view
(:require [quo2.core :as quo]
[i18n.i18n :as i18n]))
(:require [i18n.i18n :as i18n]
[quo2.core :as quo]))
(defn deleted-message
[{:keys [deleted? deleted-undoable-till timestamp-str deleted-for-me-undoable-till]}]

View File

@ -1,8 +1,11 @@
(ns status-im2.contexts.chat.messages.delete-message.events
(:require [status-im.chat.models.message-list :as message-list]
[utils.datetime :as datetime]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(:require
[i18n.i18n :as i18n]
[quo2.foundations.colors :as colors]
[status-im.chat.models.message-list :as message-list]
[taoensso.timbre :as log]
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
(defn- update-db-clear-undo-timer
[db chat-id message-id]
@ -20,8 +23,7 @@
[:messages chat-id message-id]
assoc
:deleted? true
:deleted-undoable-till (+ (datetime/timestamp)
undo-time-limit-ms))))
:deleted-undoable-till (+ (datetime/timestamp) undo-time-limit-ms))))
(defn- update-db-undo-locally
"Restore deleted message if called within timelimit"
@ -48,15 +50,43 @@
{:events [:chat.ui/delete-message]}
[{:keys [db]} {:keys [chat-id message-id]} undo-time-limit-ms]
(when (get-in db [:messages chat-id message-id])
(assoc
(message-list/rebuild-message-list
{:db (update-db-delete-locally db chat-id message-id undo-time-limit-ms)}
chat-id)
:utils/dispatch-later
[{:dispatch [:chat.ui/delete-message-and-send
{:chat-id chat-id
:message-id message-id}]
:ms undo-time-limit-ms}])))
;; all delete message toast are the same toast with id :delete-message-for-everyone
;; new delete operation will reset prev pending deletes' undo timelimit
;; undo will undo all pending deletes
;; all pending deletes are stored in toast
(let [existing-undo-toast (get-in db [:toasts :toasts :delete-message-for-everyone])
toast-count (inc (get existing-undo-toast :message-deleted-for-everyone-count 0))
existing-undos (-> existing-undo-toast
(get :message-deleted-for-everyone-undos [])
(conj {:message-id message-id :chat-id chat-id}))]
(assoc
(message-list/rebuild-message-list
{:db (reduce
;; sync all pending deletes' undo timelimit, extend to the latest one
(fn [db-acc {:keys [chat-id message-id]}]
(update-db-delete-locally db-acc chat-id message-id undo-time-limit-ms))
db
existing-undos)}
chat-id)
:dispatch-n
[[:toasts/close :delete-message-for-everyone]
[:toasts/upsert :delete-message-for-everyone
{:icon :info
:icon-color colors/danger-50-opa-40
:message-deleted-for-everyone-count toast-count
:message-deleted-for-everyone-undos existing-undos
:text (i18n/label-pluralize
toast-count
:t/message-deleted-for-everyone-count)
:duration undo-time-limit-ms
:undo-duration (/ undo-time-limit-ms 1000)
:undo-on-press #(do (rf/dispatch [:chat.ui/undo-all-delete-message])
(rf/dispatch [:toasts/close
:delete-message-for-everyone]))}]]
:utils/dispatch-later [{:dispatch [:chat.ui/delete-message-and-send
{:chat-id chat-id :message-id message-id}]
:ms undo-time-limit-ms}]))))
(rf/defn undo
{:events [:chat.ui/undo-delete-message]}
@ -66,22 +96,41 @@
{:db (update-db-undo-locally db chat-id message-id)}
chat-id)))
(rf/defn undo-all
{:events [:chat.ui/undo-all-delete-message]}
[{:keys [db]}]
(when-let [pending-undos (get-in db
[:toasts :toasts :delete-message-for-everyone
:message-deleted-for-everyone-undos])]
{:dispatch-n (mapv #(vector :chat.ui/undo-delete-message %) pending-undos)}))
(defn- check-before-delete-and-send
"make sure message alredy deleted? locally and undo timelimit has passed"
[db chat-id message-id]
(let [message (get-in db [:messages chat-id message-id])
{:keys [deleted? deleted-undoable-till]} message]
(and deleted?
deleted-undoable-till
(>= (datetime/timestamp) deleted-undoable-till))))
(rf/defn delete-and-send
{:events [:chat.ui/delete-message-and-send]}
[{:keys [db]} {:keys [message-id chat-id]}]
[{:keys [db]} {:keys [message-id chat-id]} force?]
(when-let [message (get-in db [:messages chat-id message-id])]
(cond-> {:db (update-db-clear-undo-timer db chat-id message-id)
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
:params [message-id]
:js-response true
:on-error #(log/error "failed to delete message "
{:message-id message-id :error %})
:on-success #(rf/dispatch [:sanitize-messages-and-process-response
%])}]}
(get-in db [:pin-messages chat-id message-id])
(assoc :dispatch
[:pin-message/send-pin-message
{:chat-id chat-id :message-id message-id :pinned false}]))))
(when (or force? (check-before-delete-and-send db chat-id message-id))
(cond-> {:db (update-db-clear-undo-timer db chat-id message-id)
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
:params [message-id]
:js-response true
:on-error #(log/error "failed to delete message "
{:message-id message-id :error %})
:on-success #(rf/dispatch
[:sanitize-messages-and-process-response
%])}]}
(get-in db [:pin-messages chat-id message-id])
(assoc :dispatch
[:pin-message/send-pin-message
{:chat-id chat-id :message-id message-id :pinned false}])))))
(defn- filter-pending-send-messages
"traverse all messages find not yet synced deleted? messages"
@ -96,7 +145,7 @@
{:events [:chat.ui/send-all-deleted-messages]}
[{:keys [db] :as cofx}]
(let [pending-send-messages (reduce-kv filter-pending-send-messages [] (:messages db))]
(apply rf/merge cofx (map delete-and-send pending-send-messages))))
(apply rf/merge cofx (map #(delete-and-send % true) pending-send-messages))))
(rf/defn delete-messages-localy
"Mark messages :deleted? localy in client"

View File

@ -15,11 +15,46 @@
(let [result-message (get-in (delete-message/delete {:db db} message 1000)
[:db :messages cid mid])]
(is (= (:id result-message) mid))
(is (true? (:deleted? result-message)))
(is (= (:deleted-undoable-till result-message) 1001))))
(is (true? (:deleted? result-message)) "mark message :deleted?")
(is (= (:deleted-undoable-till result-message) 1001) "set message undo timelimit")))
(testing "delete with pending deletes"
(let [db (-> db
(update-in [:messages cid "pending-delete-message"]
assoc
:deleted? true
:deleted-undoable-till 0
:whisper-timestamp 0)
(update-in [:toasts :toasts :delete-message-for-everyone]
assoc
:message-deleted-for-everyone-count 1
:message-deleted-for-everyone-undos [{:message-id
"pending-delete-message"
:chat-id cid}]))
effects (delete-message/delete {:db db} message 1000)]
(is (= (get-in effects [:db :messages cid mid :deleted-undoable-till])
(get-in effects [:db :messages cid "pending-delete-message" :deleted-undoable-till])
1001)
"sync all pending delete undo timelimit")
(let [upsert-toast (-> effects :dispatch-n second)]
(is (= (-> upsert-toast last :message-deleted-for-everyone-count) 2)
"+1 pending deletes")
(is
(and
(-> upsert-toast
last
:message-deleted-for-everyone-undos
first
:message-id
(= "pending-delete-message"))
(-> upsert-toast
last
:message-deleted-for-everyone-undos
second
:message-id
(= mid)))
"pending deletes are in order"))))
(testing "return nil if message not in db"
(is (= (delete-message/delete {:db {:messages []}} message 1000)
nil)))))))
(is (= (delete-message/delete {:db {:messages []}} message 1000) nil)))))))
(deftest undo-delete
(let [db {:messages {cid {mid {:id mid :whisper-timestamp 1}}}}
@ -30,14 +65,11 @@
[:messages cid mid]
assoc
:deleted? true
:deleted-undoable-till
(+ (datetime/timestamp) 1000))
result-message (get-in (delete-message/undo {:db db} message)
[:db :messages cid mid])]
:deleted-undoable-till (+ (datetime/timestamp) 1000))
result-message (get-in (delete-message/undo {:db db} message) [:db :messages cid mid])]
(is (= (:id result-message) mid))
(is (nil? (:deleted? result-message)))
(is (nil? (:deleted-undoable-till result-message)))))
(testing "remain deleted when undo after timelimit"
(let [db (update-in db
[:messages cid mid]
@ -48,47 +80,46 @@
(is (= (:id result-message) mid))
(is (nil? (:deleted-undoable-till result-message)))
(is (true? (:deleted? result-message)))))
(testing "return nil if message not in db"
(is (= (delete-message/undo {:db {:messages []}} message)
nil))))))
(is (= (delete-message/undo {:db {:messages []}} message) nil))))))
(deftest delete-and-send
(let [db {:messages {cid {mid {:id mid}}}}
(let [db {:messages {cid {mid {:id mid :deleted? true :deleted-undoable-till 0}}}}
message {:message-id mid :chat-id cid}]
(testing "delete and send"
(testing "dispatch right rpc call fx"
(let [expected-db {:messages {cid {mid {:id mid}}}}
effects (delete-message/delete-and-send {:db db} message)
(let [expected-db {:messages {cid {mid {:id mid :deleted? true}}}}
effects (delete-message/delete-and-send {:db db} message false)
result-db (:db effects)
rpc-calls (:json-rpc/call effects)]
(is (= result-db expected-db))
(is (= (count rpc-calls) 1))
(is (= (-> rpc-calls
first
:method)
"wakuext_deleteMessageAndSend"))
(is (= (-> rpc-calls
first
:params
count)
1))
(is (= (-> rpc-calls
first
:params
first)
mid))))
(is (= (-> rpc-calls first :method) "wakuext_deleteMessageAndSend"))
(is (= (-> rpc-calls first :params count) 1))
(is (= (-> rpc-calls first :params first) mid))))
(testing "clean undo timer"
(let [expected-db {:messages {cid {mid {:id mid}}}}
(let [expected-db {:messages {cid {mid {:id mid :deleted? true}}}}
effects (delete-message/delete-and-send
{:db (update-in db
[:messages cid mid
:deleted-undoable-till]
[:messages cid mid :deleted-undoable-till]
(constantly (datetime/timestamp)))}
message)
message
false)
result-db (:db effects)]
(is (= result-db expected-db))))
(testing "before deleted locally"
(let [effects (delete-message/delete-and-send
{:db (update-in db [:messages cid mid] dissoc :deleted?)}
message
false)]
(is (-> effects :db nil?) "not delete and send")))
(testing "before undo timelimit"
(with-redefs [datetime/timestamp (constantly 1)]
(let [effects (delete-message/delete-and-send
{:db (update-in db [:messages cid mid] assoc :deleted-undoable-till 2)}
message
false)]
(is (-> effects :db nil?)))))
(testing "return nil if message not in db"
(is (= (delete-message/delete-and-send {:db {:messages []}}
message)
(is (= (delete-message/delete-and-send {:db {:messages []}} message false)
nil))))))

View File

@ -1,8 +1,11 @@
(ns status-im2.contexts.chat.messages.delete-message-for-me.events
(:require [status-im.chat.models.message-list :as message-list]
[utils.datetime :as datetime]
[taoensso.timbre :as log]
[utils.re-frame :as rf]))
(:require
[i18n.i18n :as i18n]
[quo2.foundations.colors :as colors]
[status-im.chat.models.message-list :as message-list]
[taoensso.timbre :as log]
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
(defn- update-db-clear-undo-timer
[db chat-id message-id]
@ -42,15 +45,37 @@
{:events [:chat.ui/delete-message-for-me]}
[{:keys [db]} {:keys [chat-id message-id]} undo-time-limit-ms]
(when (get-in db [:messages chat-id message-id])
(assoc
(message-list/rebuild-message-list
{:db (update-db-delete-locally db chat-id message-id undo-time-limit-ms)}
chat-id)
:utils/dispatch-later
[{:dispatch [:chat.ui/delete-message-for-me-and-sync
{:chat-id chat-id
:message-id message-id}]
:ms undo-time-limit-ms}])))
(let [existing-undo-toast (get-in db [:toasts :toasts :delete-message-for-me])
toast-count (inc (get existing-undo-toast :message-deleted-for-me-count 0))
existing-undos (-> existing-undo-toast
(get :message-deleted-for-me-undos [])
(conj {:message-id message-id :chat-id chat-id}))]
(assoc
(message-list/rebuild-message-list
{:db (reduce
;; sync all pending deletes' undo timelimit, extend to the latest one
(fn [db-acc {:keys [message-id chat-id]}]
(update-db-delete-locally db-acc chat-id message-id undo-time-limit-ms))
db
existing-undos)}
chat-id)
:dispatch-n [[:toasts/close :delete-message-for-me]
[:toasts/upsert :delete-message-for-me
{:icon :info
:icon-color colors/danger-50-opa-40
:message-deleted-for-me-count toast-count
:message-deleted-for-me-undos existing-undos
:text (i18n/label-pluralize toast-count
:t/message-deleted-for-you-count)
:duration undo-time-limit-ms
:undo-duration (/ undo-time-limit-ms 1000)
:undo-on-press #(do (rf/dispatch
[:chat.ui/undo-all-delete-message-for-me])
(rf/dispatch [:toasts/close
:delete-message-for-me]))}]]
:utils/dispatch-later [{:dispatch [:chat.ui/delete-message-for-me-and-sync
{:chat-id chat-id :message-id message-id}]
:ms undo-time-limit-ms}]))))
(rf/defn undo
{:events [:chat.ui/undo-delete-message-for-me]}
@ -60,17 +85,37 @@
{:db (update-db-undo-locally db chat-id message-id)}
chat-id)))
(rf/defn undo-all
{:events [:chat.ui/undo-all-delete-message-for-me]}
[{:keys [db]}]
(when-let [pending-undos (get-in db
[:toasts :toasts :delete-message-for-me
:message-deleted-for-me-undos])]
{:dispatch-n (mapv #(vector :chat.ui/undo-delete-message-for-me %) pending-undos)}))
(defn- check-before-delete-and-sync
"Make sure message alredy deleted-for-me? locally and undo timelimit has passed"
[db chat-id message-id]
(let [message (get-in db [:messages chat-id message-id])
{:keys [deleted-for-me? deleted-for-me-undoable-till]} message]
(and deleted-for-me?
deleted-for-me-undoable-till
(>= (datetime/timestamp) deleted-for-me-undoable-till))))
(rf/defn delete-and-sync
{:events [:chat.ui/delete-message-for-me-and-sync]}
[{:keys [db]} {:keys [message-id chat-id]}]
(when (get-in db [:messages chat-id message-id])
{:db (update-db-clear-undo-timer db chat-id message-id)
:json-rpc/call [{:method "wakuext_deleteMessageForMeAndSync"
:params [chat-id message-id]
:js-response true
:on-error #(log/error "failed to delete message for me, message id: "
{:message-id message-id :error %})
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}))
[{:keys [db]} {:keys [message-id chat-id]} force?]
(when-let [message (get-in db [:messages chat-id message-id])]
(when (or force? (check-before-delete-and-sync db chat-id message-id))
{:db (update-db-clear-undo-timer db chat-id message-id)
:json-rpc/call [{:method "wakuext_deleteMessageForMeAndSync"
:params [chat-id message-id]
:js-response true
:on-error #(log/error
"failed to delete message for me, message id: "
{:message-id message-id :error %})
:on-success #(rf/dispatch [:sanitize-messages-and-process-response
%])}]})))
(defn- filter-pending-sync-messages
"traverse all messages find not yet synced deleted-for-me? messages"
@ -86,4 +131,4 @@
{:events [:chat.ui/sync-all-deleted-for-me-messages]}
[{:keys [db] :as cofx}]
(let [pending-sync-messages (reduce-kv filter-pending-sync-messages [] (:messages db))]
(apply rf/merge cofx (map delete-and-sync pending-sync-messages))))
(apply rf/merge cofx (map #(delete-and-sync % true) pending-sync-messages))))

View File

@ -18,6 +18,43 @@
(is (= (:id result-message) mid))
(is (true? (:deleted-for-me? result-message)))
(is (= (:deleted-for-me-undoable-till result-message) 1001))))
(testing "delete with pending deletes"
(let [db (-> db
(update-in [:messages cid "pending-delete-message"]
assoc
:deleted-for-me? true
:deleted-for-me-undoable-till 0
:whisper-timestamp 0)
(update-in [:toasts :toasts :delete-message-for-me]
assoc
:message-deleted-for-me-count 1
:message-deleted-for-me-undos [{:message-id
"pending-delete-message"
:chat-id cid}]))
effects (delete-message-for-me/delete {:db db} message 1000)]
(is (= (get-in effects [:db :messages cid mid :deleted-for-me-undoable-till])
(get-in effects
[:db :messages cid "pending-delete-message" :deleted-for-me-undoable-till])
1001)
"sync all pending delete undo timelimit")
(let [upsert-toast (-> effects :dispatch-n second)]
(is (= (-> upsert-toast last :message-deleted-for-me-count) 2)
"+1 pending deletes")
(is
(and
(-> upsert-toast
last
:message-deleted-for-me-undos
first
:message-id
(= "pending-delete-message"))
(-> upsert-toast
last
:message-deleted-for-me-undos
second
:message-id
(= mid)))
"pending deletes are in order"))))
(testing "return nil if message not in db"
(is (= (delete-message-for-me/delete {:db {:messages []}} message 1000)
nil)))))))
@ -56,46 +93,42 @@
nil))))))
(deftest delete-for-me-and-sync
(let [db {:messages {cid {mid {:id mid}}}}
(let [db {:messages {cid {mid {:id mid :deleted-for-me? true :deleted-for-me-undoable-till 0}}}}
message {:message-id mid :chat-id cid}]
(testing "delete for me and sync"
(testing "dispatch right rpc call"
(let [expected-db {:messages {cid {mid {:id mid}}}}
effects (delete-message-for-me/delete-and-sync {:db db} message)
(let [expected-db {:messages {cid {mid {:id mid :deleted-for-me? true}}}}
effects (delete-message-for-me/delete-and-sync {:db db} message false)
result-db (:db effects)
rpc-calls (:json-rpc/call effects)]
(is (= result-db expected-db))
(is (= (count rpc-calls) 1))
(is (= (-> rpc-calls
first
:method)
"wakuext_deleteMessageForMeAndSync"))
(is (= (-> rpc-calls
first
:params
count)
2))
(is (= (-> rpc-calls
first
:params
first)
cid))
(is (= (-> rpc-calls
first
:params
second)
mid))))
(is (= (-> rpc-calls first :method) "wakuext_deleteMessageForMeAndSync"))
(is (= (-> rpc-calls first :params count) 2))
(is (= (-> rpc-calls first :params first) cid))
(is (= (-> rpc-calls first :params second) mid))))
(testing "clean undo timer"
(let [expected-db {:messages {cid {mid {:id mid}}}}
(let [expected-db {:messages {cid {mid {:id mid :deleted-for-me? true}}}}
effects (delete-message-for-me/delete-and-sync
{:db (update-in db
[:messages cid mid
:deleted-for-me-undoable-till]
[:messages cid mid :deleted-for-me-undoable-till]
(constantly (datetime/timestamp)))}
message)
message
false)
result-db (:db effects)]
(is (= result-db expected-db))))
(testing "before deleted locally"
(let [effects (delete-message-for-me/delete-and-sync
{:db (update-in db [:messages cid mid] dissoc :deleted-for-me?)}
message
false)]
(is (-> effects :db nil?) "not delete and send")))
(testing "before undo timelimit"
(with-redefs [datetime/timestamp (constantly 1)]
(let [effects (delete-message-for-me/delete-and-sync
{:db (update-in db [:messages cid mid] assoc :deleted-for-me-undoable-till 2)}
message
false)]
(is (-> effects :db nil?)))))
(testing "return nil if message not in db"
(is (= (delete-message-for-me/delete-and-sync {:db {:messages []}}
message)
nil))))))
(is (= (delete-message-for-me/delete-and-sync {:db {:messages []}} message false) nil))))))

View File

@ -34,6 +34,7 @@
:chat/spam-messages-frequency 0
:chats-home-list #{}
:home-items-show-number 20
:toasts {:ordered '() :toasts {}}
:tooltips {}
:dimensions/window (rn/get-window)
:registry {}

View File

@ -6,3 +6,9 @@
:<- [:toasts]
(fn [toasts [_ toast-id]]
(get-in toasts [:toasts toast-id])))
(re-frame/reg-sub
:toasts/toast-cursor
:<- [:toasts]
(fn [toasts [_ toast-id & cursor]]
(get-in toasts (into [:toasts toast-id] cursor))))

View File

@ -878,7 +878,15 @@
"message": "Message",
"message-deleted": "Message deleted",
"message-deleted-for-everyone": "Message deleted for everyone",
"message-deleted-for-everyone-count": {
"one": "1 message deleted for everyone",
"other": "{{count}} messages deleted for everyone"
},
"message-deleted-for-you": "Message deleted for you",
"message-deleted-for-you-count": {
"one": "1 message deleted for you",
"other": "{{count}} messages deleted for you"
},
"message-not-sent": "Message not sent",
"message-options-cancel": "Cancel",
"message-reply": "Reply",