parent
a8d392e4de
commit
a39e0f6fbd
|
@ -4,18 +4,15 @@
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]))
|
[react-native.core :as rn]))
|
||||||
|
|
||||||
(defn date
|
(defn date [value]
|
||||||
[value]
|
[rn/view {:margin-vertical 8
|
||||||
[rn/view
|
:padding-right 20
|
||||||
{:margin-vertical 16
|
:padding-left 60}
|
||||||
:padding-right 8
|
[text/text {:weight :medium
|
||||||
:padding-left 62}
|
:accessibility-label :divider-date-text
|
||||||
[text/text
|
:size :label
|
||||||
{:weight :medium
|
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||||
:accessibility-label :divider-date-text
|
:text-transform :capitalize
|
||||||
:size :label
|
:margin-bottom 4}}
|
||||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
|
||||||
:text-transform :capitalize
|
|
||||||
:margin-bottom 4}}
|
|
||||||
value]
|
value]
|
||||||
[separator/separator]])
|
[separator/separator]])
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
(def container
|
(def container
|
||||||
{:flex 1
|
{:flex 1
|
||||||
:flex-wrap :wrap
|
:flex-wrap :wrap
|
||||||
:height 18
|
|
||||||
:flex-direction :row
|
:flex-direction :row
|
||||||
:align-items :center})
|
:align-items :center})
|
||||||
|
|
||||||
|
@ -40,4 +39,4 @@
|
||||||
(defn time-text
|
(defn time-text
|
||||||
[ens?]
|
[ens?]
|
||||||
{:color colors/neutral-50
|
{:color colors/neutral-50
|
||||||
:margin-left (if ens? 8 4)})
|
:margin-left (if ens? 8 4)})
|
||||||
|
|
|
@ -95,5 +95,6 @@
|
||||||
[text/text
|
[text/text
|
||||||
{:monospace true
|
{:monospace true
|
||||||
:size :paragraph-2
|
:size :paragraph-2
|
||||||
|
:accessibility-label :message-timestamp
|
||||||
:style (style/time-text ens?)}
|
:style (style/time-text ens?)}
|
||||||
time-str]]))])
|
time-str]]))])
|
||||||
|
|
|
@ -146,12 +146,11 @@
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style (assoc centrify-style
|
{:style (assoc centrify-style
|
||||||
:flex-direction :row
|
:flex-direction :row
|
||||||
:flex 1
|
|
||||||
:justify-content :flex-end)}
|
:justify-content :flex-end)}
|
||||||
(let [last-icon-index (-> right-section-buttons count dec)]
|
(let [last-icon-index (-> right-section-buttons count dec)]
|
||||||
(map-indexed (fn [index {:keys [icon on-press type] :or {type :grey}}]
|
(map-indexed (fn [index {:keys [icon on-press type style] :or {type :grey}}]
|
||||||
^{:key index}
|
^{:key index}
|
||||||
[rn/view {:style {:margin-right (if (not= index last-icon-index) 8 0)}}
|
[rn/view {:style (merge {:margin-right (if (not= index last-icon-index) 8 0)} style)}
|
||||||
[button/button {:on-press on-press :icon true :type type :size 32}
|
[button/button {:on-press on-press :icon true :type type :size 32}
|
||||||
icon]])
|
icon]])
|
||||||
right-section-buttons))])
|
right-section-buttons))])
|
||||||
|
|
|
@ -1,31 +1,18 @@
|
||||||
(ns quo2.components.reactions.reaction
|
(ns quo2.components.reactions.reaction
|
||||||
(:require [quo2.components.icon :as icons]
|
(:require [quo2.components.icon :as icons]
|
||||||
[quo2.components.markdown.text :as quo2.text]
|
[quo2.components.markdown.text :as text]
|
||||||
|
[quo2.components.reactions.style :as style]
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[quo2.theme :as theme]
|
[quo2.theme :as theme]
|
||||||
[react-native.core :as rn]))
|
[react-native.core :as rn]))
|
||||||
|
|
||||||
(def reaction-styling
|
(defn add-reaction
|
||||||
{:flex-direction :row
|
|
||||||
:justify-content :center
|
|
||||||
:align-items :center
|
|
||||||
:padding-horizontal 8
|
|
||||||
:border-radius 8
|
|
||||||
:height 24})
|
|
||||||
|
|
||||||
(defn open-reactions-menu
|
|
||||||
[{:keys [on-press]}]
|
[{:keys [on-press]}]
|
||||||
(let [dark? (theme/dark?)]
|
(let [dark? (theme/dark?)]
|
||||||
[rn/touchable-opacity
|
[rn/touchable-opacity
|
||||||
{:on-press on-press
|
{:on-press on-press
|
||||||
:accessibility-label :emoji-reaction-add
|
:accessibility-label :emoji-reaction-add
|
||||||
:style (merge reaction-styling
|
:style (style/add-reaction)}
|
||||||
{:padding-horizontal 9
|
|
||||||
:border-width 1
|
|
||||||
:margin-top 5
|
|
||||||
:border-color (if dark?
|
|
||||||
colors/neutral-70
|
|
||||||
colors/neutral-30)})}
|
|
||||||
[icons/icon :i/add
|
[icons/icon :i/add
|
||||||
{:size 20
|
{:size 20
|
||||||
:color (if dark?
|
:color (if dark?
|
||||||
|
@ -35,41 +22,17 @@
|
||||||
(defn reaction
|
(defn reaction
|
||||||
"Add your emoji as a param here"
|
"Add your emoji as a param here"
|
||||||
[{:keys [emoji clicks neutral? on-press accessibility-label]}]
|
[{:keys [emoji clicks neutral? on-press accessibility-label]}]
|
||||||
(let [dark? (theme/dark?)
|
(let [numeric-value (int clicks)]
|
||||||
text-color (if dark?
|
|
||||||
colors/white
|
|
||||||
colors/neutral-100)
|
|
||||||
numeric-value (int clicks)
|
|
||||||
clicks-positive? (pos? numeric-value)]
|
|
||||||
[rn/touchable-opacity
|
[rn/touchable-opacity
|
||||||
{:on-press on-press
|
{:on-press on-press
|
||||||
:accessibility-label accessibility-label
|
:accessibility-label accessibility-label
|
||||||
:style (merge reaction-styling
|
:style (style/reaction neutral?)}
|
||||||
(cond->
|
[icons/icon emoji {:no-color true
|
||||||
{:background-color
|
:size 16}]
|
||||||
(if dark?
|
[text/text {:size :paragraph-2
|
||||||
(if neutral?
|
:weight :semi-bold
|
||||||
colors/neutral-70
|
:flex-direction :row
|
||||||
:transparent)
|
:align-items :center
|
||||||
(if neutral?
|
:justify-content :center}
|
||||||
colors/neutral-30
|
(when (pos? numeric-value)
|
||||||
:transparent))}
|
(str " " numeric-value))]]))
|
||||||
(and dark? (not neutral?))
|
|
||||||
(assoc :border-color colors/neutral-70
|
|
||||||
:border-width 1)
|
|
||||||
(and (not dark?) (not neutral?))
|
|
||||||
(assoc :border-color colors/neutral-30
|
|
||||||
:border-width 1)))}
|
|
||||||
[icons/icon emoji
|
|
||||||
{:no-color true
|
|
||||||
:size 16}]
|
|
||||||
[quo2.text/text
|
|
||||||
{:size :paragraph-2
|
|
||||||
:weight :semi-bold
|
|
||||||
:color text-color
|
|
||||||
:flex-direction :row
|
|
||||||
:align-items :center
|
|
||||||
:justify-content :center}
|
|
||||||
(if clicks-positive?
|
|
||||||
(str " " numeric-value)
|
|
||||||
"")]]))
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
(ns quo2.components.reactions.style
|
||||||
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
|
|
||||||
|
(def reaction-styling
|
||||||
|
{:flex-direction :row
|
||||||
|
:justify-content :center
|
||||||
|
:align-items :center
|
||||||
|
:padding-horizontal 8
|
||||||
|
:border-radius 8
|
||||||
|
:height 24})
|
||||||
|
|
||||||
|
(defn add-reaction []
|
||||||
|
(merge reaction-styling
|
||||||
|
{:padding-horizontal 9
|
||||||
|
:border-width 1
|
||||||
|
:border-color (colors/theme-colors colors/neutral-30 colors/neutral-70)}))
|
||||||
|
|
||||||
|
(defn reaction [neutral?]
|
||||||
|
(merge reaction-styling
|
||||||
|
(cond-> {:background-color (colors/theme-colors (if neutral?
|
||||||
|
colors/neutral-30
|
||||||
|
:transparent)
|
||||||
|
(if neutral?
|
||||||
|
colors/neutral-70
|
||||||
|
:transparent))}
|
||||||
|
(and (colors/dark?) (not neutral?))
|
||||||
|
(assoc :border-color colors/neutral-70
|
||||||
|
:border-width 1)
|
||||||
|
(and (not (colors/dark?)) (not neutral?))
|
||||||
|
(assoc :border-color colors/neutral-30
|
||||||
|
:border-width 1))))
|
|
@ -29,6 +29,7 @@
|
||||||
quo2.components.list-items.preview-list
|
quo2.components.list-items.preview-list
|
||||||
quo2.components.loaders.skeleton
|
quo2.components.loaders.skeleton
|
||||||
quo2.components.markdown.text
|
quo2.components.markdown.text
|
||||||
|
quo2.components.messages.author.view
|
||||||
quo2.components.messages.gap
|
quo2.components.messages.gap
|
||||||
quo2.components.messages.system-message
|
quo2.components.messages.system-message
|
||||||
quo2.components.navigation.floating-shell-button
|
quo2.components.navigation.floating-shell-button
|
||||||
|
@ -64,6 +65,7 @@
|
||||||
(def gap quo2.components.messages.gap/gap)
|
(def gap quo2.components.messages.gap/gap)
|
||||||
(def system-message quo2.components.messages.system-message/system-message)
|
(def system-message quo2.components.messages.system-message/system-message)
|
||||||
(def reaction quo2.components.reactions.reaction/reaction)
|
(def reaction quo2.components.reactions.reaction/reaction)
|
||||||
|
(def add-reaction quo2.components.reactions.reaction/add-reaction)
|
||||||
(def tags quo2.components.tags.tags/tags)
|
(def tags quo2.components.tags.tags/tags)
|
||||||
(def user-avatar-tag quo2.components.tags.context-tags/user-avatar-tag)
|
(def user-avatar-tag quo2.components.tags.context-tags/user-avatar-tag)
|
||||||
(def context-tag quo2.components.tags.context-tags/context-tag)
|
(def context-tag quo2.components.tags.context-tags/context-tag)
|
||||||
|
@ -77,6 +79,7 @@
|
||||||
(def disclaimer quo2.components.selectors.disclaimer/disclaimer)
|
(def disclaimer quo2.components.selectors.disclaimer/disclaimer)
|
||||||
(def checkbox quo2.components.selectors.selectors/checkbox)
|
(def checkbox quo2.components.selectors.selectors/checkbox)
|
||||||
(def skeleton quo2.components.loaders.skeleton/skeleton)
|
(def skeleton quo2.components.loaders.skeleton/skeleton)
|
||||||
|
(def author quo2.components.messages.author.view/author)
|
||||||
|
|
||||||
;;;; AVATAR
|
;;;; AVATAR
|
||||||
(def account-avatar quo2.components.avatars.account-avatar/account-avatar)
|
(def account-avatar quo2.components.avatars.account-avatar/account-avatar)
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
[status-im.utils.universal-links.utils :as links]
|
[status-im.utils.universal-links.utils :as links]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.debounce :as debounce]))
|
[utils.debounce :as debounce]
|
||||||
|
[utils.security.core :as security]))
|
||||||
|
|
||||||
(fx/defn update-browser-option
|
(fx/defn update-browser-option
|
||||||
[{:keys [db]} option-key option-value]
|
[{:keys [db]} option-key option-value]
|
||||||
|
@ -226,9 +227,10 @@
|
||||||
(fx/defn handle-message-link
|
(fx/defn handle-message-link
|
||||||
{:events [:browser.ui/message-link-pressed]}
|
{:events [:browser.ui/message-link-pressed]}
|
||||||
[_ link]
|
[_ link]
|
||||||
(if (links/universal-link? link)
|
(when (security/safe-link? link)
|
||||||
{:dispatch [:universal-links/handle-url link]}
|
(if (links/universal-link? link)
|
||||||
{:browser/show-browser-selection link}))
|
{:dispatch [:universal-links/handle-url link]}
|
||||||
|
{:browser/show-browser-selection link})))
|
||||||
|
|
||||||
(fx/defn update-browser-on-nav-change
|
(fx/defn update-browser-on-nav-change
|
||||||
[cofx url error?]
|
[cofx url error?]
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message-for-me.events :as delete-for-me]
|
[status-im2.contexts.chat.messages.delete-message-for-me.events :as delete-for-me]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
|
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
|
||||||
[status-im2.navigation.events :as navigation]
|
[status-im2.navigation.events :as navigation]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
|
|
|
@ -600,7 +600,7 @@
|
||||||
{:keys [new-text at-idxs start end] :as state}
|
{:keys [new-text at-idxs start end] :as state}
|
||||||
(get-in db [:chats/mentions chat-id :mentions])
|
(get-in db [:chats/mentions chat-id :mentions])
|
||||||
new-text (or new-text text)]
|
new-text (or new-text text)]
|
||||||
(log/info "[mentions] calculate suggestions"
|
(log/debug "[mentions] calculate suggestions"
|
||||||
"state"
|
"state"
|
||||||
state)
|
state)
|
||||||
(if-not (seq at-idxs)
|
(if-not (seq at-idxs)
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
[status-im.utils.gfycat.core :as gfycat]
|
[status-im.utils.gfycat.core :as gfycat]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]
|
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
(defn- message-loaded?
|
(defn- message-loaded?
|
||||||
|
|
|
@ -73,13 +73,13 @@
|
||||||
|
|
||||||
|
|
||||||
(fx/defn send-emoji-reaction
|
(fx/defn send-emoji-reaction
|
||||||
{:events [::send-emoji-reaction]}
|
{:events [:models.reactions/send-emoji-reaction]}
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
||||||
(message.protocol/send-reaction cofx
|
(message.protocol/send-reaction cofx
|
||||||
(update reaction :chat-id #(or % current-chat-id))))
|
(update reaction :chat-id #(or % current-chat-id))))
|
||||||
|
|
||||||
(fx/defn send-retract-emoji-reaction
|
(fx/defn send-retract-emoji-reaction
|
||||||
{:events [::send-emoji-reaction-retraction]}
|
{:events [:models.reactions/send-emoji-reaction-retraction]}
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
||||||
(message.protocol/send-retract-reaction cofx
|
(message.protocol/send-retract-reaction cofx
|
||||||
(update reaction :chat-id #(or % current-chat-id))))
|
(update reaction :chat-id #(or % current-chat-id))))
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im.chat.models.images :as images]
|
[status-im.chat.models.images :as images]
|
||||||
[status-im.chat.models.reactions :as models.reactions]
|
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.react-native.resources :as resources]
|
[status-im.react-native.resources :as resources]
|
||||||
|
@ -827,11 +826,11 @@
|
||||||
:picker-on-close (fn []
|
:picker-on-close (fn []
|
||||||
(space-keeper false))
|
(space-keeper false))
|
||||||
:send-emoji (fn [{:keys [emoji-id]}]
|
:send-emoji (fn [{:keys [emoji-id]}]
|
||||||
(re-frame/dispatch [::models.reactions/send-emoji-reaction
|
(re-frame/dispatch [:models.reactions/send-emoji-reaction
|
||||||
{:message-id (:message-id message)
|
{:message-id (:message-id message)
|
||||||
:emoji-id emoji-id}]))
|
:emoji-id emoji-id}]))
|
||||||
:retract-emoji (fn [{:keys [emoji-id emoji-reaction-id]}]
|
:retract-emoji (fn [{:keys [emoji-id emoji-reaction-id]}]
|
||||||
(re-frame/dispatch [::models.reactions/send-emoji-reaction-retraction
|
(re-frame/dispatch [:models.reactions/send-emoji-reaction-retraction
|
||||||
{:message-id (:message-id message)
|
{:message-id (:message-id message)
|
||||||
:emoji-id emoji-id
|
:emoji-id emoji-id
|
||||||
:emoji-reaction-id emoji-reaction-id}]))
|
:emoji-reaction-id emoji-reaction-id}]))
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
(ns status-im.ui.screens.chat.message.reactions-row
|
|
||||||
(:require [quo.react-native :as rn]
|
|
||||||
[quo2.components.reactions.reaction :as quo2.reaction]
|
|
||||||
[status-im.constants :as constants]
|
|
||||||
[status-im.ui.screens.chat.message.styles :as styles]))
|
|
||||||
|
|
||||||
(def default-reaction-margin-top 5)
|
|
||||||
|
|
||||||
(def text-reaction-margin-top -3)
|
|
||||||
|
|
||||||
(defn message-reactions
|
|
||||||
[{:keys [content-type]} reactions timeline on-emoji-press on-open]
|
|
||||||
(when (seq reactions)
|
|
||||||
[rn/view
|
|
||||||
{:style (styles/reactions-row
|
|
||||||
timeline
|
|
||||||
(if (= content-type constants/content-type-text)
|
|
||||||
text-reaction-margin-top
|
|
||||||
default-reaction-margin-top))}
|
|
||||||
(for [{:keys [own emoji-id quantity] :as emoji-reaction} reactions]
|
|
||||||
^{:key (str emoji-reaction)}
|
|
||||||
[rn/view {:style {:margin-right 6 :margin-top 5}}
|
|
||||||
[quo2.reaction/reaction
|
|
||||||
{:emoji (get constants/reactions emoji-id)
|
|
||||||
:neutral? own
|
|
||||||
:clicks quantity
|
|
||||||
:on-press #(on-emoji-press emoji-id)
|
|
||||||
:accessibility-label (str "emoji-reaction-" emoji-id)}]])
|
|
||||||
;; on-press won't work until we integrate Message Context Drawer
|
|
||||||
[quo2.reaction/open-reactions-menu (when @on-open {:on-press @on-open})]]))
|
|
|
@ -1,7 +1,6 @@
|
||||||
(ns status-im.ui.screens.chat.styles.message.message
|
(ns status-im.ui.screens.chat.styles.message.message
|
||||||
(:require [quo.design-system.colors :as colors]
|
(:require [quo.design-system.colors :as colors]
|
||||||
[quo2.foundations.colors :as quo2.colors]
|
[quo2.foundations.colors :as quo2.colors]
|
||||||
[quo2.foundations.typography :as typography]
|
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.screens.chat.styles.photos :as photos]))
|
[status-im.ui.screens.chat.styles.photos :as photos]))
|
||||||
|
@ -51,7 +50,9 @@
|
||||||
[]
|
[]
|
||||||
{:font-size 10
|
{:font-size 10
|
||||||
:line-height 10
|
:line-height 10
|
||||||
:color colors/gray})
|
:border-color :red
|
||||||
|
:border-width 1
|
||||||
|
:color :red})
|
||||||
|
|
||||||
(defn audio-message-timestamp-text
|
(defn audio-message-timestamp-text
|
||||||
[]
|
[]
|
||||||
|
@ -104,14 +105,7 @@
|
||||||
{:flex-direction :row
|
{:flex-direction :row
|
||||||
:margin-top 1})
|
:margin-top 1})
|
||||||
|
|
||||||
(defn pin-author-text
|
(defn pinned-by-text []
|
||||||
[]
|
|
||||||
(merge typography/font-medium
|
|
||||||
{:color quo2.colors/primary-50
|
|
||||||
:bottom 2}))
|
|
||||||
|
|
||||||
(defn pinned-by-text
|
|
||||||
[]
|
|
||||||
{:margin-left 5})
|
{:margin-left 5})
|
||||||
|
|
||||||
(def message-author-touchable
|
(def message-author-touchable
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im.chat.models :as chat]
|
[status-im.chat.models :as chat]
|
||||||
[status-im.chat.models.reactions :as models.reactions]
|
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.ui.components.fast-image :as fast-image]
|
[status-im.ui.components.fast-image :as fast-image]
|
||||||
|
@ -174,12 +173,12 @@
|
||||||
:picker-on-open (fn [])
|
:picker-on-open (fn [])
|
||||||
:picker-on-close (fn [])
|
:picker-on-close (fn [])
|
||||||
:send-emoji (fn [{:keys [emoji-id]}]
|
:send-emoji (fn [{:keys [emoji-id]}]
|
||||||
(re-frame/dispatch [::models.reactions/send-emoji-reaction
|
(re-frame/dispatch [:models.reactions/send-emoji-reaction
|
||||||
{:message-id (:message-id message)
|
{:message-id (:message-id message)
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:emoji-id emoji-id}]))
|
:emoji-id emoji-id}]))
|
||||||
:retract-emoji (fn [{:keys [emoji-id emoji-reaction-id]}]
|
:retract-emoji (fn [{:keys [emoji-id emoji-reaction-id]}]
|
||||||
(re-frame/dispatch [::models.reactions/send-emoji-reaction-retraction
|
(re-frame/dispatch [:models.reactions/send-emoji-reaction-retraction
|
||||||
{:message-id (:message-id message)
|
{:message-id (:message-id message)
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:emoji-id emoji-id
|
:emoji-id emoji-id
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
(ns status-im.ui2.screens.chat.components.reaction-drawer
|
|
||||||
(:require [quo.react-native :as rn]
|
|
||||||
[quo2.components.buttons.button :as quo2.button]
|
|
||||||
[quo2.components.list-items.menu-item :as quo2.menu-item]
|
|
||||||
[quo2.components.separator :as quo2.separator]
|
|
||||||
[quo2.foundations.colors :as colors]
|
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[status-im.constants :as constants]))
|
|
||||||
|
|
||||||
(defn message-options
|
|
||||||
[actions own-reactions send-emoji]
|
|
||||||
(fn []
|
|
||||||
(let [main-actions (filter #(= (:type %) :main) actions)
|
|
||||||
danger-actions (filter #(= (:type %) :danger) actions)
|
|
||||||
admin-actions (filter #(= (:type %) :admin) actions)]
|
|
||||||
[rn/view
|
|
||||||
[rn/view
|
|
||||||
{:style {:width "100%"
|
|
||||||
:flex-direction :row
|
|
||||||
:justify-content :space-between
|
|
||||||
:padding-horizontal 30
|
|
||||||
:padding-top 5
|
|
||||||
:padding-bottom 15}}
|
|
||||||
(doall
|
|
||||||
(for [[id icon] constants/reactions
|
|
||||||
:let [active (own-reactions id)]]
|
|
||||||
;;TODO reactions selector should be used
|
|
||||||
;;https://www.figma.com/file/WQZcp6S0EnzxdTL4taoKDv/Design-System?node-id=9961%3A166549
|
|
||||||
;; not implemented yet
|
|
||||||
^{:key id}
|
|
||||||
[quo2.button/button
|
|
||||||
(merge
|
|
||||||
{:size 40
|
|
||||||
:type :grey
|
|
||||||
:icon true
|
|
||||||
:icon-no-color true
|
|
||||||
:accessibility-label (str "emoji-picker-" id)
|
|
||||||
:on-press #(do
|
|
||||||
(send-emoji id)
|
|
||||||
(re-frame/dispatch [:bottom-sheet/hide]))}
|
|
||||||
(when active {:style {:background-color colors/neutral-10}}))
|
|
||||||
icon]))]
|
|
||||||
[rn/view {:style {:padding-horizontal 8}}
|
|
||||||
(for [action main-actions]
|
|
||||||
(let [on-press (:on-press action)]
|
|
||||||
^{:key (:id action)}
|
|
||||||
[quo2.menu-item/menu-item
|
|
||||||
{:type :main
|
|
||||||
:title (:label action)
|
|
||||||
:accessibility-label (:label action)
|
|
||||||
:icon (:icon action)
|
|
||||||
:on-press #(do
|
|
||||||
(when on-press (on-press))
|
|
||||||
(re-frame/dispatch [:bottom-sheet/hide]))}]))
|
|
||||||
(when-not (empty? danger-actions)
|
|
||||||
[quo2.separator/separator])
|
|
||||||
(for [action danger-actions]
|
|
||||||
(let [on-press (:on-press action)]
|
|
||||||
^{:key (:id action)}
|
|
||||||
[quo2.menu-item/menu-item
|
|
||||||
{:type :danger
|
|
||||||
:title (:label action)
|
|
||||||
:accessibility-label (:label action)
|
|
||||||
:icon (:icon action)
|
|
||||||
:on-press #(do
|
|
||||||
(when on-press (on-press))
|
|
||||||
(re-frame/dispatch [:bottom-sheet/hide]))}]))
|
|
||||||
(when-not (empty? admin-actions)
|
|
||||||
[quo2.separator/separator])
|
|
||||||
(for [action admin-actions]
|
|
||||||
(let [on-press (:on-press action)]
|
|
||||||
^{:key (:id action)}
|
|
||||||
[quo2.menu-item/menu-item
|
|
||||||
{:type :danger
|
|
||||||
:title (:label action)
|
|
||||||
:accessibility-label (:label action)
|
|
||||||
:icon (:icon action)
|
|
||||||
:on-press #(do
|
|
||||||
(when on-press (on-press))
|
|
||||||
(re-frame/dispatch [:bottom-sheet/hide]))}]))]])))
|
|
|
@ -20,7 +20,8 @@
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[status-im2.contexts.chat.messages.list.view :refer [scroll-to-bottom]]
|
[status-im2.contexts.chat.messages.list.view :refer [scroll-to-bottom]]
|
||||||
[status-im.utils.platform :as platform]))
|
[status-im.utils.platform :as platform]
|
||||||
|
[status-im2.common.not-implemented :as not-implemented]))
|
||||||
|
|
||||||
(defn calculate-y
|
(defn calculate-y
|
||||||
[context min-y max-y added-value chat-id set-bg-opacity]
|
[context min-y max-y added-value chat-id set-bg-opacity]
|
||||||
|
@ -301,10 +302,11 @@
|
||||||
:type :outline
|
:type :outline
|
||||||
:size 32} :i/image]
|
:size 32} :i/image]
|
||||||
[rn/view {:width 12}]
|
[rn/view {:width 12}]
|
||||||
[quo2.button/button
|
[not-implemented/not-implemented
|
||||||
{:icon true
|
[quo2.button/button
|
||||||
:type :outline
|
{:icon true
|
||||||
:size 32} :i/reaction]
|
:type :outline
|
||||||
|
:size 32} :i/reaction]]
|
||||||
[rn/view {:flex 1}]
|
[rn/view {:flex 1}]
|
||||||
;;SEND button
|
;;SEND button
|
||||||
[rn/view {:ref send-ref
|
[rn/view {:ref send-ref
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
(ns status-im.ui2.screens.chat.messages.message
|
(ns status-im.ui2.screens.chat.messages.message
|
||||||
(:require [quo.core :as quo]
|
(:require [quo.design-system.colors :as quo.colors]
|
||||||
[quo.design-system.colors :as quo.colors]
|
|
||||||
[quo.react-native :as rn]
|
[quo.react-native :as rn]
|
||||||
[quo2.components.avatars.user-avatar :as user-avatar]
|
[quo2.components.avatars.user-avatar :as user-avatar]
|
||||||
[quo2.components.icon :as icons]
|
[quo2.components.icon :as icons]
|
||||||
[quo2.components.markdown.text :as text]
|
[quo2.components.markdown.text :as text]
|
||||||
[quo2.components.messages.system-message :as system-message]
|
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[quo2.foundations.typography :as typography]
|
[quo2.foundations.typography :as typography]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im.chat.models.images :as images]
|
|
||||||
[status-im.chat.models.reactions :as models.reactions]
|
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.react-native.resources :as resources]
|
[status-im.react-native.resources :as resources]
|
||||||
[status-im.ui.components.animation :as animation]
|
|
||||||
[status-im.ui.components.fast-image :as fast-image]
|
[status-im.ui.components.fast-image :as fast-image]
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.screens.chat.image.preview.views :as preview]
|
[status-im.ui.screens.chat.image.preview.views :as preview]
|
||||||
|
@ -23,93 +18,39 @@
|
||||||
[status-im.ui.screens.chat.message.command :as message.command]
|
[status-im.ui.screens.chat.message.command :as message.command]
|
||||||
[status-im.ui.screens.chat.message.gap :as message.gap]
|
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||||
[status-im.ui.screens.chat.message.link-preview :as link-preview]
|
[status-im.ui.screens.chat.message.link-preview :as link-preview]
|
||||||
[status-im.ui.screens.chat.message.reactions :as reactions]
|
|
||||||
[status-im.ui.screens.chat.message.reactions-row :as reaction-row]
|
|
||||||
[status-im.ui.screens.chat.sheets :as sheets]
|
[status-im.ui.screens.chat.sheets :as sheets]
|
||||||
[status-im.ui.screens.chat.styles.message.message :as style]
|
[status-im.ui.screens.chat.styles.message.message :as style]
|
||||||
[status-im.ui.screens.chat.styles.photos :as photos.style]
|
|
||||||
[status-im.ui.screens.chat.utils :as chat.utils]
|
[status-im.ui.screens.chat.utils :as chat.utils]
|
||||||
[status-im.ui.screens.communities.icon :as communities.icon]
|
[status-im.ui.screens.communities.icon :as communities.icon]
|
||||||
[status-im.ui2.screens.chat.components.reaction-drawer :as reaction-drawer]
|
|
||||||
[status-im.ui2.screens.chat.components.reply :as components.reply]
|
[status-im.ui2.screens.chat.components.reply :as components.reply]
|
||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.datetime :as time]
|
[status-im.utils.datetime :as time]
|
||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]
|
[status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message-for-me.events]
|
[status-im2.contexts.chat.messages.delete-message-for-me.events]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message.events]
|
[status-im2.contexts.chat.messages.delete-message.events]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[utils.security.core :as security])
|
[quo2.core :as quo])
|
||||||
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
|
||||||
|
|
||||||
(defview mention-element
|
|
||||||
[from]
|
|
||||||
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
|
|
||||||
contact-name))
|
|
||||||
|
|
||||||
(def edited-at-text (str " ⌫ " (i18n/label :t/edited)))
|
(def edited-at-text (str " ⌫ " (i18n/label :t/edited)))
|
||||||
|
|
||||||
(defn message-status
|
|
||||||
[{:keys [outgoing content outgoing-status pinned edited-at in-popover?]}]
|
|
||||||
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
|
||||||
[rn/view
|
|
||||||
{:align-self :flex-end
|
|
||||||
:position :absolute
|
|
||||||
:bottom 9 ; 6 Bubble bottom, 3 message baseline
|
|
||||||
(if (:rtl? content) :left :right) 0
|
|
||||||
:flex-direction :row
|
|
||||||
:align-items :flex-end}
|
|
||||||
(when outgoing
|
|
||||||
[icons/icon
|
|
||||||
(case outgoing-status
|
|
||||||
:sending :tiny-icons/tiny-pending
|
|
||||||
:sent :tiny-icons/tiny-sent
|
|
||||||
:not-sent :tiny-icons/tiny-warning
|
|
||||||
:delivered :tiny-icons/tiny-delivered
|
|
||||||
:tiny-icons/tiny-pending)
|
|
||||||
{:width 16
|
|
||||||
:height 12
|
|
||||||
:color (if pinned quo.colors/gray quo.colors/white)
|
|
||||||
:accessibility-label (name outgoing-status)}])
|
|
||||||
(when edited-at [rn/text {:style (style/message-status-text)} edited-at-text])]))
|
|
||||||
|
|
||||||
(defn message-timestamp
|
|
||||||
[{:keys [timestamp-str in-popover?]}]
|
|
||||||
(when-not in-popover? ;; We keep track if showing this message in a list in pin-limit-popover
|
|
||||||
(let [anim-opacity (animation/create-value 0)]
|
|
||||||
[rn/animated-view {:style (style/message-timestamp-wrapper) :opacity anim-opacity}
|
|
||||||
[rn/text
|
|
||||||
{:style (style/message-timestamp-text)
|
|
||||||
:accessibility-label :message-timestamp}
|
|
||||||
timestamp-str]])))
|
|
||||||
|
|
||||||
(defn quoted-message
|
|
||||||
[{:keys [message-id chat-id]} reply pin?]
|
|
||||||
(let [{:keys [deleted? deleted-for-me?]} (get @(re-frame/subscribe [:chats/chat-messages chat-id])
|
|
||||||
message-id)
|
|
||||||
reply (assoc reply
|
|
||||||
:deleted? deleted?
|
|
||||||
:deleted-for-me? deleted-for-me?)]
|
|
||||||
[rn/view {:style (when-not pin? (style/quoted-message-container))}
|
|
||||||
[components.reply/reply-message reply false pin?]]))
|
|
||||||
|
|
||||||
(defn system-text?
|
(defn system-text?
|
||||||
[content-type]
|
[content-type]
|
||||||
(= content-type constants/content-type-system-text))
|
(= content-type constants/content-type-system-text))
|
||||||
|
|
||||||
|
(defn mention-element
|
||||||
|
[from]
|
||||||
|
(rf/sub [:contacts/contact-name-by-identity from]))
|
||||||
|
|
||||||
(defn render-inline
|
(defn render-inline
|
||||||
[message-text content-type acc {:keys [type literal destination]}]
|
[_message-text content-type acc {:keys [type literal destination]}]
|
||||||
(case type
|
(case type
|
||||||
""
|
""
|
||||||
(conj acc literal)
|
(conj acc literal)
|
||||||
|
|
||||||
"code"
|
"code"
|
||||||
(conj acc
|
(conj acc [rn/text literal])
|
||||||
[quo/text
|
|
||||||
{:max-font-size-multiplier react/max-font-size-multiplier
|
|
||||||
:style (style/inline-code-style)
|
|
||||||
:monospace true}
|
|
||||||
literal])
|
|
||||||
|
|
||||||
"emph"
|
"emph"
|
||||||
(conj acc [rn/text (style/emph-style) literal])
|
(conj acc [rn/text (style/emph-style) literal])
|
||||||
|
@ -126,14 +67,9 @@
|
||||||
"link"
|
"link"
|
||||||
(conj acc
|
(conj acc
|
||||||
[rn/text
|
[rn/text
|
||||||
{:style
|
{:style {:color :blue
|
||||||
{:color quo.colors/blue
|
:text-decoration-line :underline}
|
||||||
:text-decoration-line :underline}
|
:on-press #(rf/dispatch [:browser.ui/message-link-pressed destination])}
|
||||||
:on-press
|
|
||||||
#(when (and (security/safe-link? destination)
|
|
||||||
(security/safe-link-text? message-text))
|
|
||||||
(re-frame/dispatch
|
|
||||||
[:browser.ui/message-link-pressed destination]))}
|
|
||||||
destination])
|
destination])
|
||||||
|
|
||||||
"mention"
|
"mention"
|
||||||
|
@ -150,16 +86,15 @@
|
||||||
"status-tag"
|
"status-tag"
|
||||||
(conj acc
|
(conj acc
|
||||||
[rn/text
|
[rn/text
|
||||||
{:style {:color quo.colors/blue
|
{:style {:color :blue
|
||||||
:text-decoration-line :underline}
|
:text-decoration-line :underline}
|
||||||
:on-press
|
:on-press #(rf/dispatch [:chat.ui/start-public-chat literal])}
|
||||||
#(re-frame/dispatch
|
|
||||||
[:chat.ui/start-public-chat literal])}
|
|
||||||
"#"
|
"#"
|
||||||
literal])
|
literal])
|
||||||
|
|
||||||
(conj acc literal)))
|
(conj acc literal)))
|
||||||
|
|
||||||
|
;; TEXT
|
||||||
(defn render-block
|
(defn render-block
|
||||||
[{:keys [content content-type in-popover?]} acc
|
[{:keys [content content-type in-popover?]} acc
|
||||||
{:keys [type ^js literal children]}]
|
{:keys [type ^js literal children]}]
|
||||||
|
@ -181,42 +116,37 @@
|
||||||
"codeblock"
|
"codeblock"
|
||||||
(conj acc
|
(conj acc
|
||||||
[rn/view {:style style/codeblock-style}
|
[rn/view {:style style/codeblock-style}
|
||||||
[quo/text
|
[rn/text (.substring literal 0 (dec (.-length literal)))]])
|
||||||
{:max-font-size-multiplier react/max-font-size-multiplier
|
|
||||||
:style style/codeblock-text-style
|
|
||||||
:monospace true}
|
|
||||||
(.substring literal 0 (dec (.-length literal)))]])
|
|
||||||
|
|
||||||
acc))
|
acc))
|
||||||
|
|
||||||
(defn render-parsed-text
|
(defn render-parsed-text
|
||||||
[message tree]
|
[{:keys [content] :as message-data}]
|
||||||
(reduce (fn [acc e] (render-block message acc e)) [:<>] tree))
|
(reduce (fn [acc e]
|
||||||
|
(render-block message-data acc e))
|
||||||
|
[:<>]
|
||||||
|
(:parsed-text content)))
|
||||||
|
|
||||||
(defn render-parsed-text-with-message-status
|
(defn message-status
|
||||||
[{:keys [edited-at in-popover?] :as message} tree]
|
[{:keys [outgoing-status edited-at]}]
|
||||||
(let [elements (render-parsed-text message tree)
|
(when (or edited-at outgoing-status)
|
||||||
message-status [rn/text {:style (style/message-status-placeholder)}
|
[rn/view {:flex-direction :row}
|
||||||
(str (if (not in-popover?) " " " ")
|
[rn/text {:style (style/message-status-text)}
|
||||||
(when (and (not in-popover?) edited-at) edited-at-text))]
|
(str "["
|
||||||
last-element (peek elements)]
|
(if edited-at
|
||||||
;; Using `nth` here as slightly faster than `first`, roughly 30%
|
"edited"
|
||||||
;; It's worth considering pure js structures for this code path as
|
(or outgoing-status ""))
|
||||||
;; it's perfomance critical
|
" DEBUG]")]]))
|
||||||
(if (= rn/text (nth last-element 0))
|
|
||||||
;; Append message status to last text
|
|
||||||
(conj (pop elements) (conj last-element message-status))
|
|
||||||
;; Append message status to new block
|
|
||||||
(conj elements message-status))))
|
|
||||||
|
|
||||||
(defn unknown-content-type
|
(defn quoted-message
|
||||||
[{:keys [content-type content] :as message}]
|
[{:keys [message-id chat-id]} reply pin?]
|
||||||
[rn/view (style/message-view message)
|
(let [{:keys [deleted? deleted-for-me?]} (get @(re-frame/subscribe [:chats/chat-messages chat-id])
|
||||||
[rn/text
|
message-id)
|
||||||
{:style {:color quo.colors/white-persist}}
|
reply (assoc reply
|
||||||
(if (seq (:text content))
|
:deleted? deleted?
|
||||||
(:text content)
|
:deleted-for-me? deleted-for-me?)]
|
||||||
(str "Unhandled content-type " content-type))]])
|
[rn/view {:style (when-not pin? (style/quoted-message-container))}
|
||||||
|
[components.reply/reply-message reply false pin?]]))
|
||||||
|
|
||||||
(defn message-not-sent-text
|
(defn message-not-sent-text
|
||||||
[chat-id message-id]
|
[chat-id message-id]
|
||||||
|
@ -234,33 +164,6 @@
|
||||||
[rn/view style/not-sent-icon
|
[rn/view style/not-sent-icon
|
||||||
[icons/icon :i/warning {:color quo.colors/red}]]]])
|
[icons/icon :i/warning {:color quo.colors/red}]]]])
|
||||||
|
|
||||||
(defn pin-author-name
|
|
||||||
[pinned-by]
|
|
||||||
(let [user-contact @(re-frame/subscribe [:multiaccount/contact])
|
|
||||||
contact-names @(re-frame/subscribe [:contacts/contact-two-names-by-identity pinned-by])]
|
|
||||||
;; We append empty spaces to the name as a workaround to make one-line and multi-line label
|
|
||||||
;; components show correctly
|
|
||||||
(str " " (if (= pinned-by (user-contact :public-key)) (i18n/label :t/You) (first contact-names)))))
|
|
||||||
|
|
||||||
(defn pin-icon
|
|
||||||
[color size]
|
|
||||||
[icons/icon :i/pin
|
|
||||||
{:color color
|
|
||||||
:height size
|
|
||||||
:width size}])
|
|
||||||
|
|
||||||
(defn pinned-by-indicator
|
|
||||||
[pinned-by]
|
|
||||||
[rn/view
|
|
||||||
{:style (style/pin-indicator)
|
|
||||||
:accessibility-label :pinned-by}
|
|
||||||
[pin-icon colors/primary-50 16]
|
|
||||||
[quo/text
|
|
||||||
{:size :small
|
|
||||||
:color :main
|
|
||||||
:style (style/pin-author-text)}
|
|
||||||
(pin-author-name pinned-by)]])
|
|
||||||
|
|
||||||
(defn message-delivery-status
|
(defn message-delivery-status
|
||||||
[{:keys [chat-id message-id outgoing-status message-type]}]
|
[{:keys [chat-id message-id outgoing-status message-type]}]
|
||||||
(when (and (not= constants/message-type-private-group-system-message message-type)
|
(when (and (not= constants/message-type-private-group-system-message message-type)
|
||||||
|
@ -278,44 +181,6 @@
|
||||||
(letsubs [contact-with-names [:multiaccount/contact]]
|
(letsubs [contact-with-names [:multiaccount/contact]]
|
||||||
(chat.utils/format-author contact-with-names opts nil)))
|
(chat.utils/format-author contact-with-names opts nil)))
|
||||||
|
|
||||||
(defview community-content
|
|
||||||
[{:keys [community-id] :as message}]
|
|
||||||
(letsubs [{:keys [name description verified] :as community} [:communities/community community-id]
|
|
||||||
communities-enabled? [:communities/enabled?]]
|
|
||||||
(when (and communities-enabled? community)
|
|
||||||
[rn/view
|
|
||||||
{:style (assoc (style/message-wrapper message)
|
|
||||||
:margin-vertical 10
|
|
||||||
:margin-left 8
|
|
||||||
:width 271)}
|
|
||||||
(when verified
|
|
||||||
[rn/view (style/community-verified)
|
|
||||||
[rn/text
|
|
||||||
{:style {:font-size 13
|
|
||||||
:color quo.colors/blue}} (i18n/label :t/communities-verified)]])
|
|
||||||
[rn/view (style/community-message verified)
|
|
||||||
[rn/view
|
|
||||||
{:width 62
|
|
||||||
:padding-left 14}
|
|
||||||
(if (= community-id constants/status-community-id)
|
|
||||||
[rn/image
|
|
||||||
{:source (resources/get-image :status-logo)
|
|
||||||
:style {:width 40
|
|
||||||
:height 40}}]
|
|
||||||
[communities.icon/community-icon community])]
|
|
||||||
[rn/view {:padding-right 14 :flex 1}
|
|
||||||
[rn/text {:style {:font-weight "700" :font-size 17}}
|
|
||||||
name]
|
|
||||||
[rn/text description]]]
|
|
||||||
[rn/view (style/community-view-button)
|
|
||||||
[rn/touchable-opacity
|
|
||||||
{:on-press #(re-frame/dispatch
|
|
||||||
[:communities/navigate-to-community
|
|
||||||
{:community-id (:id community)}])}
|
|
||||||
[rn/text
|
|
||||||
{:style {:text-align :center
|
|
||||||
:color quo.colors/blue}} (i18n/label :t/view)]]]])))
|
|
||||||
|
|
||||||
(defn display-name-view
|
(defn display-name-view
|
||||||
[display-name contact timestamp show-key?]
|
[display-name contact timestamp show-key?]
|
||||||
[rn/view {:style {:flex-direction :row}}
|
[rn/view {:style {:flex-direction :row}}
|
||||||
|
@ -343,55 +208,43 @@
|
||||||
|
|
||||||
(defn message-content-wrapper
|
(defn message-content-wrapper
|
||||||
"Author, userpic and delivery wrapper"
|
"Author, userpic and delivery wrapper"
|
||||||
[{:keys [last-in-group? timestamp-str timestamp deleted? deleted-undoable-till
|
[{:keys [last-in-group? timestamp pinned from chat-id]
|
||||||
deleted-for-me? deleted-for-me-undoable-till pinned from chat-id]
|
|
||||||
:as message} content]
|
:as message} content]
|
||||||
(let [response-to (:response-to (:content message))
|
(let [response-to (:response-to (:content message))
|
||||||
display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
|
display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
|
||||||
contact (rf/sub [:contacts/contact-by-address from])
|
contact (rf/sub [:contacts/contact-by-address from])
|
||||||
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))
|
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))
|
||||||
online? (rf/sub [:visibility-status-updates/online? from])]
|
online? (rf/sub [:visibility-status-updates/online? from])]
|
||||||
(if (or deleted? deleted-for-me?)
|
[rn/view
|
||||||
[system-message/system-message
|
{:style (style/message-wrapper message)
|
||||||
{:type :deleted
|
:pointer-events :box-none
|
||||||
:label (if deleted? :message-deleted :message-deleted-for-you)
|
:accessibility-label :chat-item}
|
||||||
:labels {:pinned-a-message (i18n/label :pinned-a-message)
|
(when (and (seq response-to) (:quoted-message message))
|
||||||
:message-deleted (i18n/label :message-deleted-for-everyone)
|
[quoted-message {:message-id response-to :chat-id chat-id} (:quoted-message message)])
|
||||||
:message-deleted-for-you (i18n/label :message-deleted-for-you)
|
[rn/view
|
||||||
:added (i18n/label :added)}
|
{:style (style/message-body)
|
||||||
:timestamp-str timestamp-str
|
:pointer-events :box-none}
|
||||||
:non-pressable? true
|
;; AVATAR
|
||||||
:animate-landing? (if (or deleted-undoable-till deleted-for-me-undoable-till)
|
[rn/view {:style {:width 40}}
|
||||||
true
|
(when (or (and (seq response-to) (:quoted-message message)) last-in-group? pinned)
|
||||||
false)}]
|
[react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/show-profile from])}
|
||||||
[rn/view
|
[user-avatar/user-avatar
|
||||||
{:style (style/message-wrapper message)
|
{:full-name display-name
|
||||||
:pointer-events :box-none
|
:profile-picture photo-path
|
||||||
:accessibility-label :chat-item}
|
:status-indicator? true
|
||||||
(when (and (seq response-to) (:quoted-message message))
|
:online? online?
|
||||||
[quoted-message {:message-id response-to :chat-id chat-id} (:quoted-message message)])
|
:size :small
|
||||||
[rn/view
|
:ring? false}]])]
|
||||||
{:style (style/message-body)
|
[rn/view {:style (style/message-author-wrapper)}
|
||||||
:pointer-events :box-none}
|
;; AUTHOR NAME
|
||||||
[rn/view {:style {:width 40}}
|
(when (or (and (seq response-to) (:quoted-message message)) last-in-group? pinned)
|
||||||
(when (or (and (seq response-to) (:quoted-message message)) last-in-group? pinned)
|
[display-name-view display-name contact timestamp true])
|
||||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/show-profile from])}
|
;; MESSAGE CONTENT
|
||||||
[user-avatar/user-avatar
|
content
|
||||||
{:full-name display-name
|
[link-preview/link-preview-wrapper (:links (:content message)) false false]]]
|
||||||
:profile-picture photo-path
|
;; delivery status
|
||||||
:status-indicator? true
|
[rn/view (style/delivery-status)
|
||||||
:online? online?
|
[message-delivery-status message]]]))
|
||||||
:size :small
|
|
||||||
:ring? false}]])]
|
|
||||||
[rn/view {:style (style/message-author-wrapper)}
|
|
||||||
(when (or (and (seq response-to) (:quoted-message message)) last-in-group? pinned)
|
|
||||||
[display-name-view display-name contact timestamp true])
|
|
||||||
;; MESSAGE CONTENT
|
|
||||||
content
|
|
||||||
[link-preview/link-preview-wrapper (:links (:content message)) false false]]]
|
|
||||||
;; delivery status
|
|
||||||
[rn/view (style/delivery-status)
|
|
||||||
[message-delivery-status message]]])))
|
|
||||||
|
|
||||||
(def image-max-width 260)
|
(def image-max-width 260)
|
||||||
(def image-max-height 192)
|
(def image-max-height 192)
|
||||||
|
@ -408,46 +261,6 @@
|
||||||
(reset! dimensions {:width (/ width k) :height image-max-height :loaded true})))
|
(reset! dimensions {:width (/ width k) :height image-max-height :loaded true})))
|
||||||
(swap! dimensions assoc :loaded true)))))
|
(swap! dimensions assoc :loaded true)))))
|
||||||
|
|
||||||
(defn message-content-image
|
|
||||||
[{:keys [content]} _]
|
|
||||||
(let [dimensions (reagent/atom {:width image-max-width :height image-max-height :loaded false})
|
|
||||||
visible (reagent/atom false)
|
|
||||||
uri (:image content)]
|
|
||||||
(fn [{:keys [in-popover?] :as message}
|
|
||||||
{:keys [on-long-press]}]
|
|
||||||
(let [style-opts {:outgoing false
|
|
||||||
:opacity (if (:loaded @dimensions) 1 0)
|
|
||||||
:width (:width @dimensions)
|
|
||||||
:height (:height @dimensions)}]
|
|
||||||
[:<>
|
|
||||||
[preview/preview-image
|
|
||||||
{:message message
|
|
||||||
:visible @visible
|
|
||||||
:on-close #(do (reset! visible false)
|
|
||||||
(reagent/flush))}]
|
|
||||||
[rn/touchable-opacity
|
|
||||||
{:on-press (fn []
|
|
||||||
(reset! visible true)
|
|
||||||
(rn/dismiss-keyboard!))
|
|
||||||
:on-long-press @on-long-press
|
|
||||||
:disabled in-popover?}
|
|
||||||
[rn/view
|
|
||||||
{:style (style/image-message style-opts)
|
|
||||||
:accessibility-label :image-message}
|
|
||||||
(when (or (:error @dimensions) (not (:loaded @dimensions)))
|
|
||||||
[rn/view
|
|
||||||
(merge (dissoc style-opts :opacity)
|
|
||||||
{:flex 1 :align-items :center :justify-content :center :position :absolute})
|
|
||||||
(if (:error @dimensions)
|
|
||||||
[icons/icon :i/cancel]
|
|
||||||
[rn/activity-indicator {:animating true}])])
|
|
||||||
[fast-image/fast-image
|
|
||||||
{:style (dissoc style-opts :outgoing)
|
|
||||||
:on-load (image-set-size dimensions)
|
|
||||||
:on-error #(swap! dimensions assoc :error true)
|
|
||||||
:source {:uri uri}}]
|
|
||||||
[rn/view {:style (style/image-message-border style-opts)}]]]]))))
|
|
||||||
|
|
||||||
(defmulti ->message :content-type)
|
(defmulti ->message :content-type)
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-command
|
(defmethod ->message constants/content-type-command
|
||||||
|
@ -519,220 +332,73 @@
|
||||||
:icon :i/delete
|
:icon :i/delete
|
||||||
:id :delete-for-all}]))))
|
:id :delete-for-all}]))))
|
||||||
|
|
||||||
(defn collapsible-text-message
|
;; STATUS ? whats that ?
|
||||||
[_ _]
|
|
||||||
(let [collapsed? (reagent/atom false)
|
|
||||||
show-timestamp? (reagent/atom false)]
|
|
||||||
(fn [{:keys [content in-popover?] :as message} on-long-press modal ref]
|
|
||||||
(let [on-long-press (fn []
|
|
||||||
(if @collapsed?
|
|
||||||
(do (reset! collapsed? false)
|
|
||||||
(js/setTimeout #(on-long-press-fn on-long-press message content) 200))
|
|
||||||
(on-long-press-fn on-long-press message content)))]
|
|
||||||
(reset! ref on-long-press)
|
|
||||||
[rn/touchable-opacity
|
|
||||||
(when-not modal
|
|
||||||
{:delay-long-press 100
|
|
||||||
:on-long-press on-long-press
|
|
||||||
:disabled in-popover?})
|
|
||||||
[rn/view style/message-view-wrapper
|
|
||||||
[message-timestamp message show-timestamp?]
|
|
||||||
[rn/view {:style (style/message-view message)}
|
|
||||||
[rn/view {:style (style/message-view-content)}
|
|
||||||
[rn/view
|
|
||||||
[render-parsed-text-with-message-status message (:parsed-text content)]]]]]]))))
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-text
|
|
||||||
[message {:keys [on-long-press modal ref] :as reaction-picker}]
|
|
||||||
[message-content-wrapper message
|
|
||||||
[collapsible-text-message message on-long-press modal ref]
|
|
||||||
reaction-picker])
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-community
|
|
||||||
[message]
|
|
||||||
[community-content message])
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-status
|
(defmethod ->message constants/content-type-status
|
||||||
[{:keys [content content-type] :as message}]
|
[{:keys [content content-type]}]
|
||||||
[message-content-wrapper message
|
[rn/view style/status-container
|
||||||
[rn/view style/status-container
|
[rn/text {:style (style/status-text)}
|
||||||
[rn/text {:style (style/status-text)}
|
(reduce
|
||||||
(reduce
|
(fn [acc e] (render-inline (:text content) content-type acc e))
|
||||||
(fn [acc e] (render-inline (:text content) content-type acc e))
|
[rn/text {:style (style/status-text)}]
|
||||||
[rn/text {:style (style/status-text)}]
|
(-> content :parsed-text peek :children))]])
|
||||||
(-> content :parsed-text peek :children))]]])
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-emoji
|
;; EMOJI
|
||||||
|
(defn emoji
|
||||||
[]
|
[]
|
||||||
(let [show-timestamp? (reagent/atom false)]
|
(fn [{:keys [content] :as message}]
|
||||||
(fn [{:keys [content pinned in-popover? message-pin-enabled] :as message}
|
[rn/view (style/message-view message)
|
||||||
{:keys [on-long-press modal ref]
|
[rn/view {:style (style/message-view-content)}
|
||||||
:as reaction-picker}]
|
[rn/view {:style (style/style-message-text)}
|
||||||
(let [on-long-press (fn []
|
[rn/text {:style (style/emoji-message message)}
|
||||||
(on-long-press
|
(:text content)]]]]))
|
||||||
(concat
|
|
||||||
[{:type :main
|
|
||||||
:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
|
||||||
:id :reply
|
|
||||||
:icon :i/reply
|
|
||||||
:label (i18n/label :t/message-reply)}
|
|
||||||
{:type :main
|
|
||||||
:on-press #(react/copy-to-clipboard (get content :text))
|
|
||||||
:id :copy
|
|
||||||
:icon :i/copy
|
|
||||||
:label (i18n/label :t/copy-text)}]
|
|
||||||
(when message-pin-enabled
|
|
||||||
[{:type :main
|
|
||||||
:on-press #(pin-message message)
|
|
||||||
:id :pin
|
|
||||||
:icon :i/pin
|
|
||||||
:label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin))}]))))]
|
|
||||||
(reset! ref on-long-press)
|
|
||||||
[message-content-wrapper message
|
|
||||||
[rn/touchable-opacity
|
|
||||||
(when-not modal
|
|
||||||
{:disabled in-popover?
|
|
||||||
:on-press (fn []
|
|
||||||
(rn/dismiss-keyboard!)
|
|
||||||
(reset! show-timestamp? true))
|
|
||||||
:delay-long-press 100
|
|
||||||
:on-long-press on-long-press})
|
|
||||||
[rn/view style/message-view-wrapper
|
|
||||||
[message-timestamp message show-timestamp?]
|
|
||||||
[rn/view (style/message-view message)
|
|
||||||
[rn/view {:style (style/message-view-content)}
|
|
||||||
[rn/view {:style (style/style-message-text)}
|
|
||||||
[rn/text {:style (style/emoji-message message)}
|
|
||||||
(:text content)]]
|
|
||||||
[message-status message]]]]]
|
|
||||||
reaction-picker]))))
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-sticker
|
;; STICKER
|
||||||
[{:keys [content from outgoing in-popover?]
|
(defn sticker
|
||||||
:as message}
|
[{:keys [content]}]
|
||||||
{:keys [on-long-press modal ref]
|
[fast-image/fast-image
|
||||||
:as reaction-picker}]
|
{:style {:margin 10 :width 140 :height 140}
|
||||||
(let [pack (get-in content [:sticker :pack])
|
:source {:uri (str (-> content :sticker :url) "&download=true")}}])
|
||||||
on-long-press (fn []
|
|
||||||
(on-long-press
|
|
||||||
(when-not outgoing
|
|
||||||
[{:type :main
|
|
||||||
:icon :i/stickers
|
|
||||||
:on-press #(when pack
|
|
||||||
(re-frame/dispatch [:chat.ui/show-profile from]))
|
|
||||||
:label (i18n/label :t/see-sticker-set)}])))]
|
|
||||||
(reset! ref on-long-press)
|
|
||||||
[message-content-wrapper message
|
|
||||||
[rn/touchable-opacity
|
|
||||||
(when-not modal
|
|
||||||
{:disabled in-popover?
|
|
||||||
:accessibility-label :sticker-message
|
|
||||||
:on-press (fn [_]
|
|
||||||
(when pack
|
|
||||||
(re-frame/dispatch [:stickers/open-sticker-pack (str pack)]))
|
|
||||||
(rn/dismiss-keyboard!))
|
|
||||||
:delay-long-press 100
|
|
||||||
:on-long-press on-long-press})
|
|
||||||
[fast-image/fast-image
|
|
||||||
{:style {:margin 10 :width 140 :height 140}
|
|
||||||
:source {:uri (str (-> content :sticker :url) "&download=true")}}]]
|
|
||||||
reaction-picker]))
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-image
|
;;IMAGE
|
||||||
[{:keys [content in-popover? outgoing] :as message}
|
(defn message-content-image
|
||||||
{:keys [on-long-press modal ref]
|
[{:keys [content]}]
|
||||||
:as reaction-picker}]
|
(let [dimensions (reagent/atom {:width image-max-width :height image-max-height :loaded false})
|
||||||
(let [on-long-press
|
visible (reagent/atom false)
|
||||||
(fn []
|
uri (:image content)]
|
||||||
(on-long-press
|
(fn [message]
|
||||||
(concat [{:type :main
|
(let [style-opts {:outgoing false
|
||||||
:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
:opacity (if (:loaded @dimensions) 1 0)
|
||||||
:id :reply
|
:width (:width @dimensions)
|
||||||
:icon :i/reply
|
:height (:height @dimensions)}]
|
||||||
:label (i18n/label :t/message-reply)}
|
[:<>
|
||||||
{:type :main
|
[preview/preview-image
|
||||||
:on-press #(re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)])
|
{:message message
|
||||||
:id :save
|
:visible @visible
|
||||||
:icon :i/save
|
:on-close #(do (reset! visible false)
|
||||||
:label (i18n/label :t/save-image-library)}
|
(reagent/flush))}]
|
||||||
{:type :main
|
[rn/view
|
||||||
:on-press #(images/download-image-http
|
{:style (style/image-message style-opts)
|
||||||
(get-in message [:content :image])
|
:accessibility-label :image-message}
|
||||||
preview/share)
|
(when (or (:error @dimensions) (not (:loaded @dimensions)))
|
||||||
:id :share
|
[rn/view
|
||||||
:icon :i/share
|
(merge (dissoc style-opts :opacity)
|
||||||
:label (i18n/label :t/share-image)}]
|
{:flex 1 :align-items :center :justify-content :center :position :absolute})
|
||||||
[{:type :danger
|
(if (:error @dimensions)
|
||||||
:on-press #(re-frame/dispatch
|
[icons/icon :i/cancel]
|
||||||
[:chat.ui/delete-message-for-me message
|
[rn/activity-indicator {:animating true}])])
|
||||||
config/delete-message-undo-time-limit-ms])
|
[fast-image/fast-image
|
||||||
:label (i18n/label :t/delete-for-me)
|
{:style (dissoc style-opts :outgoing)
|
||||||
:icon :i/delete
|
:on-load (image-set-size dimensions)
|
||||||
:id :delete-for-me}]
|
:on-error #(swap! dimensions assoc :error true)
|
||||||
(when (and outgoing config/delete-message-enabled?)
|
:source {:uri uri}}]
|
||||||
[{:type :danger
|
[rn/view {:style (style/image-message-border style-opts)}]]]))))
|
||||||
: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}]))))]
|
|
||||||
(reset! ref on-long-press)
|
|
||||||
[message-content-wrapper message
|
|
||||||
[message-content-image message
|
|
||||||
{:modal modal
|
|
||||||
:disabled in-popover?
|
|
||||||
:delay-long-press 100
|
|
||||||
:on-long-press ref}]
|
|
||||||
reaction-picker]))
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-audio
|
;; AUDIO
|
||||||
[]
|
(defn audio
|
||||||
(let [show-timestamp? (reagent/atom false)]
|
[message]
|
||||||
(fn [{:keys [outgoing pinned] :as message}
|
[rn/view {:style (style/message-view message) :accessibility-label :audio-message}
|
||||||
{:keys [on-long-press modal ref]
|
[rn/view {:style (style/message-view-content)}
|
||||||
:as reaction-picker}]
|
[message.audio/message-content message]]])
|
||||||
(let [on-long-press
|
|
||||||
(fn []
|
|
||||||
(on-long-press
|
|
||||||
[{: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 #(pin-message message)
|
|
||||||
:label (i18n/label (if pinned :t/unpin-from-chat :t/pin-to-chat))
|
|
||||||
:icon :i/pin
|
|
||||||
:id (if pinned :unpin :pin)}
|
|
||||||
{:type :danger
|
|
||||||
:on-press #(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 outgoing 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})]))]
|
|
||||||
(reset! ref on-long-press)
|
|
||||||
[message-content-wrapper message
|
|
||||||
[rn/touchable-opacity
|
|
||||||
(when-not modal
|
|
||||||
{:on-long-press on-long-press
|
|
||||||
:on-press (fn []
|
|
||||||
(reset! show-timestamp? true))})
|
|
||||||
[rn/view style/message-view-wrapper
|
|
||||||
[message-timestamp message show-timestamp?]
|
|
||||||
[rn/view {:style (style/message-view message) :accessibility-label :audio-message}
|
|
||||||
[rn/view {:style (style/message-view-content)}
|
|
||||||
[message.audio/message-content message] [message-status message]]]]]
|
|
||||||
reaction-picker]))))
|
|
||||||
|
|
||||||
(defn contact-request-status-pending
|
(defn contact-request-status-pending
|
||||||
[]
|
[]
|
||||||
|
@ -769,7 +435,10 @@
|
||||||
constants/contact-request-message-state-accepted [contact-request-status-accepted]
|
constants/contact-request-message-state-accepted [contact-request-status-accepted]
|
||||||
constants/contact-request-message-state-declined [contact-request-status-declined])])
|
constants/contact-request-message-state-declined [contact-request-status-declined])])
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-contact-request
|
;;;; SYSTEM
|
||||||
|
|
||||||
|
;; CONTACT REQUEST (like system message ? ) no wrapper
|
||||||
|
(defn system-contact-request
|
||||||
[message _]
|
[message _]
|
||||||
[rn/view {:style (style/content-type-contact-request)}
|
[rn/view {:style (style/content-type-contact-request)}
|
||||||
[rn/image
|
[rn/image
|
||||||
|
@ -788,120 +457,45 @@
|
||||||
(get-in message [:content :text])]]
|
(get-in message [:content :text])]]
|
||||||
[contact-request-status-label (:contact-request-state message)]])
|
[contact-request-status-label (:contact-request-state message)]])
|
||||||
|
|
||||||
(defmethod ->message :default
|
(defview community-content
|
||||||
|
[{:keys [community-id] :as message}]
|
||||||
|
(letsubs [{:keys [name description verified] :as community} [:communities/community community-id]
|
||||||
|
communities-enabled? [:communities/enabled?]]
|
||||||
|
(when (and communities-enabled? community)
|
||||||
|
[rn/view
|
||||||
|
{:style (assoc (style/message-wrapper message)
|
||||||
|
:margin-vertical 10
|
||||||
|
:margin-left 8
|
||||||
|
:width 271)}
|
||||||
|
(when verified
|
||||||
|
[rn/view (style/community-verified)
|
||||||
|
[rn/text
|
||||||
|
{:style {:font-size 13
|
||||||
|
:color quo.colors/blue}} (i18n/label :t/communities-verified)]])
|
||||||
|
[rn/view (style/community-message verified)
|
||||||
|
[rn/view
|
||||||
|
{:width 62
|
||||||
|
:padding-left 14}
|
||||||
|
(if (= community-id constants/status-community-id)
|
||||||
|
[rn/image
|
||||||
|
{:source (resources/get-image :status-logo)
|
||||||
|
:style {:width 40
|
||||||
|
:height 40}}]
|
||||||
|
[communities.icon/community-icon community])]
|
||||||
|
[rn/view {:padding-right 14 :flex 1}
|
||||||
|
[rn/text {:style {:font-weight "700" :font-size 17}}
|
||||||
|
name]
|
||||||
|
[rn/text description]]]
|
||||||
|
[rn/view (style/community-view-button)
|
||||||
|
[rn/touchable-opacity
|
||||||
|
{:on-press #(re-frame/dispatch
|
||||||
|
[:communities/navigate-to-community
|
||||||
|
{:community-id (:id community)}])}
|
||||||
|
[rn/text
|
||||||
|
{:style {:text-align :center
|
||||||
|
:color quo.colors/blue}} (i18n/label :t/view)]]]])))
|
||||||
|
|
||||||
|
;; COMMUNITY (like system ? ) no wrapper
|
||||||
|
(defn community
|
||||||
[message]
|
[message]
|
||||||
[message-content-wrapper message
|
[community-content message])
|
||||||
[unknown-content-type message]])
|
|
||||||
|
|
||||||
(defn chat-message
|
|
||||||
[{:keys [pinned pinned-by mentioned in-pinned-view? last-in-group? deleted? deleted-for-me?]
|
|
||||||
:as message}]
|
|
||||||
(let [reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message)
|
|
||||||
(:chat-id message)])
|
|
||||||
own-reactions (reduce (fn [acc {:keys [emoji-id own]}]
|
|
||||||
(if own (conj acc emoji-id) acc))
|
|
||||||
[]
|
|
||||||
reactions)
|
|
||||||
send-emoji (fn [{:keys [emoji-id]}]
|
|
||||||
(re-frame/dispatch [::models.reactions/send-emoji-reaction
|
|
||||||
{:message-id (:message-id message)
|
|
||||||
:emoji-id emoji-id}]))
|
|
||||||
retract-emoji (fn [{:keys [emoji-id emoji-reaction-id]}]
|
|
||||||
(re-frame/dispatch [::models.reactions/send-emoji-reaction-retraction
|
|
||||||
{:message-id (:message-id message)
|
|
||||||
:emoji-id emoji-id
|
|
||||||
:emoji-reaction-id emoji-reaction-id}]))
|
|
||||||
on-emoji-press (fn [emoji-id]
|
|
||||||
(let [active ((set own-reactions) emoji-id)]
|
|
||||||
(if active
|
|
||||||
(retract-emoji {:emoji-id emoji-id
|
|
||||||
:emoji-reaction-id (reactions/extract-id reactions
|
|
||||||
emoji-id)})
|
|
||||||
(send-emoji {:emoji-id emoji-id}))))
|
|
||||||
on-open-drawer (fn [actions]
|
|
||||||
(re-frame/dispatch [:bottom-sheet/show-sheet
|
|
||||||
{:content (reaction-drawer/message-options
|
|
||||||
actions
|
|
||||||
(into #{} (js->clj own-reactions))
|
|
||||||
#(on-emoji-press %))}]))
|
|
||||||
on-long-press (atom nil)]
|
|
||||||
[rn/view
|
|
||||||
{:style (merge (when (and (not in-pinned-view?) (or mentioned pinned))
|
|
||||||
{:background-color colors/primary-50-opa-5
|
|
||||||
:border-radius 16
|
|
||||||
:margin-bottom 4})
|
|
||||||
(when (or mentioned pinned last-in-group?) {:margin-top 8})
|
|
||||||
{:margin-horizontal 8})}
|
|
||||||
|
|
||||||
(when (and pinned (not (or deleted? deleted-for-me?)))
|
|
||||||
[rn/view {:style (style/pin-indicator-container)}
|
|
||||||
[pinned-by-indicator pinned-by]])
|
|
||||||
[->message message
|
|
||||||
{:ref on-long-press
|
|
||||||
:modal false
|
|
||||||
:on-long-press on-open-drawer}]
|
|
||||||
(when-not (or deleted? deleted-for-me?)
|
|
||||||
[reaction-row/message-reactions message reactions nil on-emoji-press on-long-press])])) ;; TODO: pass on-open-drawer function
|
|
||||||
|
|
||||||
(defn message-render-fn
|
|
||||||
[{:keys [outgoing whisper-timestamp] :as message}
|
|
||||||
_
|
|
||||||
{:keys [group-chat public? community? current-public-key show-input? edit-enabled]}]
|
|
||||||
[chat-message
|
|
||||||
(assoc message
|
|
||||||
:incoming-group (and group-chat (not outgoing))
|
|
||||||
: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 (time/timestamp->time whisper-timestamp)
|
|
||||||
:edit-enabled edit-enabled)])
|
|
||||||
|
|
||||||
(defn pin-system-message
|
|
||||||
[{:keys [from in-popover? timestamp-str chat-id] :as message} {:keys [modal close-modal]}]
|
|
||||||
(let [response-to (:response-to (:content message))]
|
|
||||||
[rn/touchable-opacity
|
|
||||||
{:on-press #(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id])
|
|
||||||
:active-opacity 1
|
|
||||||
:style (merge {:flex-direction :row :margin-vertical 8} (style/message-wrapper message))}
|
|
||||||
[rn/view
|
|
||||||
{:style {:width photos.style/default-size
|
|
||||||
:height photos.style/default-size
|
|
||||||
:margin-right 16
|
|
||||||
:border-radius photos.style/default-size
|
|
||||||
:justify-content :center
|
|
||||||
:align-items :center
|
|
||||||
:background-color colors/primary-50-opa-10}
|
|
||||||
:accessibility-label :content-type-pin-icon}
|
|
||||||
[pin-icon colors/primary-50 16]]
|
|
||||||
[rn/view
|
|
||||||
[rn/view {:style {:flex-direction :row :align-items :center}}
|
|
||||||
[rn/touchable-opacity
|
|
||||||
{:style style/message-author-touchable
|
|
||||||
:disabled in-popover?
|
|
||||||
:on-press #(do (when modal (close-modal))
|
|
||||||
(re-frame/dispatch [:chat.ui/show-profile from]))}
|
|
||||||
[message-author-name from {:modal modal} 20]]
|
|
||||||
[rn/text {:style {:font-size 13}} (str " " (i18n/label :t/pinned-a-message))]
|
|
||||||
[rn/text
|
|
||||||
{:style (merge
|
|
||||||
{:padding-left 5
|
|
||||||
:margin-top 2}
|
|
||||||
(style/message-timestamp-text))
|
|
||||||
:accessibility-label :message-timestamp}
|
|
||||||
timestamp-str]]
|
|
||||||
[quoted-message {:message-id response-to :chat-id chat-id} (:quoted-message message) true]]]))
|
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-system-text
|
|
||||||
[{:keys [content quoted-message] :as message}]
|
|
||||||
(if quoted-message
|
|
||||||
[pin-system-message message]
|
|
||||||
[rn/view {:accessibility-label :chat-item}
|
|
||||||
[rn/view (style/system-message-body message)
|
|
||||||
[rn/view (style/message-view message)
|
|
||||||
[rn/view (style/message-view-content)
|
|
||||||
[render-parsed-text message (:parsed-text content)]]]]]))
|
|
||||||
|
|
|
@ -152,8 +152,9 @@
|
||||||
|
|
||||||
(def wallet-connect-project-id "87815d72a81d739d2a7ce15c2cfdefb3")
|
(def wallet-connect-project-id "87815d72a81d739d2a7ce15c2cfdefb3")
|
||||||
|
|
||||||
|
;; NOTE moved to status-im2.common.constants
|
||||||
(def delete-message-undo-time-limit-ms 4000)
|
(def delete-message-undo-time-limit-ms 4000)
|
||||||
(def delete-message-for-me-undo-time-limit-ms 4000)
|
(def delete-message-for-me-undo-time-limit-ms 4000)
|
||||||
|
|
||||||
;;TODO for development only should be removed in status 2.0
|
;; NOTE for development only should be removed in status 2.0
|
||||||
(def new-ui-enabled? true)
|
(def new-ui-enabled? true)
|
||||||
|
|
|
@ -195,3 +195,6 @@
|
||||||
(def ^:const community-member-role-all 1)
|
(def ^:const community-member-role-all 1)
|
||||||
(def ^:const community-member-role-manage-users 2)
|
(def ^:const community-member-role-manage-users 2)
|
||||||
(def ^:const community-member-role-moderator 3)
|
(def ^:const community-member-role-moderator 3)
|
||||||
|
|
||||||
|
(def ^:const delete-message-undo-time-limit-ms 4000)
|
||||||
|
(def ^:const delete-message-for-me-undo-time-limit-ms 4000)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
(ns status-im2.common.not-implemented
|
||||||
|
(:require [react-native.core :as rn]))
|
||||||
|
|
||||||
|
(defn not-implemented [content]
|
||||||
|
[rn/view {:border-color :red :border-width 1}
|
||||||
|
content])
|
|
@ -0,0 +1,15 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.deleted.view
|
||||||
|
(:require [quo2.core :as quo]
|
||||||
|
[i18n.i18n :as i18n]))
|
||||||
|
|
||||||
|
(defn deleted-message [{:keys [deleted? deleted-undoable-till timestamp-str deleted-for-me-undoable-till]}]
|
||||||
|
[quo/system-message
|
||||||
|
{:type :deleted
|
||||||
|
:label (if deleted? :message-deleted :message-deleted-for-you)
|
||||||
|
:labels {:pinned-a-message (i18n/label :t/pinned-a-message)
|
||||||
|
:message-deleted (i18n/label :t/message-deleted-for-everyone)
|
||||||
|
:message-deleted-for-you (i18n/label :t/message-deleted-for-you)
|
||||||
|
:added (i18n/label :t/added)}
|
||||||
|
:timestamp-str timestamp-str
|
||||||
|
:non-pressable? true
|
||||||
|
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}])
|
|
@ -0,0 +1,14 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.pin.style
|
||||||
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
|
|
||||||
|
(def pin-indicator-container
|
||||||
|
{:margin-top 4
|
||||||
|
:margin-left 54
|
||||||
|
:justify-content :center
|
||||||
|
:align-self :flex-start
|
||||||
|
:align-items :flex-start
|
||||||
|
:flex-direction :row})
|
||||||
|
|
||||||
|
(def pin-author-text
|
||||||
|
{:color colors/primary-50
|
||||||
|
:bottom 2})
|
|
@ -0,0 +1,52 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.pin.view
|
||||||
|
(:require [react-native.core :as rn]
|
||||||
|
[status-im2.contexts.chat.messages.content.pin.style :as style]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[quo2.foundations.colors :as colors]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[i18n.i18n :as i18n]
|
||||||
|
[status-im.ui2.screens.chat.messages.message :as old-message]
|
||||||
|
[status-im.ui.screens.chat.styles.message.message :as old-style]))
|
||||||
|
|
||||||
|
(defn pinned-by-view [pinned-by]
|
||||||
|
(let [{:keys [public-key]} (rf/sub [:multiaccount/contact])
|
||||||
|
contact-names (rf/sub [:contacts/contact-two-names-by-identity pinned-by])
|
||||||
|
author-name (if (= pinned-by public-key) (i18n/label :t/You) (first contact-names))]
|
||||||
|
[rn/view {:style style/pin-indicator-container
|
||||||
|
:accessibility-label :pinned-by}
|
||||||
|
[quo/icon :i/pin {:color colors/primary-50 :size 16}]
|
||||||
|
[quo/text {:size :label
|
||||||
|
:weight :medium
|
||||||
|
:style style/pin-author-text}
|
||||||
|
author-name]]))
|
||||||
|
|
||||||
|
(defn system-message [{:keys [from in-popover? timestamp-str chat-id] :as message}]
|
||||||
|
(let [response-to (:response-to (:content message))
|
||||||
|
default-size 36]
|
||||||
|
[rn/touchable-opacity {:on-press #(rf/dispatch [:bottom-sheet/show-sheet :pinned-messages-list chat-id])
|
||||||
|
:active-opacity 1
|
||||||
|
:style (merge {:flex-direction :row :margin-vertical 8} (old-style/message-wrapper message))}
|
||||||
|
[rn/view {:style {:width default-size
|
||||||
|
:height default-size
|
||||||
|
:margin-right 16
|
||||||
|
:border-radius default-size
|
||||||
|
:justify-content :center
|
||||||
|
:align-items :center
|
||||||
|
:background-color colors/primary-50-opa-10}
|
||||||
|
:accessibility-label :content-type-pin-icon}
|
||||||
|
[quo/icon :i/pin {:color colors/primary-50 :size 16}]]
|
||||||
|
[rn/view
|
||||||
|
[rn/view {:style {:flex-direction :row :align-items :center}}
|
||||||
|
[rn/touchable-opacity {:style old-style/message-author-touchable
|
||||||
|
:disabled in-popover?
|
||||||
|
:on-press #(rf/dispatch [:chat.ui/show-profile from])}
|
||||||
|
[old-message/message-author-name from {} 20]]
|
||||||
|
[rn/text {:style {:font-size 13}} (str " " (i18n/label :t/pinned-a-message))]
|
||||||
|
[rn/text
|
||||||
|
{:style (merge
|
||||||
|
{:padding-left 5
|
||||||
|
:margin-top 2}
|
||||||
|
(old-style/message-timestamp-text))
|
||||||
|
:accessibility-label :message-timestamp}
|
||||||
|
timestamp-str]]
|
||||||
|
[old-message/quoted-message {:message-id response-to :chat-id chat-id} (:quoted-message message) true]]]))
|
|
@ -0,0 +1,28 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.reactions.view
|
||||||
|
(:require [status-im2.common.constants :as constants]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[status-im2.contexts.chat.messages.drawers.view :as drawers]))
|
||||||
|
|
||||||
|
(defn message-reactions-row [chat-id message-id]
|
||||||
|
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])]
|
||||||
|
(when (seq reactions)
|
||||||
|
[rn/view {:margin-left 52 :margin-bottom 12 :flex-direction :row}
|
||||||
|
(for [{:keys [own emoji-id quantity emoji-reaction-id] :as emoji-reaction} reactions]
|
||||||
|
^{:key (str emoji-reaction)}
|
||||||
|
[rn/view {:style {:margin-right 6}}
|
||||||
|
[quo/reaction {:emoji (get constants/reactions emoji-id)
|
||||||
|
:neutral? own
|
||||||
|
:clicks quantity
|
||||||
|
:on-press (if own
|
||||||
|
#(rf/dispatch [:models.reactions/send-emoji-reaction-retraction
|
||||||
|
{:message-id message-id
|
||||||
|
:emoji-id emoji-id
|
||||||
|
:emoji-reaction-id emoji-reaction-id}])
|
||||||
|
#(rf/dispatch [:models.reactions/send-emoji-reaction
|
||||||
|
{:message-id message-id
|
||||||
|
:emoji-id emoji-id}]))
|
||||||
|
:accessibility-label (str "emoji-reaction-" emoji-id)}]])
|
||||||
|
[quo/add-reaction {:on-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||||
|
{:content (fn [] [drawers/reactions chat-id message-id])}])}]])))
|
|
@ -0,0 +1,5 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.status.view
|
||||||
|
(:require [status-im.ui2.screens.chat.messages.message :as old-message]))
|
||||||
|
|
||||||
|
(defn status [message-data]
|
||||||
|
[old-message/message-status message-data])
|
|
@ -0,0 +1,10 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.style
|
||||||
|
(:require [quo2.foundations.colors :as colors]))
|
||||||
|
|
||||||
|
(defn message-container [in-pinned-view? pinned mentioned last-in-group?]
|
||||||
|
(merge (when (and (not in-pinned-view?) (or mentioned pinned))
|
||||||
|
{:background-color colors/primary-50-opa-5
|
||||||
|
:margin-bottom 4})
|
||||||
|
(when (or mentioned pinned last-in-group?)
|
||||||
|
{:margin-top 8})
|
||||||
|
{:border-radius 16}))
|
|
@ -0,0 +1,7 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.system.text.view
|
||||||
|
(:require [react-native.core :as rn]
|
||||||
|
[status-im.ui2.screens.chat.messages.message :as old-message]))
|
||||||
|
|
||||||
|
(defn text-content [message-data]
|
||||||
|
[rn/view {:accessibility-label :chat-item}
|
||||||
|
[old-message/render-parsed-text message-data]])
|
|
@ -0,0 +1 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.text.style)
|
|
@ -0,0 +1,5 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.text.view
|
||||||
|
(:require [status-im.ui2.screens.chat.messages.message :as old-message]))
|
||||||
|
|
||||||
|
(defn text-content [message-data]
|
||||||
|
[old-message/render-parsed-text message-data])
|
|
@ -0,0 +1,9 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.unknown.view
|
||||||
|
(:require [react-native.core :as rn]))
|
||||||
|
|
||||||
|
(defn unknown-content
|
||||||
|
[{:keys [content-type content]}]
|
||||||
|
[rn/text
|
||||||
|
(if (seq (:text content))
|
||||||
|
(:text content)
|
||||||
|
(str "Unhandled content-type " content-type))])
|
|
@ -0,0 +1,107 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.content.view
|
||||||
|
(:require [react-native.core :as rn]
|
||||||
|
[quo2.foundations.colors :as colors]
|
||||||
|
[status-im2.contexts.chat.messages.content.style :as style]
|
||||||
|
[status-im2.contexts.chat.messages.content.pin.view :as pin]
|
||||||
|
[status-im2.common.constants :as constants]
|
||||||
|
[status-im2.contexts.chat.messages.content.unknown.view :as content.unknown]
|
||||||
|
[status-im2.contexts.chat.messages.content.text.view :as content.text]
|
||||||
|
[status-im2.contexts.chat.messages.drawers.view :as drawers]
|
||||||
|
[status-im2.contexts.chat.messages.content.reactions.view :as reactions]
|
||||||
|
[status-im2.contexts.chat.messages.content.status.view :as status]
|
||||||
|
[status-im2.contexts.chat.messages.content.system.text.view :as system.text]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[status-im.utils.datetime :as time]
|
||||||
|
[status-im.ui2.screens.chat.messages.message :as old-message]
|
||||||
|
[status-im2.common.not-implemented :as not-implemented]))
|
||||||
|
|
||||||
|
(defn avatar
|
||||||
|
[{:keys [response-to last-in-group? pinned quoted-message from]}]
|
||||||
|
[rn/touchable-without-feedback {:on-press #(rf/dispatch [:chat.ui/show-profile from])}
|
||||||
|
[rn/view {:padding-top 2 :width 32}
|
||||||
|
(when (or (and (seq response-to) quoted-message) last-in-group? pinned)
|
||||||
|
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
|
||||||
|
contact (rf/sub [:contacts/contact-by-address from])
|
||||||
|
photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path from]))
|
||||||
|
online? (rf/sub [:visibility-status-updates/online? from])]
|
||||||
|
[quo/user-avatar
|
||||||
|
{:full-name display-name
|
||||||
|
:profile-picture photo-path
|
||||||
|
:status-indicator? true
|
||||||
|
:online? online?
|
||||||
|
:size :small
|
||||||
|
:ring? false}]))]])
|
||||||
|
|
||||||
|
(defn author
|
||||||
|
[{:keys [response-to last-in-group? pinned quoted-message from timestamp]}]
|
||||||
|
(when (or (and (seq response-to) quoted-message) last-in-group? pinned)
|
||||||
|
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from]))
|
||||||
|
{:keys [ens-verified added?]} (rf/sub [:contacts/contact-by-address from])]
|
||||||
|
[quo/author
|
||||||
|
{:profile-name display-name
|
||||||
|
:chat-key from
|
||||||
|
:time-str (time/timestamp->time timestamp)
|
||||||
|
:contact? added?
|
||||||
|
:verified? ens-verified}])))
|
||||||
|
|
||||||
|
(defn system-message-content
|
||||||
|
[{:keys [content-type quoted-message] :as message-data}]
|
||||||
|
(if quoted-message
|
||||||
|
[not-implemented/not-implemented [pin/system-message message-data]]
|
||||||
|
(case content-type
|
||||||
|
|
||||||
|
constants/content-type-system-text [not-implemented/not-implemented [system.text/text-content message-data]]
|
||||||
|
|
||||||
|
constants/content-type-community [not-implemented/not-implemented [old-message/community message-data]]
|
||||||
|
|
||||||
|
constants/content-type-contact-request [not-implemented/not-implemented [old-message/system-contact-request message-data]])))
|
||||||
|
|
||||||
|
(defn user-message-content
|
||||||
|
[{:keys [content-type quoted-message content] :as message-data}
|
||||||
|
{:keys [chat-id] :as context}]
|
||||||
|
(let [response-to (:response-to content)]
|
||||||
|
[rn/touchable-highlight
|
||||||
|
{:underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90)
|
||||||
|
:style {:border-radius 16}
|
||||||
|
:on-press #()
|
||||||
|
:on-long-press #(rf/dispatch [:bottom-sheet/show-sheet
|
||||||
|
{:content (drawers/reactions-and-actions message-data context)}])}
|
||||||
|
[rn/view {:padding-vertical 8}
|
||||||
|
(when (and (seq response-to) quoted-message)
|
||||||
|
[old-message/quoted-message {:message-id response-to :chat-id chat-id} quoted-message])
|
||||||
|
[rn/view {:padding-horizontal 12 :flex-direction :row}
|
||||||
|
[avatar message-data]
|
||||||
|
[rn/view {:margin-left 8}
|
||||||
|
[author message-data]
|
||||||
|
(case content-type
|
||||||
|
|
||||||
|
constants/content-type-text [not-implemented/not-implemented [content.text/text-content message-data]]
|
||||||
|
|
||||||
|
constants/content-type-emoji [not-implemented/not-implemented [old-message/emoji message-data]]
|
||||||
|
|
||||||
|
constants/content-type-sticker [not-implemented/not-implemented [old-message/sticker message-data]]
|
||||||
|
|
||||||
|
constants/content-type-image [not-implemented/not-implemented [old-message/message-content-image message-data]]
|
||||||
|
|
||||||
|
constants/content-type-audio [not-implemented/not-implemented [old-message/audio message-data]]
|
||||||
|
|
||||||
|
[not-implemented/not-implemented [content.unknown/unknown-content message-data]])
|
||||||
|
[status/status message-data]]]]]))
|
||||||
|
|
||||||
|
(defn message-with-reactions
|
||||||
|
[{:keys [pinned pinned-by mentioned in-pinned-view? content-type
|
||||||
|
last-in-group? message-id]
|
||||||
|
:as message-data}
|
||||||
|
{:keys [chat-id] :as context}]
|
||||||
|
[rn/view
|
||||||
|
{:style (style/message-container in-pinned-view? pinned mentioned last-in-group?)
|
||||||
|
:accessibility-label :chat-item}
|
||||||
|
(when pinned
|
||||||
|
[pin/pinned-by-view pinned-by])
|
||||||
|
(if (#{constants/content-type-system-text constants/content-type-community
|
||||||
|
constants/content-type-contact-request}
|
||||||
|
content-type)
|
||||||
|
[system-message-content message-data]
|
||||||
|
[user-message-content message-data context])
|
||||||
|
[reactions/message-reactions-row chat-id message-id]])
|
|
@ -1,4 +1,4 @@
|
||||||
(ns status-im2.contexts.chat.messages.message.delete-message.events
|
(ns status-im2.contexts.chat.messages.delete-message.events
|
||||||
(:require [status-im.chat.models.message-list :as message-list]
|
(:require [status-im.chat.models.message-list :as message-list]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
|
@ -1,7 +1,7 @@
|
||||||
(ns status-im2.contexts.chat.messages.message.delete-message.events-test
|
(ns status-im2.contexts.chat.messages.delete-message.events-test
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message.events :as delete-message]))
|
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]))
|
||||||
|
|
||||||
(def mid "message-id")
|
(def mid "message-id")
|
||||||
(def cid "chat-id")
|
(def cid "chat-id")
|
|
@ -1,4 +1,4 @@
|
||||||
(ns status-im2.contexts.chat.messages.message.delete-message-for-me.events
|
(ns status-im2.contexts.chat.messages.delete-message-for-me.events
|
||||||
(:require [status-im.chat.models.message-list :as message-list]
|
(:require [status-im.chat.models.message-list :as message-list]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
|
@ -1,8 +1,7 @@
|
||||||
(ns status-im2.contexts.chat.messages.message.delete-message-for-me.events-test
|
(ns status-im2.contexts.chat.messages.delete-message-for-me.events-test
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[status-im2.contexts.chat.messages.message.delete-message-for-me.events :as
|
[status-im2.contexts.chat.messages.delete-message-for-me.events :as delete-message-for-me]))
|
||||||
delete-message-for-me]))
|
|
||||||
|
|
||||||
(def mid "message-id")
|
(def mid "message-id")
|
||||||
(def cid "chat-id")
|
(def cid "chat-id")
|
|
@ -0,0 +1,166 @@
|
||||||
|
(ns status-im2.contexts.chat.messages.drawers.view
|
||||||
|
(:require [react-native.core :as rn]
|
||||||
|
[status-im2.common.constants :as constants]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[quo2.core :as quo]
|
||||||
|
[i18n.i18n :as i18n]
|
||||||
|
[status-im2.setup.config :as config]
|
||||||
|
[status-im.ui.components.react :as react]
|
||||||
|
[status-im.ui2.screens.chat.components.reply :as components.reply]
|
||||||
|
[status-im2.common.not-implemented :as not-implemented]))
|
||||||
|
|
||||||
|
(defn pin-message
|
||||||
|
[{:keys [chat-id pinned] :as message-data}]
|
||||||
|
(let [pinned-messages (rf/sub [:chats/pinned chat-id])]
|
||||||
|
(if (and (not pinned) (> (count pinned-messages) 2))
|
||||||
|
(do
|
||||||
|
(js/setTimeout (fn [] (rf/dispatch [:dismiss-keyboard])) 500)
|
||||||
|
(rf/dispatch [:pin-message/show-pin-limit-modal chat-id]))
|
||||||
|
(rf/dispatch [:pin-message/send-pin-message (assoc message-data :pinned (not pinned))]))))
|
||||||
|
|
||||||
|
(defn get-actions
|
||||||
|
[{:keys [outgoing content pinned] :as message-data}
|
||||||
|
{:keys [edit-enabled show-input? can-delete-message-for-everyone? community? message-pin-enabled]}]
|
||||||
|
(concat
|
||||||
|
(when (and outgoing edit-enabled)
|
||||||
|
[{:type :main
|
||||||
|
:on-press #(rf/dispatch [:chat.ui/edit-message message-data])
|
||||||
|
:label (i18n/label :t/edit-message)
|
||||||
|
:icon :i/edit
|
||||||
|
:id :edit}])
|
||||||
|
(when show-input?
|
||||||
|
[{: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 message-pin-enabled
|
||||||
|
[{:type :main
|
||||||
|
:on-press #(pin-message message-data)
|
||||||
|
: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 #(rf/dispatch [:chat.ui/delete-message-for-me message-data
|
||||||
|
constants/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 #(rf/dispatch [:chat.ui/delete-message message-data
|
||||||
|
constants/delete-message-undo-time-limit-ms])
|
||||||
|
:label (i18n/label :t/delete-for-everyone)
|
||||||
|
:icon :i/delete
|
||||||
|
:id :delete-for-all}])))
|
||||||
|
|
||||||
|
(defn extract-id
|
||||||
|
[reactions id]
|
||||||
|
(->> reactions
|
||||||
|
(filter (fn [{:keys [emoji-id]}] (= emoji-id id)))
|
||||||
|
first
|
||||||
|
:emoji-reaction-id))
|
||||||
|
|
||||||
|
(defn reactions
|
||||||
|
[chat-id message-id]
|
||||||
|
(let [reactions (rf/sub [:chats/message-reactions message-id chat-id])
|
||||||
|
own-reactions (reduce (fn [acc {:keys [emoji-id own emoji-reaction-id]}]
|
||||||
|
(if own
|
||||||
|
(assoc acc emoji-id emoji-reaction-id)
|
||||||
|
acc))
|
||||||
|
{}
|
||||||
|
reactions)]
|
||||||
|
[rn/view
|
||||||
|
{:style {:flex-direction :row
|
||||||
|
:justify-content :space-between
|
||||||
|
:padding-horizontal 30
|
||||||
|
:padding-top 5
|
||||||
|
:padding-bottom 15}}
|
||||||
|
(doall
|
||||||
|
(for [[id icon] constants/reactions]
|
||||||
|
(let [emoji-reaction-id (get own-reactions id)]
|
||||||
|
^{:key id}
|
||||||
|
[not-implemented/not-implemented
|
||||||
|
[quo/button
|
||||||
|
(merge
|
||||||
|
{:size 40
|
||||||
|
:type (if emoji-reaction-id :grey :ghost)
|
||||||
|
:icon true
|
||||||
|
:icon-no-color true
|
||||||
|
:accessibility-label (str "emoji-picker-" id)
|
||||||
|
:on-press (fn []
|
||||||
|
(if emoji-reaction-id
|
||||||
|
(rf/dispatch [:models.reactions/send-emoji-reaction-retraction
|
||||||
|
{:message-id message-id
|
||||||
|
:emoji-id id
|
||||||
|
:emoji-reaction-id emoji-reaction-id}])
|
||||||
|
(rf/dispatch [:models.reactions/send-emoji-reaction
|
||||||
|
{:message-id message-id
|
||||||
|
:emoji-id id}]))
|
||||||
|
(rf/dispatch [:bottom-sheet/hide]))})
|
||||||
|
icon]])))]))
|
||||||
|
|
||||||
|
(defn reactions-and-actions
|
||||||
|
[{:keys [message-id] :as message-data} {:keys [chat-id] :as context}]
|
||||||
|
(fn []
|
||||||
|
(let [actions (get-actions message-data context)
|
||||||
|
main-actions (filter #(= (:type %) :main) actions)
|
||||||
|
danger-actions (filter #(= (:type %) :danger) actions)
|
||||||
|
admin-actions (filter #(= (:type %) :admin) actions)]
|
||||||
|
[:<>
|
||||||
|
;; REACTIONS
|
||||||
|
[reactions chat-id message-id]
|
||||||
|
|
||||||
|
;; MAIN ACTIONS
|
||||||
|
[rn/view {:style {:padding-horizontal 8}}
|
||||||
|
(for [action main-actions]
|
||||||
|
(let [on-press (:on-press action)]
|
||||||
|
^{:key (:id action)}
|
||||||
|
[quo/menu-item
|
||||||
|
{:type :main
|
||||||
|
:title (:label action)
|
||||||
|
:accessibility-label (:label action)
|
||||||
|
:icon (:icon action)
|
||||||
|
:on-press #(do
|
||||||
|
(when on-press (on-press))
|
||||||
|
(rf/dispatch [:bottom-sheet/hide]))}]))
|
||||||
|
(when-not (empty? danger-actions)
|
||||||
|
[quo/separator])
|
||||||
|
|
||||||
|
;; DANGER ACTIONS
|
||||||
|
(for [action danger-actions]
|
||||||
|
(let [on-press (:on-press action)]
|
||||||
|
^{:key (:id action)}
|
||||||
|
[quo/menu-item
|
||||||
|
{:type :danger
|
||||||
|
:title (:label action)
|
||||||
|
:accessibility-label (:label action)
|
||||||
|
:icon (:icon action)
|
||||||
|
:on-press #(do
|
||||||
|
(when on-press (on-press))
|
||||||
|
(rf/dispatch [:bottom-sheet/hide]))}]))
|
||||||
|
(when-not (empty? admin-actions)
|
||||||
|
[quo/separator])
|
||||||
|
|
||||||
|
;; ADMIN ACTIONS
|
||||||
|
(for [action admin-actions]
|
||||||
|
(let [on-press (:on-press action)]
|
||||||
|
^{:key (:id action)}
|
||||||
|
[quo/menu-item
|
||||||
|
{:type :danger
|
||||||
|
:title (:label action)
|
||||||
|
:accessibility-label (:label action)
|
||||||
|
:icon (:icon action)
|
||||||
|
:on-press #(do
|
||||||
|
(when on-press (on-press))
|
||||||
|
(rf/dispatch [:bottom-sheet/hide]))}]))]])))
|
|
@ -8,11 +8,13 @@
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im.ui.screens.chat.group :as chat.group]
|
[status-im.ui.screens.chat.group :as chat.group]
|
||||||
[status-im.ui.screens.chat.message.gap :as gap]
|
|
||||||
[status-im.ui.screens.chat.state :as state]
|
[status-im.ui.screens.chat.state :as state]
|
||||||
[status-im.ui2.screens.chat.messages.message :as message]
|
[status-im2.contexts.chat.messages.content.view :as message]
|
||||||
[status-im2.common.constants :as constants] ;;TODO move to status-im2
|
[status-im2.common.constants :as constants]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
|
||||||
|
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||||
|
[status-im2.common.not-implemented :as not-implemented]))
|
||||||
|
|
||||||
(defonce messages-list-ref (atom nil))
|
(defonce messages-list-ref (atom nil))
|
||||||
|
|
||||||
|
@ -112,39 +114,23 @@
|
||||||
[rn/view {:style (when platform/android? {:scaleY -1})}
|
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||||
[chat.group/group-chat-footer chat-id invitation-admin]]))
|
[chat.group/group-chat-footer chat-id invitation-admin]]))
|
||||||
|
|
||||||
(defn render-fn
|
(defn render-fn [{:keys [type value deleted? deleted-for-me? content-type] :as message-data} _ _ context]
|
||||||
[{:keys [outgoing type] :as message}
|
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||||
idx
|
|
||||||
_
|
|
||||||
{:keys [group-chat public? community? current-public-key
|
|
||||||
chat-id show-input? message-pin-enabled edit-enabled in-pinned-view?
|
|
||||||
can-delete-message-for-everyone?]}]
|
|
||||||
[rn/view {:style (when (and platform/android? (not in-pinned-view?)) {:scaleY -1})}
|
|
||||||
(if (= type :datemark)
|
(if (= type :datemark)
|
||||||
[quo/divider-date (:value message)]
|
[quo/divider-date value]
|
||||||
(if (= type :gap)
|
(if (= content-type constants/content-type-gap)
|
||||||
;; TODO (flexsurfer) new gap functionality is not implemented yet
|
[not-implemented/not-implemented
|
||||||
[gap/gap message idx messages-list-ref false chat-id]
|
[message.gap/gap message-data]]
|
||||||
; message content
|
[rn/view {:padding-horizontal 8}
|
||||||
[message/chat-message
|
(if (or deleted? deleted-for-me?)
|
||||||
(assoc message
|
[content.deleted/deleted-message message-data]
|
||||||
:incoming-group (and group-chat (not outgoing))
|
[message/message-with-reactions message-data context])]))])
|
||||||
:group-chat group-chat
|
|
||||||
:public? public?
|
|
||||||
:community? community?
|
|
||||||
:current-public-key current-public-key
|
|
||||||
:show-input? show-input?
|
|
||||||
:message-pin-enabled message-pin-enabled
|
|
||||||
:edit-enabled edit-enabled
|
|
||||||
:can-delete-message-for-everyone? can-delete-message-for-everyone?)]))])
|
|
||||||
|
|
||||||
(defn messages-list
|
(defn messages-list [{:keys [chat
|
||||||
[{:keys [chat
|
pan-responder
|
||||||
bottom-space
|
show-input?]}]
|
||||||
pan-responder
|
|
||||||
mutual-contact-requests-enabled?
|
|
||||||
show-input?]}]
|
|
||||||
(let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat
|
(let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat
|
||||||
|
mutual-contact-requests-enabled? (rf/sub [:mutual-contact-requests/enabled?])
|
||||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||||
one-to-one? (= chat-type constants/one-to-one-chat-type)
|
one-to-one? (= chat-type constants/one-to-one-chat-type)
|
||||||
contact-added? (when one-to-one? (rf/sub [:contacts/contact-added? chat-id]))
|
contact-added? (when one-to-one? (rf/sub [:contacts/contact-added? chat-id]))
|
||||||
|
@ -152,8 +138,9 @@
|
||||||
(and
|
(and
|
||||||
mutual-contact-requests-enabled?
|
mutual-contact-requests-enabled?
|
||||||
one-to-one?
|
one-to-one?
|
||||||
(not contact-added?))]
|
(not contact-added?))
|
||||||
[rn/view {:style {:flex 1}}
|
bottom-space 15]
|
||||||
|
[:<>
|
||||||
;;DO NOT use anonymous functions for handlers
|
;;DO NOT use anonymous functions for handlers
|
||||||
[rn/flat-list
|
[rn/flat-list
|
||||||
(merge
|
(merge
|
||||||
|
|
|
@ -1,18 +1,36 @@
|
||||||
(ns status-im2.contexts.chat.messages.pin.list.view
|
(ns status-im2.contexts.chat.messages.pin.list.view
|
||||||
(:require [i18n.i18n :as i18n]
|
(:require [i18n.i18n :as i18n]
|
||||||
[quo2.core :as quo]
|
[quo2.core :as quo]
|
||||||
[quo2.foundations.colors :as colors] ;; TODO move to status-im2
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[status-im.ui2.screens.chat.messages.message :as old-message]
|
[status-im2.contexts.chat.messages.content.view :as message]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[status-im.utils.datetime :as time]))
|
||||||
|
|
||||||
(def list-key-fn #(or (:message-id %) (:value %)))
|
(def list-key-fn #(or (:message-id %) (:value %)))
|
||||||
|
|
||||||
(defn pinned-messages-list
|
(defn message-render-fn
|
||||||
[chat-id]
|
[{:keys [whisper-timestamp] :as message}
|
||||||
|
_
|
||||||
|
{:keys [group-chat public? community? current-public-key show-input? edit-enabled]}]
|
||||||
|
;; 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 (time/timestamp->time whisper-timestamp)
|
||||||
|
:edit-enabled edit-enabled}])
|
||||||
|
|
||||||
|
(defn pinned-messages-list [chat-id]
|
||||||
(let [pinned-messages (vec (vals (rf/sub [:chats/pinned chat-id])))
|
(let [pinned-messages (vec (vals (rf/sub [:chats/pinned chat-id])))
|
||||||
current-chat (rf/sub [:chats/current-chat])
|
current-chat (rf/sub [:chats/current-chat])
|
||||||
community (rf/sub [:communities/community (:community-id current-chat)])]
|
community (rf/sub [:communities/community (:community-id current-chat)])]
|
||||||
[rn/view {:accessibility-label :pinned-messages-list}
|
[rn/view {:accessibility-label :pinned-messages-list}
|
||||||
;; TODO (flexsurfer) this should be a component in quo2
|
;; TODO (flexsurfer) this should be a component in quo2
|
||||||
;; https://github.com/status-im/status-mobile/issues/14529
|
;; https://github.com/status-im/status-mobile/issues/14529
|
||||||
|
@ -44,7 +62,7 @@
|
||||||
(if (> (count pinned-messages) 0)
|
(if (> (count pinned-messages) 0)
|
||||||
[rn/flat-list
|
[rn/flat-list
|
||||||
{:data pinned-messages
|
{:data pinned-messages
|
||||||
:render-fn old-message/message-render-fn
|
:render-fn message-render-fn
|
||||||
:key-fn list-key-fn
|
:key-fn list-key-fn
|
||||||
:separator quo/separator}]
|
:separator quo/separator}]
|
||||||
[rn/view
|
[rn/view
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner] ;;TODO move to status-im2
|
[status-im2.contexts.chat.messages.pin.banner.view :as pin.banner] ;;TODO move to status-im2
|
||||||
[status-im2.navigation.state :as navigation.state]
|
[status-im2.navigation.state :as navigation.state]
|
||||||
[utils.debounce :as debounce]
|
[utils.debounce :as debounce]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[status-im2.common.not-implemented :as not-implemented]))
|
||||||
|
|
||||||
(defn navigate-back-handler
|
(defn navigate-back-handler
|
||||||
[]
|
[]
|
||||||
|
@ -51,28 +52,21 @@
|
||||||
:accessibility-label :back-button}
|
:accessibility-label :back-button}
|
||||||
|
|
||||||
:right-section-buttons
|
:right-section-buttons
|
||||||
[{:on-press #() ;; TODO not implemented
|
[{:on-press #()
|
||||||
|
:style {:border-width 1 :border-color :red}
|
||||||
:icon :i/options
|
:icon :i/options
|
||||||
:accessibility-label :options-button}]}]))
|
:accessibility-label :options-button}]}]))
|
||||||
|
|
||||||
(defn chat-render
|
(defn chat-render []
|
||||||
[]
|
(let [;;NOTE: we want to react only on these fields, do not use full chat map here
|
||||||
(let [;;we want to react only on these fields, do not use full chat map here
|
{:keys [chat-id show-input?] :as chat} (rf/sub [:chats/current-chat-chat-view])]
|
||||||
{:keys [chat-id show-input?] :as chat} (rf/sub [:chats/current-chat-chat-view])
|
|
||||||
mutual-contact-requests-enabled? (rf/sub [:mutual-contact-requests/enabled?])]
|
|
||||||
[rn/keyboard-avoiding-view {:style {:flex 1}}
|
[rn/keyboard-avoiding-view {:style {:flex 1}}
|
||||||
[page-nav]
|
[page-nav]
|
||||||
;; TODO (flexsurfer) this should be in-app notification component in quo2
|
[not-implemented/not-implemented
|
||||||
;; https://github.com/status-im/status-mobile/issues/14527
|
[pin-limit-popover/pin-limit-popover chat-id]]
|
||||||
[pin-limit-popover/pin-limit-popover chat-id]
|
[not-implemented/not-implemented
|
||||||
[pin.banner/banner chat-id]
|
[pin.banner/banner chat-id]]
|
||||||
;;MESSAGES LIST
|
[messages.list/messages-list {:chat chat :show-input? show-input?}]
|
||||||
[messages.list/messages-list
|
|
||||||
{:chat chat
|
|
||||||
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?
|
|
||||||
:show-input? show-input?
|
|
||||||
:bottom-space 15}]
|
|
||||||
;;INPUT COMPOSER
|
|
||||||
(when show-input?
|
(when show-input?
|
||||||
[composer/composer chat-id])]))
|
[composer/composer chat-id])]))
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
{:padding-vertical 60
|
{:padding-vertical 60
|
||||||
:align-items :center}
|
:align-items :center}
|
||||||
[quo2.reaction/reaction @state]
|
[quo2.reaction/reaction @state]
|
||||||
[quo2.reaction/open-reactions-menu @state]]]])))
|
[quo2.reaction/add-reaction @state]]]])))
|
||||||
|
|
||||||
(defn preview-react
|
(defn preview-react
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -171,7 +171,7 @@ class ChatElementByText(Text):
|
||||||
def username(self):
|
def username(self):
|
||||||
class Username(Text):
|
class Username(Text):
|
||||||
def __init__(self, driver, parent_locator: str):
|
def __init__(self, driver, parent_locator: str):
|
||||||
super().__init__(driver, prefix=parent_locator, xpath="/android.widget.TextView[1]")
|
super().__init__(driver, prefix=parent_locator, xpath="/android.view.ViewGroup/android.widget.TextView[1]")
|
||||||
|
|
||||||
return Username(self.driver, self.locator)
|
return Username(self.driver, self.locator)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue