Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
866ba63ab7 | ||
|
|
ee5dcb3683 | ||
|
|
995d120d94 | ||
|
|
cbad7f4c87 |
+17
-3
@@ -1,4 +1,4 @@
|
||||
# Guidelines
|
||||
# Code Style Guidelines
|
||||
|
||||
>The goal of this document is to help all contributors (core and external) to
|
||||
>write code in _unison_ and help establish good practices that serve the Status
|
||||
@@ -77,7 +77,21 @@ Joshua Comeau.
|
||||
[rn/view {:style {:padding-horizontal 20}}]
|
||||
```
|
||||
|
||||
#### Styles def vs defn
|
||||
### Don't prepend booleans with is-
|
||||
|
||||
It is a common practice in JavaScript and other languages to prepend boolean variable names with `is-*`.
|
||||
In ClojureScript it is common practice to suffix boolean variable names with a `?`.
|
||||
There is no need for both of these and so it is preferable to stick with the latter.
|
||||
|
||||
```clojure
|
||||
;; bad
|
||||
(let [is-open? true] ...)
|
||||
|
||||
;; good
|
||||
(let [open? true] ...)
|
||||
```
|
||||
|
||||
### Styles def vs defn
|
||||
|
||||
Always use `def` over `defn`, unless the style relies on dynamic values, such as
|
||||
deref'ed atoms.
|
||||
@@ -170,7 +184,7 @@ Use the simple `defn` to declare components. Don't use `utils.views/defview` and
|
||||
(do-something window-width)))
|
||||
```
|
||||
|
||||
#### Use `[]` instead of `()` in Reagent components
|
||||
### Use `[]` instead of `()` in Reagent components
|
||||
|
||||
- The `()` version [does NOT work with Form-2 and
|
||||
Form-3](https://github.com/reagent-project/reagent/blob/master/doc/UsingSquareBracketsInsteadOfParens.md#a-further-significant-why)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.component-spec
|
||||
(:require [quo2.components.drawers.drawer-buttons.view :as drawer-buttons]
|
||||
[react-native.core :as rn]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(h/describe "drawer-buttons"
|
||||
(h/test "the top heading and subheading render"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(-> (js/expect (h/get-by-text "top-heading"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (h/get-by-text "top-sub-heading"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "the bottom heading and subheading render"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(-> (js/expect (h/get-by-text "bottom-heading"))
|
||||
(.toBeTruthy))
|
||||
(-> (js/expect (h/get-by-text "bottom-sub-heading"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
|
||||
(h/test "it clicks the top card"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:on-press event
|
||||
:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(h/fire-event :press (h/get-by-text "top-heading"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled))))
|
||||
|
||||
(h/test "it clicks the bottom card"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:on-press event
|
||||
:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
:bottom-sub-heading])
|
||||
(h/fire-event :press (h/get-by-text "bottom-heading"))
|
||||
(-> (js/expect event)
|
||||
(.toHaveBeenCalled))))
|
||||
|
||||
(h/test "the top card child renders with a render prop"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
[rn/text :top-render-fn]
|
||||
:bottom-sub-heading])
|
||||
(-> (js/expect (h/get-by-text "top-render-fn"))
|
||||
(.toBeTruthy)))
|
||||
|
||||
(h/test "the bottom card child renders with a render prop"
|
||||
(h/render [drawer-buttons/view
|
||||
{:top-card {:heading :top-heading}
|
||||
:bottom-card {:heading :bottom-heading}}
|
||||
:top-sub-heading
|
||||
[rn/text :bottom-render-fn]])
|
||||
(-> (js/expect (h/get-by-text "bottom-render-fn"))
|
||||
(.toBeTruthy))))
|
||||
@@ -0,0 +1,48 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.style
|
||||
(:require [quo2.foundations.colors :as colors]))
|
||||
|
||||
(def outer-container {:height 216})
|
||||
|
||||
(def top-card
|
||||
{:flex 1
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-radius 20
|
||||
:background-color colors/neutral-80})
|
||||
|
||||
(def bottom-card
|
||||
{:position :absolute
|
||||
:top 80
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:padding-vertical 12
|
||||
:padding-horizontal 20
|
||||
:border-radius 20
|
||||
:background-color (colors/alpha colors/white 0.05)})
|
||||
|
||||
(def bottom-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between})
|
||||
|
||||
(def bottom-icon
|
||||
{:border-radius 40
|
||||
:border-width 1
|
||||
:margin-left 24
|
||||
:height 28
|
||||
:width 28
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:border-color (colors/alpha colors/white 0.05)})
|
||||
|
||||
(def bottom-text
|
||||
{:flex 1
|
||||
:color (colors/alpha colors/white 0.7)})
|
||||
|
||||
(def top-text
|
||||
{:color (colors/alpha colors/white 0.7)})
|
||||
|
||||
(defn heading-text
|
||||
[gap]
|
||||
{:color colors/white
|
||||
:margin-bottom gap})
|
||||
@@ -0,0 +1,80 @@
|
||||
(ns quo2.components.drawers.drawer-buttons.view
|
||||
(:require [react-native.core :as rn]
|
||||
[quo2.components.icon :as icon]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.components.drawers.drawer-buttons.style :as style]))
|
||||
|
||||
(defn render-bottom
|
||||
[children]
|
||||
[rn/view {:style style/bottom-container}
|
||||
children
|
||||
[rn/view
|
||||
{:style style/bottom-icon}
|
||||
[icon/icon :arrow-right
|
||||
{:color colors/white
|
||||
:size 20}]]])
|
||||
|
||||
(defn label? [el] (or (string? el) (keyword? el)))
|
||||
|
||||
(defn render-children-bottom
|
||||
[children]
|
||||
(if (label? children)
|
||||
[render-bottom
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style style/bottom-text
|
||||
:weight :semi-bold}
|
||||
children]]
|
||||
[render-bottom children]))
|
||||
|
||||
(defn render-children-top
|
||||
[children]
|
||||
(if (label? children)
|
||||
[text/text
|
||||
{:size :paragraph-2
|
||||
:style style/top-text
|
||||
:weight :semi-bold}
|
||||
children]
|
||||
children))
|
||||
|
||||
(defn card
|
||||
[{:keys [on-press style heading gap top?]} children]
|
||||
[rn/touchable-highlight
|
||||
{:on-press on-press
|
||||
:border-radius 20
|
||||
:style style
|
||||
:underlay-color (:background-color style)}
|
||||
[rn/view {}
|
||||
[text/text
|
||||
{:size :heading-1
|
||||
:style (style/heading-text gap)
|
||||
:weight :semi-bold}
|
||||
heading]
|
||||
(if top?
|
||||
[render-children-top children]
|
||||
[render-children-bottom children])]])
|
||||
|
||||
(defn view
|
||||
"[view opts]
|
||||
opts
|
||||
{:container-style style-object
|
||||
:top-card { :on-press event
|
||||
:heading string}
|
||||
:bottom-card { :on-press event
|
||||
:heading string}}
|
||||
child-1 string, keyword or hiccup
|
||||
child-2 string, keyword or hiccup
|
||||
"
|
||||
[{:keys [container-style top-card bottom-card]} child-1 child-2]
|
||||
[rn/view
|
||||
{:style (merge container-style style/outer-container)}
|
||||
[card
|
||||
(merge {:gap 4
|
||||
:top? true
|
||||
:style style/top-card}
|
||||
top-card) child-1]
|
||||
[card
|
||||
(merge {:style style/bottom-card
|
||||
:gap 20}
|
||||
bottom-card) child-2]])
|
||||
@@ -173,7 +173,7 @@
|
||||
(utils/truncate-str (:info content) 24)])]]]])
|
||||
|
||||
(defn system-message
|
||||
[{:keys [type style non-pressable? animate-landing? labels] :as message}]
|
||||
[{:keys [type style non-pressable? animate-landing? labels on-long-press] :as message}]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [sv-color (reanimated/use-shared-value
|
||||
@@ -186,16 +186,17 @@
|
||||
:linear
|
||||
1000))
|
||||
[reanimated/touchable-opacity
|
||||
{:on-press #(when-not non-pressable?
|
||||
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:background-color sv-color}
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:padding-vertical 9
|
||||
:padding-horizontal 11
|
||||
:background-color sv-color}
|
||||
style))}
|
||||
{:on-press #(when-not non-pressable?
|
||||
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
|
||||
:on-long-press on-long-press
|
||||
:style (reanimated/apply-animations-to-style
|
||||
{:background-color sv-color}
|
||||
(merge
|
||||
{:flex-direction :row
|
||||
:flex 1
|
||||
:border-radius 16
|
||||
:padding-vertical 9
|
||||
:padding-horizontal 11
|
||||
:background-color sv-color}
|
||||
style))}
|
||||
[sm-render message labels]]))])
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
quo2.components.dividers.divider-label
|
||||
quo2.components.dividers.new-messages
|
||||
quo2.components.drawers.action-drawers.view
|
||||
quo2.components.drawers.drawer-buttons.view
|
||||
quo2.components.drawers.permission-context.view
|
||||
quo2.components.dropdowns.dropdown
|
||||
quo2.components.header
|
||||
@@ -126,6 +127,7 @@
|
||||
|
||||
;;;; DRAWERS
|
||||
(def action-drawer quo2.components.drawers.action-drawers.view/action-drawer)
|
||||
(def drawer-buttons quo2.components.drawers.drawer-buttons.view/view)
|
||||
(def permission-context quo2.components.drawers.permission-context.view/view)
|
||||
|
||||
;;;; LIST ITEMS
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[quo2.components.counter.--tests--.counter-component-spec]
|
||||
[quo2.components.dividers.--tests--.divider-label-component-spec]
|
||||
[quo2.components.drawers.action-drawers.component-spec]
|
||||
[quo2.components.drawers.drawer-buttons.component-spec]
|
||||
[quo2.components.drawers.permission-context.component-spec]
|
||||
[quo2.components.markdown.--tests--.text-component-spec]
|
||||
[quo2.components.onboarding.small-option-card.component-spec]
|
||||
|
||||
@@ -66,15 +66,16 @@
|
||||
(assoc contact' :two-names (contact-two-names contact' true))))
|
||||
|
||||
(defn displayed-name
|
||||
"Use preferred name, name or alias in that order"
|
||||
[{:keys [name preferred-name alias public-key ens-verified]}]
|
||||
"Use preferred name, display-name, name or alias in that order"
|
||||
[{:keys [name display-name preferred-name alias public-key ens-verified]}]
|
||||
(let [ens-name (or preferred-name
|
||||
display-name
|
||||
name)]
|
||||
;; Preferred name is our own otherwise we make sure it's verified
|
||||
(if (or preferred-name (and ens-verified name))
|
||||
(let [username (stateofus/username ens-name)]
|
||||
(or username ens-name))
|
||||
(or alias (gfycat/generate-gfy public-key)))))
|
||||
(or display-name alias (gfycat/generate-gfy public-key)))))
|
||||
|
||||
(defn contact-by-identity
|
||||
[contacts identity]
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
[from username current-public-key]
|
||||
(or (and (= from current-public-key)
|
||||
(i18n/label :t/You))
|
||||
(format-author username)))
|
||||
(when username (format-author username))))
|
||||
|
||||
(defn reply-deleted-message
|
||||
[]
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
[quo.react-native :as rn]
|
||||
[quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[quo2.foundations.typography :as typography]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im.react-native.resources :as resources]
|
||||
[status-im.ui.components.fast-image :as fast-image]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.chat.image.preview.views :as preview]
|
||||
[status-im.ui.screens.chat.message.audio :as message.audio]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||
@@ -21,14 +19,14 @@
|
||||
[status-im.ui.screens.chat.utils :as chat.utils]
|
||||
[status-im.ui.screens.communities.icon :as communities.icon]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
|
||||
[status-im2.config :as config]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im.utils.utils :as utils]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]
|
||||
[status-im2.contexts.chat.messages.delete-message-for-me.events]
|
||||
[status-im2.contexts.chat.messages.delete-message.events]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.core :as quo])
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf])
|
||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||
|
||||
(defn system-text?
|
||||
@@ -230,58 +228,6 @@
|
||||
(re-frame/dispatch [:pin-message/show-pin-limit-modal chat-id]))
|
||||
(re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned (not pinned))]))))
|
||||
|
||||
(defn on-long-press-fn
|
||||
[on-long-press
|
||||
{:keys [pinned message-pin-enabled outgoing edit-enabled show-input? community?
|
||||
can-delete-message-for-everyone?]
|
||||
:as message} content]
|
||||
(on-long-press
|
||||
(concat
|
||||
(when (and outgoing edit-enabled)
|
||||
[{:type :main
|
||||
:on-press #(re-frame/dispatch [:chat.ui/edit-message message])
|
||||
:label (i18n/label :t/edit-message)
|
||||
:icon :i/edit
|
||||
:id :edit}])
|
||||
(when show-input?
|
||||
[{:type :main
|
||||
:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||
:label (i18n/label :t/message-reply)
|
||||
:icon :i/reply
|
||||
:id :reply}])
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
:id :copy}]
|
||||
(when message-pin-enabled
|
||||
[{:type :main
|
||||
:on-press #(pin-message message)
|
||||
:label (i18n/label (if pinned
|
||||
(if community? :t/unpin-from-channel :t/unpin-from-chat)
|
||||
(if community? :t/pin-to-channel :t/pin-to-chat)))
|
||||
:icon :i/pin
|
||||
:id (if pinned :unpin :pin)}])
|
||||
(when-not pinned
|
||||
[{:type :danger
|
||||
:on-press (fn []
|
||||
(re-frame/dispatch
|
||||
[:chat.ui/delete-message-for-me message
|
||||
config/delete-message-for-me-undo-time-limit-ms]))
|
||||
:label (i18n/label :t/delete-for-me)
|
||||
:icon :i/delete
|
||||
:id :delete-for-me}])
|
||||
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
|
||||
[{:type :danger
|
||||
:on-press #(re-frame/dispatch [:chat.ui/delete-message
|
||||
message
|
||||
config/delete-message-undo-time-limit-ms])
|
||||
:label (i18n/label :t/delete-for-everyone)
|
||||
:icon :i/delete
|
||||
:id :delete-for-all}]))))
|
||||
|
||||
;; STATUS ? whats that ?
|
||||
(defmethod ->message constants/content-type-status
|
||||
[{:keys [content content-type]}]
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
(def communities-enabled? (enabled? (get-config :COMMUNITIES_ENABLED "0")))
|
||||
(def database-management-enabled? (enabled? (get-config :DATABASE_MANAGEMENT_ENABLED "0")))
|
||||
(def debug-webview? (enabled? (get-config :DEBUG_WEBVIEW "0")))
|
||||
(def delete-message-enabled? (enabled? (get-config :DELETE_MESSAGE_ENABLED "0")))
|
||||
(def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1")))
|
||||
(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0")))
|
||||
(def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0")))
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
{:type :negative :label (i18n/label :t/declined)}
|
||||
nil)}
|
||||
(case (:contact-request-state message)
|
||||
constants/contact-request-state-mutual
|
||||
constants/contact-request-message-state-pending
|
||||
{:button-1 {:label (i18n/label :t/decline)
|
||||
:accessibility-label :decline-contact-request
|
||||
:type :danger
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im2.contexts.chat.messages.content.deleted.view
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.chat.messages.drawers.view :as drawers]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -20,8 +21,20 @@
|
||||
[quo/text {:style {:margin-left 4} :size :paragraph-2}
|
||||
(i18n/label :t/deleted-this-message)]])
|
||||
|
||||
(defn- compute-on-long-press-fn
|
||||
[{:keys [deleted? pinned] :as message}
|
||||
{:keys [message-pin-enabled] :as context}]
|
||||
;; only show drawer for user who has the permission to unpin messages
|
||||
(when (and pinned deleted? message-pin-enabled)
|
||||
(fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (drawers/reactions-and-actions message
|
||||
context)}]))))
|
||||
|
||||
(defn deleted-by-message
|
||||
[{:keys [deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]}]
|
||||
[{:keys [deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]}
|
||||
on-long-press-fn]
|
||||
(let [;; deleted message with nil deleted-by is deleted by (:from message)
|
||||
display-name (first (rf/sub [:contacts/contact-two-names-by-identity (or deleted-by from)]))
|
||||
contact (rf/sub [:contacts/contact-by-address (or deleted-by from)])
|
||||
@@ -32,21 +45,25 @@
|
||||
:timestamp-str timestamp-str
|
||||
:child [user-xxx-deleted-this-message
|
||||
{:display-name display-name :profile-picture photo-path}]
|
||||
:non-pressable? true
|
||||
:on-long-press on-long-press-fn
|
||||
:non-pressable? (if on-long-press-fn false true)
|
||||
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}]))
|
||||
|
||||
(defn deleted-message
|
||||
[{:keys [deleted? deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]
|
||||
:as message}]
|
||||
(let [pub-key (rf/sub [:multiaccount/public-key])
|
||||
deleted-by-me? (= (or deleted-by from) pub-key)]
|
||||
(if (not deleted-by-me?)
|
||||
[deleted-by-message message]
|
||||
:as message}
|
||||
context]
|
||||
(let [pub-key (rf/sub [:multiaccount/public-key])
|
||||
deleted-by-me? (= (or deleted-by from) pub-key)
|
||||
on-long-press-fn (compute-on-long-press-fn message context)]
|
||||
(if-not deleted-by-me?
|
||||
[deleted-by-message message on-long-press-fn]
|
||||
[quo/system-message
|
||||
{:type :deleted
|
||||
:label (if deleted? :message-deleted :message-deleted-for-you)
|
||||
:labels {:message-deleted (i18n/label :t/message-deleted-for-everyone)
|
||||
:message-deleted-for-you (i18n/label :t/message-deleted-for-you)}
|
||||
:on-long-press on-long-press-fn
|
||||
:timestamp-str timestamp-str
|
||||
:non-pressable? true
|
||||
:non-pressable? (if on-long-press-fn false true)
|
||||
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}])))
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns status-im2.contexts.chat.messages.delete-message.events
|
||||
(:require
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- update-db-clear-undo-timer
|
||||
@@ -47,6 +47,26 @@
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
(update-in db [:messages chat-id message-id] assoc :deleted? true :deleted-by deleted-by)))
|
||||
|
||||
(defn- should-and-able-to-unpin-to-be-deleted-message
|
||||
"check
|
||||
1. if the to-be deleted message is pinned
|
||||
2. if user has the permission to unpin message in current chat"
|
||||
[db {:keys [chat-id message-id]}]
|
||||
(let [{:keys [group-chat chat-id public? community-id admins]} (get-in db [:chats chat-id])
|
||||
community (get-in db [:communities community-id])
|
||||
community-admin? (get community :admin false)
|
||||
pub-key (get-in db [:multiaccount :public-key])
|
||||
group-admin? (get admins pub-key)
|
||||
message-pin-enabled (and (not public?)
|
||||
(or (not group-chat)
|
||||
(and group-chat
|
||||
(or group-admin?
|
||||
community-admin?))))
|
||||
pinned (get-in db
|
||||
[:pin-messages chat-id
|
||||
message-id])]
|
||||
(and pinned message-pin-enabled)))
|
||||
|
||||
(rf/defn delete
|
||||
"Delete message now locally and broadcast after undo time limit timeout"
|
||||
{:events [:chat.ui/delete-message]}
|
||||
@@ -56,14 +76,22 @@
|
||||
;; new delete operation will reset prev pending deletes' undo timelimit
|
||||
;; undo will undo all pending deletes
|
||||
;; all pending deletes are stored in toast
|
||||
(let [pub-key (get-in db [:multiaccount :public-key])
|
||||
(let [unpin? (should-and-able-to-unpin-to-be-deleted-message
|
||||
db
|
||||
{:chat-id chat-id :message-id message-id})
|
||||
|
||||
pub-key (get-in db [:multiaccount :public-key])
|
||||
|
||||
;; compute deleted by
|
||||
message-from (get message :from)
|
||||
deleted-by (when (not= pub-key message-from) pub-key)
|
||||
|
||||
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}))]
|
||||
existing-undos
|
||||
(-> existing-undo-toast
|
||||
(get :message-deleted-for-everyone-undos [])
|
||||
(conj {:message-id message-id :chat-id chat-id :should-pin-back? unpin?}))]
|
||||
(assoc
|
||||
(message-list/rebuild-message-list
|
||||
{:db (reduce
|
||||
@@ -89,7 +117,10 @@
|
||||
: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]))}]]
|
||||
:delete-message-for-everyone]))}]
|
||||
(when unpin?
|
||||
[:pin-message/send-pin-message-locally
|
||||
{:chat-id chat-id :message-id message-id :pinned false}])]
|
||||
:utils/dispatch-later (mapv (fn [{:keys [chat-id message-id]}]
|
||||
{:dispatch [:chat.ui/delete-message-and-send
|
||||
{:chat-id chat-id :message-id message-id}]
|
||||
@@ -98,11 +129,16 @@
|
||||
|
||||
(rf/defn undo
|
||||
{:events [:chat.ui/undo-delete-message]}
|
||||
[{:keys [db]} {:keys [chat-id message-id]}]
|
||||
[{:keys [db]} {:keys [chat-id message-id should-pin-back?]}]
|
||||
(when (get-in db [:messages chat-id message-id])
|
||||
(message-list/rebuild-message-list
|
||||
{:db (update-db-undo-locally db chat-id message-id)}
|
||||
chat-id)))
|
||||
(let [effects (message-list/rebuild-message-list
|
||||
{:db (update-db-undo-locally db chat-id message-id)}
|
||||
chat-id)
|
||||
message (get-in effects [:db :messages chat-id message-id])]
|
||||
(cond-> effects
|
||||
should-pin-back?
|
||||
(assoc :dispatch
|
||||
[:pin-message/send-pin-message-locally (assoc message :pinned true)])))))
|
||||
|
||||
(rf/defn undo-all
|
||||
{:events [:chat.ui/undo-all-delete-message]}
|
||||
@@ -126,19 +162,32 @@
|
||||
[{: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-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}])))))
|
||||
(let [unpin-locally?
|
||||
;; this only check against local client data
|
||||
;; generally msg is already unpinned at delete locally phase when user
|
||||
;; has unpin permission
|
||||
;;
|
||||
;; will be true only if
|
||||
;; 1. admin delete an unpinned msg
|
||||
;; 2. another admin pin the msg within the undo time limit
|
||||
;; 3. msg finally deleted
|
||||
(should-and-able-to-unpin-to-be-deleted-message db
|
||||
{:chat-id chat-id
|
||||
:message-id message-id})]
|
||||
{: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
|
||||
%])}]
|
||||
:dispatch [:pin-message/send-pin-message
|
||||
{:chat-id chat-id
|
||||
:message-id message-id
|
||||
:pinned false
|
||||
:remote-only? (not unpin-locally?)}]}))))
|
||||
|
||||
(defn- filter-pending-send-messages
|
||||
"traverse all messages find not yet synced deleted? messages"
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
(ns status-im2.contexts.chat.messages.drawers.view
|
||||
(:require [react-native.core :as rn]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im2.config :as config]
|
||||
(:require [quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
|
||||
[status-im2.common.not-implemented :as not-implemented]))
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn pin-message
|
||||
[{:keys [chat-id pinned pinned-by] :as message-data}]
|
||||
@@ -21,37 +20,39 @@
|
||||
(assoc message-data :pinned message-not-pinned?)]))))
|
||||
|
||||
(defn get-actions
|
||||
[{:keys [outgoing content pinned-by outgoing-status] :as message-data}
|
||||
{:keys [edit-enabled show-input? can-delete-message-for-everyone? community? message-pin-enabled]}]
|
||||
[{:keys [outgoing content pinned outgoing-status deleted? deleted-for-me?] :as message-data}
|
||||
{:keys [edit-enabled show-input? community? can-delete-message-for-everyone?
|
||||
message-pin-enabled group-chat group-admin?]}]
|
||||
(concat
|
||||
(when (and outgoing edit-enabled)
|
||||
(when (and outgoing edit-enabled (not (or deleted? deleted-for-me?)))
|
||||
[{:type :main
|
||||
:on-press #(rf/dispatch [:chat.ui/edit-message message-data])
|
||||
:label (i18n/label :t/edit-message)
|
||||
:icon :i/edit
|
||||
:id :edit}])
|
||||
(when (and show-input? (not= outgoing-status :sending))
|
||||
(when (and show-input? (not= outgoing-status :sending) (not (or deleted? deleted-for-me?)))
|
||||
[{:type :main
|
||||
:on-press #(rf/dispatch [:chat.ui/reply-to-message message-data])
|
||||
:label (i18n/label :t/message-reply)
|
||||
:icon :i/reply
|
||||
:id :reply}])
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
:id :copy}]
|
||||
(when-not (or deleted? deleted-for-me?)
|
||||
[{:type :main
|
||||
:on-press #(react/copy-to-clipboard
|
||||
(components.reply/get-quoted-text-with-mentions
|
||||
(get content :parsed-text)))
|
||||
:label (i18n/label :t/copy-text)
|
||||
:icon :i/copy
|
||||
:id :copy}])
|
||||
(when message-pin-enabled
|
||||
[{:type :main
|
||||
:on-press #(pin-message message-data)
|
||||
:label (i18n/label (if pinned-by
|
||||
:label (i18n/label (if pinned
|
||||
(if community? :t/unpin-from-channel :t/unpin-from-chat)
|
||||
(if community? :t/pin-to-channel :t/pin-to-chat)))
|
||||
:icon :i/pin
|
||||
:id (if pinned-by :unpin :pin)}])
|
||||
(when-not pinned-by
|
||||
:id (if pinned :unpin :pin)}])
|
||||
(when-not (or pinned deleted? deleted-for-me?)
|
||||
[{:type :danger
|
||||
:on-press (fn []
|
||||
(rf/dispatch
|
||||
@@ -62,7 +63,13 @@
|
||||
:label (i18n/label :t/delete-for-me)
|
||||
:icon :i/delete
|
||||
:id :delete-for-me}])
|
||||
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
|
||||
(when (cond
|
||||
deleted? false
|
||||
deleted-for-me? false
|
||||
outgoing true
|
||||
community? can-delete-message-for-everyone?
|
||||
group-chat group-admin?
|
||||
:else false)
|
||||
[{:type :danger
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
@@ -119,7 +126,8 @@
|
||||
icon]])))]))
|
||||
|
||||
(defn reactions-and-actions
|
||||
[{:keys [message-id outgoing-status] :as message-data} {:keys [chat-id] :as context}]
|
||||
[{:keys [message-id outgoing-status deleted? deleted-for-me?] :as message-data}
|
||||
{:keys [chat-id] :as context}]
|
||||
(fn []
|
||||
(let [actions (get-actions message-data context)
|
||||
main-actions (filter #(= (:type %) :main) actions)
|
||||
@@ -127,7 +135,7 @@
|
||||
admin-actions (filter #(= (:type %) :admin) actions)]
|
||||
[:<>
|
||||
;; REACTIONS
|
||||
(when (not= outgoing-status :sending)
|
||||
(when (and (not= outgoing-status :sending) (not (or deleted? deleted-for-me?)))
|
||||
[reactions {:chat-id chat-id :message-id message-id}])
|
||||
|
||||
;; MAIN ACTIONS
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
(ns status-im2.contexts.chat.messages.list.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[oops.core :as oops]
|
||||
(:require [oops.core :as oops]
|
||||
[quo2.core :as quo]
|
||||
[react-native.background-timer :as background-timer]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[status-im.ui.screens.chat.group :as chat.group]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[status-im.ui.screens.chat.group :as chat.group]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[status-im2.contexts.chat.messages.list.state :as state]
|
||||
[status-im.ui.screens.chat.message.gap :as message.gap]))
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defonce messages-list-ref (atom nil))
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
(if platform/low-device? 700 200))))
|
||||
|
||||
(defn get-render-data
|
||||
"compute data used to render message list, including pinned message list and message list in chats"
|
||||
[{:keys [group-chat chat-id public? community-id admins space-keeper show-input? edit-enabled
|
||||
in-pinned-view?]}]
|
||||
(let [current-public-key (rf/sub [:multiaccount/public-key])
|
||||
@@ -82,6 +83,7 @@
|
||||
(or group-admin?
|
||||
community-admin?))))]
|
||||
{:group-chat group-chat
|
||||
:group-admin? group-admin?
|
||||
:public? public?
|
||||
:community? (not (nil? community-id))
|
||||
:current-public-key current-public-key
|
||||
@@ -123,7 +125,7 @@
|
||||
[message.gap/gap message-data]]
|
||||
[rn/view {:padding-horizontal 8}
|
||||
(if (or deleted? deleted-for-me?)
|
||||
[content.deleted/deleted-message message-data]
|
||||
[content.deleted/deleted-message message-data context]
|
||||
[message/message-with-reactions message-data context])]))])
|
||||
|
||||
(defn messages-list
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.banner.view
|
||||
(:require [quo2.core :as quo]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn banner
|
||||
[chat-id]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list chat-id])
|
||||
latest-pin-text (->> pinned-messages
|
||||
last
|
||||
:content
|
||||
:text)
|
||||
pins-count (count pinned-messages)]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list
|
||||
chat-id])
|
||||
latest-pinned-message (last pinned-messages)
|
||||
latest-pin-text (get-in latest-pinned-message [:content :text])
|
||||
{:keys [deleted? deleted-for-me?]} latest-pinned-message
|
||||
pins-count (count pinned-messages)
|
||||
|
||||
latest-pin-text
|
||||
(cond deleted? (i18n/label :t/message-deleted-for-everyone)
|
||||
deleted-for-me? (i18n/label :t/message-deleted-for-you)
|
||||
:else latest-pin-text)]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.events
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||
[status-im2.common.toasts.events :as toasts]
|
||||
[status-im2.constants :as constants]
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.data-store.pin-messages :as data-store.pin-messages]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[utils.re-frame :as rf]
|
||||
[taoensso.timbre :as log]))
|
||||
[status-im2.common.toasts.events :as toasts]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn handle-failed-loading-pin-messages
|
||||
{:events [:pin-message/failed-loading-pin-messages]}
|
||||
@@ -59,23 +59,34 @@
|
||||
(assoc-in [:pin-message-lists chat-id]
|
||||
(message-list/add-many nil (vals all-messages))))}))))
|
||||
|
||||
(rf/defn send-pin-message
|
||||
"Pin message, rebuild pinned messages list"
|
||||
{:events [:pin-message/send-pin-message]}
|
||||
|
||||
(rf/defn send-pin-message-locally
|
||||
"Pin message, rebuild pinned messages list locally"
|
||||
{:events [:pin-message/send-pin-message-locally]}
|
||||
[{:keys [db] :as cofx} {:keys [chat-id message-id pinned] :as pin-message}]
|
||||
(let [current-public-key (get-in db [:multiaccount :public-key])
|
||||
message (merge pin-message {:pinned-by current-public-key})
|
||||
preferred-name (get-in db [:multiaccount :preferred-name])]
|
||||
(let [current-public-key (get-in db [:multiaccount :public-key])
|
||||
message (merge pin-message {:pinned-by current-public-key})
|
||||
pin-message-lists-exist? (some? (get-in db [:pin-message-lists chat-id]))]
|
||||
(rf/merge cofx
|
||||
{:db (cond-> db
|
||||
pinned
|
||||
(->
|
||||
(update-in [:pin-message-lists chat-id] message-list/add message)
|
||||
(assoc-in [:pin-messages chat-id message-id] message))
|
||||
(not pinned)
|
||||
(and (not pinned) pin-message-lists-exist?)
|
||||
(->
|
||||
(update-in [:pin-message-lists chat-id] message-list/remove-message pin-message)
|
||||
(update-in [:pin-messages chat-id] dissoc message-id)))}
|
||||
(update-in [:pin-messages chat-id] dissoc message-id)))})))
|
||||
|
||||
(rf/defn send-pin-message
|
||||
"Pin message, rebuild pinned messages list"
|
||||
{:events [:pin-message/send-pin-message]}
|
||||
[{:keys [db] :as cofx} {:keys [chat-id message-id pinned remote-only?] :as pin-message}]
|
||||
(let [current-public-key (get-in db [:multiaccount :public-key])
|
||||
message (merge pin-message {:pinned-by current-public-key})
|
||||
preferred-name (get-in db [:multiaccount :preferred-name])]
|
||||
(rf/merge cofx
|
||||
(when-not remote-only? (send-pin-message-locally pin-message))
|
||||
(data-store.pin-messages/send-pin-message {:chat-id (pin-message :chat-id)
|
||||
:message_id (pin-message :message-id)
|
||||
:pinned (pin-message :pinned)})
|
||||
|
||||
@@ -1,37 +1,33 @@
|
||||
(ns status-im2.contexts.chat.messages.pin.list.view
|
||||
(:require [utils.i18n :as i18n]
|
||||
[quo2.core :as quo]
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||
[status-im2.contexts.chat.messages.content.view :as message]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.datetime :as datetime]))
|
||||
[status-im2.contexts.chat.messages.list.view :as list.view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def list-key-fn #(or (:message-id %) (:value %)))
|
||||
|
||||
(defn message-render-fn
|
||||
[{:keys [whisper-timestamp] :as message}
|
||||
_
|
||||
{:keys [group-chat public? community? current-public-key show-input? edit-enabled]}]
|
||||
[{:keys [deleted? deleted-for-me?] :as message} _ _ context]
|
||||
;; TODO (flexsurfer) probably we don't want reactions here
|
||||
[message/message-with-reactions
|
||||
message
|
||||
{:group-chat group-chat
|
||||
:public? public?
|
||||
:community? community?
|
||||
:current-public-key current-public-key
|
||||
:show-input? show-input?
|
||||
:message-pin-enabled true
|
||||
:in-pinned-view? true
|
||||
:pinned true
|
||||
:timestamp-str (datetime/timestamp->time whisper-timestamp)
|
||||
:edit-enabled edit-enabled}])
|
||||
(if (or deleted? deleted-for-me?)
|
||||
[content.deleted/deleted-message message context]
|
||||
[message/message-with-reactions message context]))
|
||||
|
||||
(defn pinned-messages-list
|
||||
[chat-id]
|
||||
(let [pinned-messages (vec (vals (rf/sub [:chats/pinned chat-id])))
|
||||
current-chat (rf/sub [:chat-by-id chat-id])
|
||||
community (rf/sub [:communities/community (:community-id current-chat)])]
|
||||
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list
|
||||
chat-id])
|
||||
current-chat (rf/sub [:chat-by-id chat-id])
|
||||
|
||||
{:keys [group-chat chat-id public? community-id admins]}
|
||||
current-chat
|
||||
|
||||
community (rf/sub [:communities/community
|
||||
community-id])]
|
||||
[rn/view {:accessibility-label :pinned-messages-list}
|
||||
;; TODO (flexsurfer) this should be a component in quo2
|
||||
;; https://github.com/status-im/status-mobile/issues/14529
|
||||
@@ -62,10 +58,18 @@
|
||||
(str "# " (:chat-name current-chat))]])]
|
||||
(if (> (count pinned-messages) 0)
|
||||
[rn/flat-list
|
||||
{:data pinned-messages
|
||||
:render-fn message-render-fn
|
||||
:key-fn list-key-fn
|
||||
:separator quo/separator}]
|
||||
{:data pinned-messages
|
||||
:render-data (list.view/get-render-data {:group-chat group-chat
|
||||
:chat-id chat-id
|
||||
:public? public?
|
||||
:community-id community-id
|
||||
:show-input? false
|
||||
:admins admins
|
||||
:edit-enabled true
|
||||
:in-pinned-view? true})
|
||||
:render-fn message-render-fn
|
||||
:key-fn list-key-fn
|
||||
:separator quo/separator}]
|
||||
[rn/view
|
||||
{:style {:justify-content :center
|
||||
:align-items :center
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
(ns status-im2.contexts.quo-preview.drawers.drawer-buttons
|
||||
(:require [quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Top Heading"
|
||||
:key :top-heading
|
||||
:type :text}
|
||||
{:label "Top Sub heading"
|
||||
:key :top-sub-heading
|
||||
:type :text}
|
||||
{:label "Bottom heading"
|
||||
:key :bottom-heading
|
||||
:type :text}])
|
||||
|
||||
(defn text-with-link
|
||||
[]
|
||||
[quo/text
|
||||
{:style {:flex 1
|
||||
:flex-wrap :wrap}}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:flex 1
|
||||
:color (colors/alpha colors/white 0.7)}
|
||||
:weight :semi-bold}
|
||||
"By continuing you accept our "]
|
||||
[quo/text
|
||||
{:on-press #(js/alert "Terms of use clicked")
|
||||
:size :paragraph-2
|
||||
:style {:flex 1
|
||||
:color colors/white}
|
||||
:weight :semi-bold}
|
||||
"Terms of Use"]])
|
||||
|
||||
(defn render-drawer-buttons
|
||||
[state]
|
||||
[rn/view
|
||||
{:height 300
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95)}
|
||||
[quo/drawer-buttons
|
||||
{:container-style {:margin-left 40
|
||||
:margin-right 24}
|
||||
:top-card {:on-press #(js/alert "top card clicked")
|
||||
:heading (:top-heading @state)}
|
||||
:bottom-card {:on-press #(js/alert "bottom card clicked")
|
||||
:heading (:bottom-heading @state)}}
|
||||
(:top-sub-heading @state) [text-with-link]]])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [state (reagent/atom {:top-heading "Sign in "
|
||||
:top-sub-heading "You already use Status"
|
||||
:bottom-heading "I'm new to status"})]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 400}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view {:padding-vertical 60}
|
||||
[render-drawer-buttons state]]]])))
|
||||
|
||||
(defn preview-drawer-buttons
|
||||
[]
|
||||
[rn/view
|
||||
{:background-color (colors/theme-colors colors/white colors/neutral-95)
|
||||
:flex 1}
|
||||
[rn/flat-list
|
||||
{:flex 1
|
||||
:nestedScrollEnabled true
|
||||
:keyboardShouldPersistTaps :always
|
||||
:header [cool-preview]
|
||||
:key-fn :id}]])
|
||||
@@ -29,7 +29,8 @@
|
||||
[status-im2.contexts.quo-preview.dividers.date :as divider-date]
|
||||
[status-im2.contexts.quo-preview.dividers.divider-label :as divider-label]
|
||||
[status-im2.contexts.quo-preview.dividers.new-messages :as new-messages]
|
||||
[status-im2.contexts.quo-preview.drawers.action-drawers :as drawers]
|
||||
[status-im2.contexts.quo-preview.drawers.action-drawers :as action-drawers]
|
||||
[status-im2.contexts.quo-preview.drawers.drawer-buttons :as drawer-buttons]
|
||||
[status-im2.contexts.quo-preview.drawers.permission-drawers :as permission-drawers]
|
||||
[status-im2.contexts.quo-preview.dropdowns.dropdown :as dropdown]
|
||||
[status-im2.contexts.quo-preview.foundations.shadows :as shadows]
|
||||
@@ -138,7 +139,10 @@
|
||||
:component divider-date/preview-divider-date}]
|
||||
:drawers [{:name :action-drawers
|
||||
:insets {:top false}
|
||||
:component drawers/preview-action-drawers}
|
||||
:component action-drawers/preview-action-drawers}
|
||||
{:name :drawer-buttons
|
||||
:insets {:top false}
|
||||
:component drawer-buttons/preview-drawer-buttons}
|
||||
{:name :permission-drawers
|
||||
:insets {:top false}
|
||||
:component permission-drawers/preview-permission-drawers}]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns status-im2.subs.chat.messages
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[status-im2.contexts.chat.messages.list.events :as models.message-list]
|
||||
[status-im.chat.models.reactions :as models.reactions]
|
||||
[utils.datetime :as datetime]
|
||||
[status-im2.constants :as constants]))
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.messages.list.events :as models.message-list]
|
||||
[utils.datetime :as datetime]))
|
||||
|
||||
(defn intersperse-datemark
|
||||
"Reduce step which expects the input list of messages to be sorted by clock value.
|
||||
@@ -24,7 +24,7 @@
|
||||
:acc (conj acc msg)}
|
||||
|
||||
(and (not= last-datemark datemark) ; not the same day
|
||||
(< whisper-timestamp last-timestamp)) ; not out-of-order
|
||||
(< whisper-timestamp last-timestamp)) ; not out-of-order
|
||||
{:last-timestamp whisper-timestamp
|
||||
:last-datemark datemark
|
||||
:acc (conj acc
|
||||
@@ -32,7 +32,7 @@
|
||||
:type :datemark}
|
||||
msg)}
|
||||
:else
|
||||
{:last-timestamp (min whisper-timestamp last-timestamp) ; use last datemark
|
||||
{:last-timestamp (min whisper-timestamp last-timestamp) ; use last datemark
|
||||
:last-datemark last-datemark
|
||||
:acc (conj acc (assoc msg :datemark last-datemark))}))
|
||||
|
||||
@@ -158,14 +158,18 @@
|
||||
[(re-frame/subscribe [:messages/pin-messages])
|
||||
(re-frame/subscribe [:chats/chat-messages chat-id])])
|
||||
(fn [[pin-messages messages] [_ chat-id]]
|
||||
(let [pin-messages (get pin-messages chat-id {})]
|
||||
(reduce-kv (fn [acc message-id message]
|
||||
(let [{:keys [deleted? deleted-for-me?]} (get messages message-id)]
|
||||
(if (or deleted? deleted-for-me?)
|
||||
acc
|
||||
(assoc acc message-id message))))
|
||||
{}
|
||||
pin-messages))))
|
||||
(let [pinned-messages (get pin-messages chat-id {})]
|
||||
(reduce-kv
|
||||
(fn [pinned-messages pinned-message-id pinned-message]
|
||||
(let [{:keys [deleted? deleted-for-me? deleted-by]} (get messages pinned-message-id)
|
||||
pinned-message (assoc pinned-message
|
||||
:deleted? deleted?
|
||||
:deleted-for-me? deleted-for-me?
|
||||
:deleted-by deleted-by
|
||||
:pinned true)]
|
||||
(assoc pinned-messages pinned-message-id pinned-message)))
|
||||
pinned-messages
|
||||
pinned-messages))))
|
||||
|
||||
;; local messages will not have a :pinned-at key until user navigates away and to
|
||||
;; chat screen. For this reason we want to retain order of local messages with :pinned-at nil
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns status-im2.subs.chat.messages-test
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[re-frame.db :as rf-db]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.subs.chat.messages :as messages]
|
||||
[test-helpers.unit :as h]
|
||||
[utils.re-frame :as rf]
|
||||
[re-frame.db :as rf-db]
|
||||
[status-im2.constants :as constants]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def messages-state
|
||||
[{:message-id "0x111" :album-id "abc" :albumize? true}
|
||||
@@ -109,51 +109,91 @@
|
||||
[sub-name]
|
||||
(testing "It sorts three messages with pinned-at property"
|
||||
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state)
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 1000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user}]
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 1000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}]
|
||||
(rf/sub [sub-name :0xChat]))))
|
||||
(testing "It sorts messages from backend with pinned-at property and 1 new local pinned message"
|
||||
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-1-new-local-message)
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user}]
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}]
|
||||
(rf/sub [sub-name :0xChat]))))
|
||||
(testing "It sorts messages from backend with pinned-at property and 2 new local pinned messages"
|
||||
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-2-new-local-messages)
|
||||
(is (= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x4
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user}]
|
||||
(rf/sub [sub-name :0xChat])))))
|
||||
|
||||
(is
|
||||
(= [{:chat-id :0xChat
|
||||
:message-id :0x1
|
||||
:pinned-at 2000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x2
|
||||
:pinned-at 3000
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x3
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}
|
||||
{:chat-id :0xChat
|
||||
:message-id :0x4
|
||||
:pinned-at nil
|
||||
:pinned-by :test-user
|
||||
:pinned true
|
||||
:deleted? nil
|
||||
:deleted-for-me? nil
|
||||
:deleted-by nil}]
|
||||
(rf/sub [sub-name :0xChat])))))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.131.4",
|
||||
"commit-sha1": "0b2f0ef28923d2bc3c9051d038e7c512bfdc741f",
|
||||
"src-sha256": "1pql2dkzwny5yv8ggi2dikfc6dbp64cyxjnm8k0nyl2wfs8ax2cg"
|
||||
"version": "v0.131.7",
|
||||
"commit-sha1": "97579ee36393955705e51f364fce3ab40d1d6921",
|
||||
"src-sha256": "0b15kv6f1f1935lljl4bmvmndsr5smb9kxazx0fxz6xfsyjd1x5i"
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ module.exports = {
|
||||
},
|
||||
"testTimeout": 60000,
|
||||
"transformIgnorePatterns": [
|
||||
"/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions)/).*/"
|
||||
"/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions|@react-native-community/blur)/).*/"
|
||||
],
|
||||
"globals": {
|
||||
"__TEST__": true
|
||||
|
||||
Reference in New Issue
Block a user