diff --git a/.carve_ignore b/.carve_ignore index 9f72912b66..caa11565b5 100644 --- a/.carve_ignore +++ b/.carve_ignore @@ -1,7 +1,7 @@ status-im.utils.build/warning-handler status-im.utils.build/get-current-sha -status-im.chat.constants/spacing-char -status-im.chat.constants/arg-wrapping-char +status-im2.common.constants/spacing-char +status-im2.common.constants/arg-wrapping-char status-im.ios.core/init status-im.ui.components.camera/aspects status-im.ui.components.camera/capture-targets diff --git a/resources/chats.json b/resources/chats.json deleted file mode 100644 index 6003dcd400..0000000000 --- a/resources/chats.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "chats": [ - ["Featured", [ - "status", - "support", - "crypto", - "chitchat", - "defi", - "markets", - "dap-ps", - "devcon", - "eth2" - ]], - - ["General", [ - "chitchat", - "hello", - "worldnews", - "status", - "support" - ]], - - ["Entertainment", [ - "music", - "movies", - "podcasts", - "books", - "gaming", - "adult", - "tv-shows" - ]], - - ["Interests", [ - "sports", - "travel", - "design", - "food", - "automotive" - ]], - - ["Society", [ - "climatechange", - "blacklivesmatter", - "politics", - "hongkong", - "privacy" - ]], - - ["Crypto", [ - "crypto", - "markets", - "crypto-education", - "ethereum", - "bitcoin", - "chainlink", - "avalanche", - "eth2", - "eips", - "dap-ps", - "cryptolife", - "governance", - "staking", - "defi", - "cryptopayments", - "tokenomics", - "web3", - "web3design", - "devcon", - "exchange", - "validators" - ]], - - ["Technologies", [ - "tech", - "ai", - "vr-ar", - "networks" - ]], - - ["Status", [ - "status", - "support", - "statusphere", - "status-townhall-questions", - "status-core-ui", - "status-keycard", - "nimbus-general", - "status-assemble", - "status-marketing", - "status-protocol", - "status-desktop", - "status-watercooler", - "status-security", - "waku", - "status-docs", - "status-general", - "status-design" - ]], - - ["Development", [ - "ethereum-clients", - "storage", - "indexing", - "sidechains", - "layer2", - "devops", - "smart-contracts", - "embark-community", - "subspace", - "open-source", - "security" - ]], - - ["Languages", [ - "status-espanol", - "statusbrasil", - "status-german", - "status-french", - "status-italiano", - "status-dutch", - "status-russian", - "status-chinese", - "status-korean", - "status-japanese", - "status-farsi", - "status-turkish", - "status-filipino", - "status-naija", - "status-indian", - "status-arabic", - "indonesian" - ]] - ] -} diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 1ecc0d606b..e03174e264 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -58,8 +58,7 @@ ;; in the SHADOW_HOST env variable to make sure that ;; it will use the right interface :local-ip #shadow/env "SHADOW_HOST"} - :chunks {:fleets status-im.fleet.default-fleet/default-fleets - :chats status-im.chat.default-chats/default-chats} + :chunks {:fleets status-im.fleet.default-fleet/default-fleets} :release {:closure-defines {status-im.utils.config/POKT_TOKEN #shadow/env "POKT_TOKEN" diff --git a/src/mocks/js_dependencies.cljs b/src/mocks/js_dependencies.cljs index 372856a5da..c77112d486 100644 --- a/src/mocks/js_dependencies.cljs +++ b/src/mocks/js_dependencies.cljs @@ -1,8 +1,7 @@ (ns mocks.js-dependencies (:require-macros [status-im.utils.slurp :refer [slurp]]) (:require [status-im.fleet.default-fleet :refer (default-fleets)]) - (:require [status-im.utils.test :as utils.test]) - (:require [status-im.chat.default-chats :refer (default-chats)])) + (:require [status-im.utils.test :as utils.test])) ;; to generate a js Proxy at js/__STATUS_MOBILE_JS_IDENTITY_PROXY__ that accept any (.xxx) call and ;; return itself @@ -398,7 +397,6 @@ globalThis.__STATUS_MOBILE_JS_IDENTITY_PROXY__ = new Proxy({}, {get() { return ( "../src/js/bottom_sheet.js" bottom-sheet "../src/js/record_audio_worklets.js" record-audio-worklets "./fleets.js" default-fleets - "./chats.js" default-chats "@walletconnect/client" wallet-connect-client "../translations/ar.json" (js/JSON.parse (slurp "./translations/ar.json")) "../translations/de.json" (js/JSON.parse (slurp "./translations/de.json")) diff --git a/src/react_native/core.cljs b/src/react_native/core.cljs index f5328e7f91..24fe910d70 100644 --- a/src/react_native/core.cljs +++ b/src/react_native/core.cljs @@ -109,3 +109,11 @@ (let [fn-ref (use-ref f)] (oops/oset! fn-ref "current" f) (use-effect-once (fn [] (fn [] (oops/ocall! fn-ref "current")))))) + +(def layout-animation (.-LayoutAnimation ^js react-native)) +(def configure-next (.-configureNext ^js layout-animation)) + +(def layout-animation-presets + {:ease-in-ease-out (-> ^js layout-animation .-Presets .-easeInEaseOut) + :linear (-> ^js layout-animation .-Presets .-linear) + :spring (-> ^js layout-animation .-Presets .-spring)}) diff --git a/src/status_im/chat/constants.cljs b/src/status_im/chat/constants.cljs deleted file mode 100644 index d89d45bc97..0000000000 --- a/src/status_im/chat/constants.cljs +++ /dev/null @@ -1,16 +0,0 @@ -(ns status-im.chat.constants) - -(def command-char "/") -(def spacing-char " ") -(def arg-wrapping-char "\"") - -(def spam-message-frequency-threshold 4) -(def spam-interval-ms 1000) -(def default-cooldown-period-ms 10000) -(def cooldown-reset-threshold 3) -(def cooldown-periods-ms - {1 2000 - 2 5000 - 3 10000}) - -(def max-text-size 4096) diff --git a/src/status_im/chat/db.cljs b/src/status_im/chat/db.cljs index 62c37b17db..3dd6c98707 100644 --- a/src/status_im/chat/db.cljs +++ b/src/status_im/chat/db.cljs @@ -5,10 +5,6 @@ [{:keys [public? name]}] (str (when public? "#") name)) -(defn datemark? - [{:keys [type]}] - (= type :datemark)) - (defn intersperse-datemark "Reduce step which expects the input list of messages to be sorted by clock value. It makes best effort to group them by day. diff --git a/src/status_im/chat/default_chats.cljs b/src/status_im/chat/default_chats.cljs deleted file mode 100644 index 3b982c1569..0000000000 --- a/src/status_im/chat/default_chats.cljs +++ /dev/null @@ -1,4 +0,0 @@ -(ns status-im.chat.default-chats (:require-macros [status-im.utils.slurp :refer [slurp]])) - -(def default-chats - (slurp "resources/chats.json")) \ No newline at end of file diff --git a/src/status_im/chat/models.cljs b/src/status_im/chat/models.cljs index 12c645d8bd..6d2881e601 100644 --- a/src/status_im/chat/models.cljs +++ b/src/status_im/chat/models.cljs @@ -4,27 +4,22 @@ [re-frame.core :as re-frame] [status-im.add-new.db :as new-public-chat.db] [status-im.chat.models.loading :as loading] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [status-im.constants :as constants] [status-im.data-store.chats :as chats-store] [status-im.data-store.contacts :as contacts-store] [i18n.i18n :as i18n] [status-im.mailserver.core :as mailserver] [status-im.multiaccounts.model :as multiaccounts.model] - [status-im.ui.screens.chat.state :as chat.state] + [status-im2.contexts.chat.messages.list.state :as chat.state] [status-im.utils.clocks :as utils.clocks] [utils.re-frame :as rf] - [status-im.utils.types :as types] [status-im.utils.utils :as utils] [status-im2.contexts.chat.messages.delete-message-for-me.events :as delete-for-me] [status-im2.contexts.chat.messages.delete-message.events :as delete-message] [status-im2.navigation.events :as navigation] [taoensso.timbre :as log])) -(defn chats - [] - (:chats (types/json->clj (js/require "./chats.js")))) - (defn- get-chat [cofx chat-id] (get-in cofx [:db :chats chat-id])) diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs index c77bff2c19..99cc25dbd1 100644 --- a/src/status_im/chat/models/input.cljs +++ b/src/status_im/chat/models/input.cljs @@ -3,7 +3,7 @@ [clojure.string :as string] [goog.object :as object] [re-frame.core :as re-frame] - [status-im.chat.constants :as chat.constants] + [status-im2.common.constants :as chat.constants] [status-im.chat.models :as chat] [status-im.chat.models.mentions :as mentions] [status-im.chat.models.message :as chat.message] diff --git a/src/status_im/chat/models/input_test.cljs b/src/status_im/chat/models/input_test.cljs index 344a589501..f3c24ae43a 100644 --- a/src/status_im/chat/models/input_test.cljs +++ b/src/status_im/chat/models/input_test.cljs @@ -1,6 +1,6 @@ (ns status-im.chat.models.input-test (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.chat.constants :as constants] + [status-im2.common.constants :as constants] [status-im.chat.models.input :as input] [utils.datetime :as datetime])) diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index 750b2d2db6..1b82f55661 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -1,6 +1,6 @@ (ns status-im.chat.models.loading (:require [re-frame.core :as re-frame] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [status-im.constants :as constants] [status-im.data-store.chats :as data-store.chats] [status-im.data-store.messages :as data-store.messages] diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs index 12698b57c6..b490f8cc14 100644 --- a/src/status_im/chat/models/message.cljs +++ b/src/status_im/chat/models/message.cljs @@ -4,11 +4,11 @@ [status-im.chat.models :as chat-model] [status-im.chat.models.loading :as chat.loading] [status-im.chat.models.mentions :as mentions] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [status-im.constants :as constants] [status-im.data-store.messages :as data-store.messages] [status-im.transport.message.protocol :as protocol] - [status-im.ui.screens.chat.state :as view.state] + [status-im2.contexts.chat.messages.list.state :as view.state] [utils.re-frame :as rf] [status-im.utils.gfycat.core :as gfycat] [status-im.utils.platform :as platform] diff --git a/src/status_im/chat/models/message_content.cljs b/src/status_im/chat/models/message_content.cljs index 35fe027cb8..d90a665c85 100644 --- a/src/status_im/chat/models/message_content.cljs +++ b/src/status_im/chat/models/message_content.cljs @@ -1,11 +1,6 @@ (ns status-im.chat.models.message-content (:require [status-im.constants :as constants])) -(def stylings - [[:bold constants/regx-bold] - [:italic constants/regx-italic] - [:backquote constants/regx-backquote]]) - (defn emoji-only-content? "Determines if text is just an emoji" [{:keys [text response-to]}] diff --git a/src/status_im/chat/models/message_test.cljs b/src/status_im/chat/models/message_test.cljs index 0978f3a75d..48284f4e84 100644 --- a/src/status_im/chat/models/message_test.cljs +++ b/src/status_im/chat/models/message_test.cljs @@ -2,7 +2,7 @@ (:require [cljs.test :refer-macros [deftest is testing]] [status-im.chat.models.loading :as loading] [status-im.chat.models.message :as message] - [status-im.ui.screens.chat.state :as view.state])) + [status-im2.contexts.chat.messages.list.state :as list.state])) (deftest add-received-message-test (with-redefs [message/add-message #(identity %1)] @@ -26,7 +26,7 @@ ;; <- message ;; <- top of the chat (testing "there's no hidden item" - (with-redefs [view.state/first-not-visible-item (atom nil)] + (with-redefs [list.state/first-not-visible-item (atom nil)] (is (= {:db @@ -46,7 +46,7 @@ ;; <- message ;; <- top of the chat (testing "the hidden item has a clock value less than the current" - (with-redefs [view.state/first-not-visible-item (atom {:clock-value (dec clock-value)})] + (with-redefs [list.state/first-not-visible-item (atom {:clock-value (dec clock-value)})] (is (= {:db @@ -66,7 +66,7 @@ ;; <- first-hidden-item ;; <- top of the chat (testing "the message falls between the first-hidden-item and cursor" - (with-redefs [view.state/first-not-visible-item (atom {:clock-value (inc clock-value)})] + (with-redefs [list.state/first-not-visible-item (atom {:clock-value (inc clock-value)})] (let [result (dissoc (message/receive-many cofx #js {:messages (to-array [message])}) @@ -81,7 +81,7 @@ ;; <- first-hidden-item ;; <- top of the chat (testing "the message falls between the first-hidden-item and cursor is nil" - (with-redefs [view.state/first-not-visible-item (atom {:clock-value (inc clock-value)})] + (with-redefs [list.state/first-not-visible-item (atom {:clock-value (inc clock-value)})] (let [result (dissoc (message/receive-many (update-in cofx [:db :pagination-info chat-id] @@ -101,7 +101,7 @@ ;; <- first-hidden-item ;; <- top of the chat (testing "the message falls before both the first-hidden-item and cursor" - (with-redefs [view.state/first-not-visible-item (atom {:clock-value (inc clock-value)})] + (with-redefs [list.state/first-not-visible-item (atom {:clock-value (inc clock-value)})] (let [message #js {:localChatId chat-id :clock (- clock-value 2) diff --git a/src/status_im/contact/block.cljs b/src/status_im/contact/block.cljs index fa664b1fd1..4a5bf82684 100644 --- a/src/status_im/contact/block.cljs +++ b/src/status_im/contact/block.cljs @@ -1,6 +1,6 @@ (ns status-im.contact.block (:require [re-frame.core :as re-frame] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [status-im.contact.db :as contact.db] [status-im.data-store.chats :as chats-store] [status-im.data-store.contacts :as contacts-store] diff --git a/src/status_im/profile/db.cljs b/src/status_im/profile/db.cljs deleted file mode 100644 index 423d8c6fc4..0000000000 --- a/src/status_im/profile/db.cljs +++ /dev/null @@ -1,22 +0,0 @@ -(ns status-im.profile.db - (:require [cljs.spec.alpha :as spec] - [clojure.string :as string] - [status-im.chat.constants :as chat.constants])) - -(defn correct-name? - [username] - (when-let [username (some-> username - (string/trim))] - (every? false? - [(string/blank? username) - (string/includes? username chat.constants/command-char)]))) - -(defn base64-png? - [photo-path] - (string/starts-with? photo-path "data:image/png;base64,")) - -(defn base64-jpeg? - [photo-path] - (string/starts-with? photo-path "data:image/jpeg;base64,")) - -(spec/def :profile/name correct-name?) \ No newline at end of file diff --git a/src/status_im/ui/components/chat_icon/screen.cljs b/src/status_im/ui/components/chat_icon/screen.cljs index fc050ce110..ba3bb8c2f2 100644 --- a/src/status_im/ui/components/chat_icon/screen.cljs +++ b/src/status_im/ui/components/chat_icon/screen.cljs @@ -4,7 +4,6 @@ [quo.react-native :as rn] [re-frame.core :as re-frame.core] [status-im.multiaccounts.core :as multiaccounts] - [status-im.profile.db :as profile.db] [status-im.ui.components.chat-icon.styles :as styles] [status-im.ui.components.icons.icons :as icons] [status-im.ui.screens.chat.photos :as photos] @@ -55,7 +54,8 @@ styles/container-chat-list photo-container) size (:width photo-container) - identicon? (when photo-path (profile.db/base64-png? photo-path)) + identicon? (and photo-path + (string/starts-with? photo-path "data:image/png;base64,")) dot-styles (visibility-status-utils/icon-visibility-status-dot public-key size diff --git a/src/status_im/ui/screens/add_new/new_public_chat/view.cljs b/src/status_im/ui/screens/add_new/new_public_chat/view.cljs index 5e20412aa2..6a7d5cd2fc 100644 --- a/src/status_im/ui/screens/add_new/new_public_chat/view.cljs +++ b/src/status_im/ui/screens/add_new/new_public_chat/view.cljs @@ -3,11 +3,9 @@ [quo.design-system.colors :as colors] [re-frame.core :as re-frame] [status-im.add-new.db :as db] - [status-im.chat.models :as chat.models] [status-im.react-native.resources :as resources] [status-im.ui.components.icons.icons :as icons] [status-im.ui.components.react :as react] - [status-im2.setup.i18n-resources :as i18n-resources] [i18n.i18n :as i18n]) (:require-macros [status-im.utils.views :as views])) @@ -37,59 +35,6 @@ :auto-correct false :error error}]) -(defn render-topic - [topic] - [react/touchable-highlight - {:on-press #(start-chat topic) - :accessibility-label :chat-item} - [react/view - {:border-color colors/gray-lighter - :border-radius 36 - :border-width 1 - :padding-horizontal 8 - :padding-vertical 5 - :margin-right 8 - :margin-vertical 8} - [react/text {:style {:color colors/blue :typography :main-medium}} - (str "#" topic)]]]) - -(def lang-names - {"es" "status-espanol" - "pt" "statusbrasil" - "de" "status-german" - "fr" "status-french" - "it" "status-italiano" - "ru" "status-russian" - "zh" "status-chinese" - "ko" "status-korean" - "ja" "status-japanese" - "fa" "status-farsi" - "tr" "status-turkish" - "id" "indonesian" - "in" "indonesian" - "hi" "status-indian" - "ar" "status-arabic" - "fil" "status-filipino" - "nl" "status-dutch"}) - -(defn get-language-topic - [] - (let [lang (subs (name i18n-resources/default-device-language) 0 2) - lang3 (subs (name i18n-resources/default-device-language) 0 3) - lang-name (or (get lang-names lang3) (get lang-names lang))] - (when-not (= lang "en") - (or lang-name (str "status-" lang))))) - -(def section-featured "Featured") - -(defn featured-public-chats - [] - (let [lang-topic (get-language-topic) - chats (some #(when (= section-featured (first %)) (second %)) (chat.models/chats))] - (if lang-topic - (conj chats lang-topic) - chats))) - (views/defview new-public-chat [] (views/letsubs [topic [:public-group-topic] diff --git a/src/status_im/ui/screens/chat/audio_message/styles.cljs b/src/status_im/ui/screens/chat/audio_message/styles.cljs deleted file mode 100644 index 16d064558e..0000000000 --- a/src/status_im/ui/screens/chat/audio_message/styles.cljs +++ /dev/null @@ -1,50 +0,0 @@ -(ns status-im.ui.screens.chat.audio-message.styles - (:require [quo.design-system.colors :as colors])) - -(def container - {:flex 1 - :flex-direction :column - :justify-content :space-around}) - -(def timer - {:font-size 28 - :line-height 38 - :align-self :center}) - -(def buttons-container - {:flex 1 - :max-height 80 - :flex-direction :row - :align-items :center - :justify-content :space-around - :align-self :stretch - :padding-horizontal 80}) - -(def rec-button-base-size 61) - -(def rec-button-container - {:width rec-button-base-size - :height rec-button-base-size - :align-items "center"}) - -(defn rec-outer-circle - [scale-anim] - {:position "absolute" - :width rec-button-base-size - :height rec-button-base-size - :top 0 - :border-width 4 - :transform [{:scale scale-anim}] - :border-color colors/red-audio-recorder - :border-radius rec-button-base-size}) - -(defn rec-inner-circle - [scale-anim border-radius-anim] - {:position "absolute" - :top 6 - :left 6 - :bottom 6 - :right 6 - :transform [{:scale scale-anim}] - :border-radius border-radius-anim - :background-color colors/red-audio-recorder}) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/audio_message/views.cljs b/src/status_im/ui/screens/chat/audio_message/views.cljs deleted file mode 100644 index 069a92ede0..0000000000 --- a/src/status_im/ui/screens/chat/audio_message/views.cljs +++ /dev/null @@ -1,323 +0,0 @@ -(ns status-im.ui.screens.chat.audio-message.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [goog.string :as gstring] - [quo.components.animated.pressable :as pressable] - [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [status-im.audio.core :as audio] - [i18n.i18n :as i18n] - [status-im.native-module.core :as status] - [status-im.ui.components.animation :as anim] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.audio-message.styles :as styles] - [status-im.ui.screens.chat.components.input :as input] - [status-im.ui.screens.chat.components.style :as input.style] - [status-im.utils.fs :as fs] - [utils.re-frame :as rf] - [status-im.utils.utils :as utils.utils])) - -;; reference db levels -(def total-silence-db -160) -(def silence-db -35) - -;; update interval for the pulsing rec button -(def metering-interval 100) - -;; rec pulse animation target -(defonce visual-target-value (anim/create-value total-silence-db)) -;;ensure animation finishes before next meter update -(defonce metering-anim-duration (int (* metering-interval 0.9))) - -(defn update-meter - [meter-data] - (let [value (if meter-data - (.-value ^js meter-data) - total-silence-db)] - (anim/start (anim/timing visual-target-value - {:toValue value - :duration metering-anim-duration - :useNativeDriver true})))) - -(def base-filename "am.") -(def default-format "aac") -(def rec-options - (merge - audio/default-recorder-options - {:filename (str base-filename default-format) - :meteringInterval metering-interval})) - -;; maximum 1 minute of recordings time to keep data at certain size -(def max-recording-ms (* 1 60 1000)) - -;; audio objects -(defonce recorder-ref (atom nil)) -(defonce player-ref (atom nil)) - -(defn destroy-recorder - [] - (audio/destroy-recorder @recorder-ref) - (reset! recorder-ref nil)) - -(defn destroy-player - [] - (audio/destroy-player @player-ref) - (reset! player-ref nil)) - -;; state update callback -(defonce state-cb (atom #())) - -;; max recording ms reached callback -(defonce max-recording-reached-cb (atom #())) - -;; to be called when app goes in background -(defonce on-background-cb (atom #())) - -(rf/defn on-background - {:events [:audio-recorder/on-background]} - [_] - (when @on-background-cb - (@on-background-cb)) - nil) - -;; during recording -(defonce recording-timer (atom nil)) -(defonce recording-start-ts (atom nil)) -(defonce recording-backlog-ms (atom 0)) - -;; updates timer UI -(defn update-timer - [timer] - (let [ms (if @recording-start-ts - (+ - (- (js/Date.now) @recording-start-ts) - @recording-backlog-ms) - @recording-backlog-ms) - s (quot ms 1000)] - (if (> ms max-recording-ms) - (@max-recording-reached-cb) - (reset! timer (gstring/format "%d:%02d" (quot s 60) (mod s 60)))))) - -(defn reset-timer - [timer] - (reset! timer "0:00") - (reset! recording-backlog-ms 0)) - -(defn animate-buttons - [rec? show-ctrl? {:keys [rec-button-anim-value ctrl-buttons-anim-value]}] - (anim/start - (anim/parallel - [(anim/timing rec-button-anim-value - {:toValue (if rec? 1 0) - :duration 100 - :useNativeDriver true}) - (anim/timing ctrl-buttons-anim-value - {:toValue (if show-ctrl? 1 0) - :duration 100 - :useNativeDriver true})]))) - -(defn start-recording - [{:keys [timer] :as params}] - (if (> @recording-backlog-ms max-recording-ms) - (@max-recording-reached-cb) - (do - (animate-buttons true true params) - (reset! recording-start-ts (js/Date.now)) - (reset! recording-timer (utils.utils/set-interval #(update-timer timer) 1000)) - (audio/start-recording - @recorder-ref - @state-cb - #(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %)))))) - -(defn reload-recorder - [] - (when @recorder-ref - (destroy-recorder)) - (reset! recorder-ref (audio/new-recorder rec-options #(update-meter %) @state-cb)) - ;; we skip preparation since if a recorder is prepared, player wont play - (@state-cb)) - -(defn reload-player - ([] (reload-player nil)) - ([on-success] - (when @player-ref - (destroy-player)) - (reset! player-ref (audio/new-player - (:filename rec-options) - {:autoDestroy false - :continuesToPlayInBackground false} - @state-cb)) - (audio/prepare-player - @player-ref - #(do (@state-cb) (when on-success (on-success))) - #(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %))))) - -(defn stop-recording - [{:keys [on-success timer max-recording-reached?] :as params}] - (when @recording-timer - (utils.utils/clear-interval @recording-timer) - (reset! recording-timer nil)) - (if max-recording-reached? - (reset! recording-backlog-ms (+ @recording-backlog-ms (- (js/Date.now) @recording-start-ts))) - (reset-timer timer)) - (audio/stop-recording - @recorder-ref - #(do - (update-meter nil) - (reload-recorder) - (reload-player on-success)) - #(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %))) - (animate-buttons false max-recording-reached? params)) - -(defn pause-recording - [{:keys [timer] :as params}] - (when @recording-timer - (utils.utils/clear-interval @recording-timer) - (reset! recording-backlog-ms (+ @recording-backlog-ms (- (js/Date.now) @recording-start-ts))) - (reset! recording-start-ts nil) - (reset! recording-timer nil) - (update-timer timer)) - (audio/pause-recording - @recorder-ref - #(do (update-meter nil) - (@state-cb)) - #(utils.utils/show-popup (i18n/label :t/audio-recorder-error) (:message %))) - (animate-buttons false true params)) - -(defn update-state - "update main UI state. - general states are: - - :recording - - :playing - - :ready-to-send - - :recording-paused - - :ready-to-record" - [state-ref] - (let [player-state (audio/get-state @player-ref) - recorder-state (audio/get-state @recorder-ref) - output-file (or - (audio/get-recorder-file-path @recorder-ref) - (:output-file @state-ref)) - general (cond - (= recorder-state audio/RECORDING) :recording - (= player-state audio/PLAYING) :playing - (= player-state audio/PREPARED) :ready-to-send - (= recorder-state audio/PAUSED) :recording-paused - :else :ready-to-record) - new-state {:general general - :cancel-disabled? (nil? (#{:recording :recording-paused :ready-to-send} general)) - :output-file output-file - :duration (audio/get-player-duration @player-ref)}] - (if (#{:recording :recording-paused} general) - (status/activate-keep-awake) - (status/deactivate-keep-awake)) - (when (not= @state-ref new-state) - (reset! state-ref new-state)))) - -(defn send-audio-msessage - [state-ref] - (re-frame/dispatch [:chat/send-audio - (:output-file @state-ref) - (int (:duration @state-ref))]) - (destroy-player) - (@state-cb)) - -;; rec-button-anim-value 0 => stopped, 1 => recording -(defview rec-button-view - [{:keys [rec-button-anim-value state] :as params}] - (letsubs [outer-scale (anim/interpolate visual-target-value - {:inputRange [total-silence-db silence-db 0] - :outputRange [1 0.8 1.2]}) - inner-scale (anim/interpolate rec-button-anim-value - {:inputRange [0 1] - :outputRange [1 0.5]}) - inner-border-radius (anim/interpolate rec-button-anim-value - {:inputRange [0 1] - :outputRange [styles/rec-button-base-size 16]})] - [react/touchable-highlight - {:on-press #(if (= (:general @state) :recording) - (pause-recording params) - (start-recording params)) - :accessibility-label :start-stop-audio-recording-button} - [react/view {:style styles/rec-button-container} - [react/animated-view {:style (styles/rec-outer-circle outer-scale)}] - [react/animated-view {:style (styles/rec-inner-circle inner-scale inner-border-radius)}]]])) - -(defn- cancel-button - [disabled? on-press contact-request] - [pressable/pressable - {:type :scale - :disabled disabled? - :on-press on-press} - [react/view {:style (input.style/send-message-button)} - [icons/icon :main-icons/close - {:container-style (merge (input.style/send-message-container contact-request) - {:background-color colors/gray}) - :accessibility-label :cancel-message-button - :color colors/white-persist}]]]) - -(defview audio-message-view - [] - (letsubs [rec-button-anim-value (anim/create-value 0) - ctrl-buttons-anim-value (anim/create-value 0) - timer (reagent/atom "") - state (reagent/atom nil)] - {:component-did-mount (fn [] - (reset-timer timer) - (reset! state-cb #(update-state state)) - (reset! max-recording-reached-cb - #(do - (when (= (:general @state) :recording) - (stop-recording {:rec-button-anim-value rec-button-anim-value - :ctrl-buttons-anim-value ctrl-buttons-anim-value - :timer timer - :max-recording-reached? true})) - (utils.utils/show-popup (i18n/label :t/audio-recorder) - (i18n/label - :t/audio-recorder-max-ms-reached)))) - (reset! on-background-cb #(when (= (:general @state) :recording) - (pause-recording - {:rec-button-anim-value rec-button-anim-value - :ctrl-buttons-anim-value - ctrl-buttons-anim-value - :timer timer}))) - (reload-recorder)) - :component-will-unmount (fn [] - (when @recording-timer - (utils.utils/clear-interval @recording-timer) - (reset! recording-timer nil)) - (destroy-recorder) - (destroy-player) - (when (:output-file @state) - ; possible issue if message is not yet sent? - (fs/unlink (:output-file @state))) - (reset! state-cb nil) - (reset! max-recording-reached-cb nil) - (reset! on-background-cb nil))} - (let [base-params {:rec-button-anim-value rec-button-anim-value - :ctrl-buttons-anim-value ctrl-buttons-anim-value - :timer timer} - contact-request @(re-frame/subscribe [:chats/sending-contact-request])] - [react/view {:style styles/container} - [react/text - {:style styles/timer - :accessibility-label :audio-message-recorded-time} @timer] - [react/view {:style styles/buttons-container} - [react/animated-view {:style {:opacity ctrl-buttons-anim-value}} - [cancel-button (:cancel-disabled? @state) #(stop-recording base-params) contact-request]] - [rec-button-view (merge base-params {:state state})] - [react/animated-view {:style {:opacity ctrl-buttons-anim-value}} - [input/send-button - (fn [] - (cond - (= :ready-to-send (:general @state)) - (do - (reset-timer timer) - (animate-buttons false false base-params) - (send-audio-msessage state)) - - (#{:recording :recording-paused} (:general @state)) - (stop-recording (merge base-params - {:on-success - #(send-audio-msessage state)}))))]]]]))) diff --git a/src/status_im/ui/screens/chat/components/input.cljs b/src/status_im/ui/screens/chat/components/input.cljs index b5b63686f2..cca6841d18 100644 --- a/src/status_im/ui/screens/chat/components/input.cljs +++ b/src/status_im/ui/screens/chat/components/input.cljs @@ -9,7 +9,7 @@ [quo.react-native :as rn] [re-frame.core :as re-frame] [reagent.core :as reagent] - [status-im.chat.constants :as chat.constants] + [status-im2.common.constants :as chat.constants] [status-im.chat.models.mentions :as mentions] [i18n.i18n :as i18n] [status-im.multiaccounts.core :as multiaccounts] diff --git a/src/status_im/ui/screens/chat/extensions/views.cljs b/src/status_im/ui/screens/chat/extensions/views.cljs deleted file mode 100644 index 7a2806fb3c..0000000000 --- a/src/status_im/ui/screens/chat/extensions/views.cljs +++ /dev/null @@ -1,53 +0,0 @@ -(ns status-im.ui.screens.chat.extensions.views - (:require [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [i18n.i18n :as i18n] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.react :as react])) - -(defn extensions-view - [] - [react/view - {:style {:background-color colors/white - :flex 1}} - [react/view {:style {:flex-direction :row}} - [react/touchable-highlight - {:on-press #(re-frame/dispatch [:wallet/prepare-transaction-from-chat])} - [react/view - {:width 128 - :height 128 - :justify-content :space-between - :padding-horizontal 10 - :padding-vertical 12 - :background-color (colors/alpha colors/purple 0.2) - :border-radius 16 - :margin-left 8} - [react/view - {:background-color colors/purple - :width 40 - :height 40 - :border-radius 20 - :align-items :center - :justify-content :center} - [icons/icon :main-icons/send {:color colors/white}]] - [react/text {:typography :medium} (i18n/label :t/send-transaction)]]] - [react/touchable-highlight - {:on-press #(re-frame/dispatch [:wallet/prepare-request-transaction-from-chat])} - [react/view - {:width 128 - :height 128 - :justify-content :space-between - :padding-horizontal 10 - :padding-vertical 12 - :background-color (colors/alpha colors/orange 0.2) - :border-radius 16 - :margin-left 8} - [react/view - {:background-color colors/orange - :width 40 - :height 40 - :border-radius 20 - :align-items :center - :justify-content :center} - [icons/icon :main-icons/receive {:color colors/white}]] - [react/text {:typography :medium} (i18n/label :t/request-transaction)]]]]]) diff --git a/src/status_im/ui/screens/chat/group.cljs b/src/status_im/ui/screens/chat/group.cljs index 0605f49ffe..bea5601915 100644 --- a/src/status_im/ui/screens/chat/group.cljs +++ b/src/status_im/ui/screens/chat/group.cljs @@ -4,11 +4,8 @@ [re-frame.core :as re-frame] [status-im.constants :as constants] [i18n.i18n :as i18n] - [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.styles.main :as style] [status-im.utils.platform :as platform] - [status-im.utils.universal-links.utils :as links] [utils.debounce :as debounce]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) @@ -76,124 +73,3 @@ (letsubs [invitations [:group-chat/invitations-by-chat-id chat-id]] (when invitation-admin [request-membership (first invitations)]))) - -(def group-chat-description-loading - [react/view - {:style (merge style/intro-header-description-container - {:margin-bottom 36 - :height 44})} - [react/text {:style style/intro-header-description} - (i18n/label :t/loading)] - [react/activity-indicator - {:animating true - :size :small - :color colors/gray}]]) - -(defn calculate-quiet-time - [synced-to - synced-from] - (when synced-from - (let [quiet-hours (quot (- synced-to synced-from) - (* 60 60))] - (if (<= quiet-hours 24) - (i18n/label :t/quiet-hours - {:quiet-hours quiet-hours}) - (i18n/label :t/quiet-days - {:quiet-days (quot quiet-hours 24)}))))) - -(defview no-messages-community-chat-description-container - [chat-id] - (letsubs [{:keys [synced-to synced-from]} - [:chats/synced-to-and-from chat-id]] - [react/text - {:style (merge style/intro-header-description - {:margin-bottom 36})} - (let [quiet-time (calculate-quiet-time synced-to - synced-from)] - (i18n/label :t/empty-chat-description-community - {:quiet-hours quiet-time}))])) - -(defview no-messages-private-group-chat-description-container - [chat-id] - (letsubs [{:keys [synced-to synced-from]} - [:chats/synced-to-and-from chat-id]] - (let [quiet-time (calculate-quiet-time synced-to - synced-from)] - [react/nested-text - {:style (merge style/intro-header-description - {:margin-bottom 36})} - (if quiet-time - (i18n/label :t/empty-chat-description-public - {:quiet-hours quiet-time}) - (i18n/label :t/cleared-chat-description-public)) - [{:style {:color colors/blue} - :on-press #(list-selection/open-share - {:message - (i18n/label - :t/share-public-chat-text - {:link (links/generate-link :public-chat :external chat-id)})})} - (i18n/label :t/empty-chat-description-public-share-this)]]))) - -(defview pending-invitation-description - [inviter-pk chat-name] - (letsubs [inviter-name [:contacts/contact-name-by-identity inviter-pk]] - [react/nested-text {:style style/intro-header-description} - [{:style {:color colors/black}} inviter-name] - (i18n/label :t/join-group-chat-description - {:username "" - :group-name chat-name})])) - -(defview joined-group-chat-description - [inviter-pk chat-name] - (letsubs [inviter-name [:contacts/contact-name-by-identity inviter-pk]] - [react/nested-text {:style style/intro-header-description} - (i18n/label :t/joined-group-chat-description - {:username "" - :group-name chat-name}) - [{:style {:color colors/black}} inviter-name]])) - -(defn created-group-chat-description - [chat-name] - [react/text {:style style/intro-header-description} - (i18n/label :t/created-group-chat-description - {:group-name chat-name})]) - -(defview group-chat-inviter-description-container - [chat-id chat-name] - (letsubs [{:keys [member? inviter-pk]} - [:group-chat/inviter-info chat-id]] - (cond - (not member?) - [pending-invitation-description inviter-pk chat-name] - inviter-pk - [joined-group-chat-description inviter-pk chat-name] - :else - [created-group-chat-description chat-name]))) - -(defn group-chat-membership-description - [] - [react/text {:style {:text-align :center :margin-horizontal 30}} - (i18n/label :t/membership-description)]) - -(defn group-chat-description-container - [{:keys [invitation-admin - chat-id - chat-name - chat-type - loading-messages? - no-messages?]}] - (cond - loading-messages? - group-chat-description-loading - - (and no-messages? (= chat-type constants/public-chat-type)) - [no-messages-private-group-chat-description-container chat-id] - - (and no-messages? (= chat-type constants/community-chat-type)) - [no-messages-community-chat-description-container chat-id] - - invitation-admin - [group-chat-membership-description] - - (= chat-type constants/private-group-chat-type) - [group-chat-inviter-description-container chat-id chat-name])) diff --git a/src/status_im/ui/screens/chat/image/views.cljs b/src/status_im/ui/screens/chat/image/views.cljs deleted file mode 100644 index 880e51fbe8..0000000000 --- a/src/status_im/ui/screens/chat/image/views.cljs +++ /dev/null @@ -1,128 +0,0 @@ -(ns status-im.ui.screens.chat.image.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [quo.components.animated.pressable :as pressable] - [quo.core :as quo] - [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [i18n.i18n :as i18n] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.permissions :as permissions] - [status-im.ui.components.react :as react] - [status-im.utils.config :as config] - [status-im.utils.utils :as utils])) - -(defn take-picture - [] - (permissions/request-permissions - {:permissions [:camera] - :on-allowed #(re-frame/dispatch [:chat.ui/show-image-picker-camera]) - :on-denied (fn [] - (utils/set-timeout - #(utils/show-popup (i18n/label :t/error) - (i18n/label :t/camera-access-error)) - 50))})) - -(defn show-image-picker - [] - (permissions/request-permissions - {:permissions [:read-external-storage :write-external-storage] - :on-allowed #(re-frame/dispatch [:chat.ui/open-image-picker]) - :on-denied (fn [] - (utils/set-timeout - #(utils/show-popup (i18n/label :t/error) - (i18n/label :t/external-storage-denied)) - 50))})) - -(defn buttons - [] - [react/view - [pressable/pressable - {:type :scale - :accessibility-label :take-picture - :on-press take-picture} - [react/view {:style {:padding 10}} - [icons/icon :main-icons/camera]]] - [react/view {:style {:padding-top 8}} - [pressable/pressable - {:on-press show-image-picker - :accessibility-label :open-gallery - :type :scale} - [react/view {:style {:padding 10}} - [icons/icon :main-icons/gallery]]]]]) - -(defn image-preview - [uri all-selected first? panel-height] - (let [wh (/ (- panel-height 8) 2) - selected (get all-selected uri) - max-selected (>= (count all-selected) config/max-images-batch)] - [react/touchable-highlight - {:on-press #(if selected - (re-frame/dispatch [:chat.ui/image-unselected uri]) - (re-frame/dispatch [:chat.ui/camera-roll-pick uri])) - :disabled (and max-selected (not selected))} - [react/view - {:style (merge {:width wh - :height wh - :border-radius 4 - :overflow :hidden} - (when (and (not selected) max-selected) - {:opacity 0.5}) - (when first? - {:margin-bottom 4}))} - [react/image - {:style (merge {:width wh - :height wh - :background-color :black - :resize-mode :cover - :border-radius 4}) - :source {:uri uri}}] - (when selected - [react/view - {:style {:position :absolute - :top 0 - :bottom 0 - :left 0 - :right 0 - :padding 10 - :background-color (:highlight @colors/theme) - :align-items :flex-end}} - [quo/radio {:value true}]])]])) - -(defview photos - [] - (letsubs [camera-roll-photos [:camera-roll/photos] - selected [:chats/sending-image] - panel-height (reagent/atom nil)] - [react/view - {:style {:flex 1 - :flex-direction :row} - :on-layout #(reset! panel-height (.-nativeEvent.layout.height ^js %))} - (let [height @panel-height] - (for [[first-img second-img] (partition 2 camera-roll-photos)] - ^{:key (str "image" first-img)} - [react/view {:margin-left 4} - (when first-img - [image-preview first-img selected true height]) - (when second-img - [image-preview second-img selected false height])]))])) - -(defview image-view - [] - {:component-did-mount - (fn [] - (permissions/request-permissions - {:permissions [:read-external-storage :write-external-storage] - :on-allowed #(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20]) - :on-denied (fn [] - (utils/set-timeout - #(utils/show-popup (i18n/label :t/error) - (i18n/label :t/external-storage-denied)) - 50))}))} - [react/animated-view - {:style {:background-color (:ui-background @colors/theme) - :flex 1}} - [react/scroll-view {:horizontal true :style {:flex 1}} - [react/view {:flex 1 :flex-direction :row :margin-horizontal 4} - [buttons] - [photos]]]]) diff --git a/src/status_im/ui/screens/chat/message/audio_old.cljs b/src/status_im/ui/screens/chat/message/audio_old.cljs deleted file mode 100644 index 25fef359d3..0000000000 --- a/src/status_im/ui/screens/chat/message/audio_old.cljs +++ /dev/null @@ -1,272 +0,0 @@ -(ns status-im.ui.screens.chat.message.audio-old - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require ["react-native-blob-util" :default ReactNativeBlobUtil] - [goog.string :as gstring] - [quo.design-system.colors :as colors] - [reagent.core :as reagent] - [status-im.audio.core :as audio] - [status-im.ui.components.animation :as anim] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.react :as react] - [status-im.ui.components.slider :as slider] - [status-im.ui.screens.chat.styles.message.audio-old :as style] - [utils.re-frame :as rf] - [status-im.utils.platform :as platform] - [status-im.utils.utils :as utils] - [taoensso.timbre :as log])) - -(defonce player-ref (atom nil)) -(defonce current-player-message-id (atom nil)) -(defonce current-active-state-ref-ref (atom nil)) -(defonce progress-timer (atom nil)) - -(defn start-stop-progress-timer - [{:keys [state-ref progress-ref progress-anim]} start?] - (when @progress-timer - (utils/clear-interval @progress-timer) - (when-not start? - (reset! progress-timer nil))) - (when start? - (when @progress-timer - (utils/clear-interval @progress-timer)) - (reset! progress-timer - (utils/set-interval - #(when (and @state-ref (not (:slider-seeking @state-ref))) - (let [ct (audio/get-player-current-time @player-ref)] - (reset! progress-ref ct) - (when ct - (anim/start (anim/timing progress-anim - {:toValue @progress-ref - :duration 100 - :easing (.-linear ^js anim/easing) - :useNativeDriver true}))))) - 100)))) - -(defn update-state - [{:keys [state-ref progress-ref progress-anim message-id seek-to-ms audio-duration-ms - slider-new-state-seeking? unloaded? error]}] - (let [player-state (audio/get-state @player-ref) - slider-seeking (if (some? slider-new-state-seeking?) - slider-new-state-seeking? - (:slider-seeking @state-ref)) - general (cond - (some? error) :error - (or unloaded? (not= message-id @current-player-message-id)) :not-loaded - slider-seeking (:general - @state-ref) ; persist - ; player - ; state - ; at - ; the - ; time - ; user - ; started - ; sliding - (= player-state audio/PLAYING) :playing - (= player-state audio/PAUSED) :paused - (= player-state audio/SEEKING) :seeking - (= player-state audio/PREPARED) :ready-to-play - :else :preparing) - new-state {:general general - :error-msg error - :duration (cond (not (#{:preparing :not-loaded :error} general)) - (audio/get-player-duration @player-ref) - - audio-duration-ms audio-duration-ms - - :else (:duration @state-ref)) - :progress-ref (or progress-ref (:progress-ref @state-ref)) - :progress-anim (or progress-anim (:progress-anim @state-ref)) - :slider-seeking slider-seeking - - ; persist seek-to-ms while seeking or audio is not loaded - :seek-to-ms (when (or - slider-seeking - (#{:preparing :not-loaded :error} general)) - (or seek-to-ms (:seek-to-ms @state-ref)))}] - ; update state if needed - (when (not= @state-ref new-state) - (reset! state-ref new-state)) - - ; update progress UI on slider release - (when (and (some? slider-new-state-seeking?) (not slider-new-state-seeking?) (some? seek-to-ms)) - (reset! (:progress-ref new-state) seek-to-ms)) - - ; update progres anim value to follow the slider - (when (and slider-seeking (some? seek-to-ms)) - (anim/set-value (:progress-anim new-state) seek-to-ms)) - - ; on unload, reset values - (when unloaded? - (reset! (:progress-ref new-state) 0) - (anim/set-value (:progress-anim new-state) 0)))) - -(defn destroy-player - [{:keys [message-id reloading?]}] - (when (and @player-ref - (or reloading? - (= message-id @current-player-message-id))) - (audio/destroy-player @player-ref) - (reset! player-ref nil) - (when @current-active-state-ref-ref - (update-state {:state-ref @current-active-state-ref-ref :unloaded? true})) - (reset! current-player-message-id nil) - (reset! current-active-state-ref-ref nil))) - -(defonce last-seek (atom (js/Date.now))) - -(defn seek - [{:keys [message-id] :as params} value immediate? on-success] - (when (and @player-ref (= message-id @current-player-message-id)) - (let [now (js/Date.now)] - (when (or immediate? (> (- now @last-seek) 200)) - (reset! last-seek (js/Date.now)) - (audio/seek-player - @player-ref - value - #(do - (update-state params) - (when on-success (on-success))) - #(update-state (merge params {:error (:message %)})))))) - (update-state (merge params {:seek-to-ms value}))) - -(defn download-audio-http - [base64-uri on-success] - (-> (.config ReactNativeBlobUtil (clj->js {:trusty platform/ios?})) - (.fetch "GET" (str base64-uri)) - (.then #(on-success (.base64 ^js %))) - (.catch #(log/error "could not fetch audio")))) - -(defn reload-player - [{:keys [message-id state-ref] :as params} audio-url on-success] - ;; to avoid reloading player while is initializing, - ;; we go ahead only if there is no player or - ;; if it is already prepared - (when (or (nil? @player-ref) (audio/can-play? @player-ref)) - (when @player-ref - (destroy-player (merge params {:reloading? true}))) - (download-audio-http - audio-url - (fn [base64-data] - (reset! player-ref (audio/new-player - (str "data:audio/acc;base64," base64-data) - {:autoDestroy false - :continuesToPlayInBackground false} - #(seek params 0 true nil))) - (audio/prepare-player - @player-ref - #(when on-success (on-success)) - #(update-state (merge params {:error (:message %)}))) - (reset! current-player-message-id message-id) - (reset! current-active-state-ref-ref state-ref) - (update-state params))))) - -(defn play-pause - [{:keys [message-id state-ref] :as params} audio] - (if (not= message-id @current-player-message-id) - ;; player has audio from another message, we need to reload - (reload-player params - audio - ;; on-success: audio is loaded, do we have an existing value to seek to? - #(if-some [seek-time (:seek-to-ms @state-ref)] - ;; check seek time against real audio duration and play - (let [checked-seek-time (min (audio/get-player-duration @player-ref) seek-time)] - (seek params - checked-seek-time - true - (fn [] (play-pause params audio)))) - - ;; nothing to seek to, play - (play-pause params audio))) - - ;; loaded audio corresponds to current message we can play - (when @player-ref - (audio/toggle-playpause-player - @player-ref - #(do - (start-stop-progress-timer params true) - (update-state params)) - #(do - (start-stop-progress-timer params false) - (update-state params)) - #(update-state (merge params {:error (:message %)})))))) - -(defn- play-pause-button - [state-ref outgoing on-press] - (let [color (if outgoing colors/blue colors/white-persist)] - (if (= (:general @state-ref) :preparing) - [react/view {:style (style/play-pause-container outgoing true)} - [react/small-loading-indicator color]] - [react/touchable-highlight {:on-press on-press} - [icons/icon - (case (:general @state-ref) - :playing :main-icons/pause - :main-icons/play) - {:container-style (style/play-pause-container outgoing false) - :accessibility-label :play-pause-audio-message-button - :color color}]]))) - -(rf/defn on-background - {:events [:audio-message/on-background]} - [_] - (when (and @current-active-state-ref-ref - @@current-active-state-ref-ref) - (update-state {:state-ref @current-active-state-ref-ref - :message-id @current-player-message-id})) - nil) - -(defview message-content - [{:keys [audio audio-duration-ms message-id outgoing]}] - (letsubs [state (reagent/atom nil) - progress (reagent/atom 0) - progress-anim (anim/create-value 0) - width [:dimensions/window-width]] - {:component-did-mount (fn [] - (update-state {:state-ref state - :audio-duration-ms audio-duration-ms - :message-id message-id - :unloaded? true - :progress-ref progress - :progress-anim progress-anim})) - :component-will-unmount (fn [] - (destroy-player {:state-ref state :message-id message-id}) - (when (= @current-player-message-id message-id) - (reset! current-active-state-ref-ref nil) - (reset! current-player-message-id nil)) - (reset! state nil))} - - (let [base-params {:state-ref state - :message-id message-id - :progress-ref progress - :progress-anim progress-anim}] - (if (= (:general @state) :error) - [react/text - {:style {:typography :main-medium - :margin-bottom 16}} (:error-msg @state)] - [react/view (style/container width) - [react/view style/play-pause-slider-container - [play-pause-button state outgoing #(play-pause base-params audio)] - [react/view style/slider-container - [slider/animated-slider - (merge (style/slider outgoing) - {:minimum-value 0 - :maximum-value (:duration @state) - :value progress-anim - :on-value-change #(seek base-params % false nil) - :on-sliding-start #(seek (merge base-params {:slider-new-state-seeking? true}) - % - true - nil) - :on-sliding-complete #(seek (merge base-params {:slider-new-state-seeking? false}) - % - true - nil)})]]] - - [react/view style/times-container - [react/text {:style (style/timestamp outgoing)} - (let [time (cond - (or (:slider-seeking @state) (> (:seek-to-ms @state) 0)) (:seek-to-ms @state) - (#{:playing :paused :seeking} (:general @state)) @progress - :else (:duration @state)) - s (quot time 1000)] - (gstring/format "%02d:%02d" (quot s 60) (mod s 60)))]]])))) diff --git a/src/status_im/ui/screens/chat/message/command.cljs b/src/status_im/ui/screens/chat/message/command.cljs deleted file mode 100644 index c189906821..0000000000 --- a/src/status_im/ui/screens/chat/message/command.cljs +++ /dev/null @@ -1,285 +0,0 @@ -(ns status-im.ui.screens.chat.message.command - (:require [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [status-im.commands.core :as commands] - [status-im.constants :as constants] - [status-im.ethereum.transactions.core :as transactions] - [i18n.i18n :as i18n] - [status-im.ui.components.chat-icon.screen :as chat-icon] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.react :as react] - [status-im.utils.money :as money] - [status-im.utils.utils :as utils])) - -(defn- final-status? - [command-state] - (or (= command-state constants/command-state-request-address-for-transaction-declined) - (= command-state constants/command-state-request-transaction-declined) - (= command-state constants/command-state-transaction-sent))) - -(defn- command-pending-status - [command-state direction to transaction-type] - [react/view - {:style {:flex-direction :row - :height 28 - :align-items :center - :border-width 1 - :border-color colors/gray-lighter - :border-radius 16 - :padding-horizontal 8 - :margin-right 12 - :margin-bottom 2}} - [icons/icon :tiny-icons/tiny-pending - {:width 16 - :height 16 - :color colors/gray - :container-style {:margin-right 6}}] - [react/text - {:style {:color colors/gray - :font-weight "500" - :line-height 16 - :margin-right 4 - :font-size 13}} - (if (and (or (= command-state constants/command-state-request-transaction) - (= command-state constants/command-state-request-address-for-transaction-accepted)) - (= direction :incoming)) - (str (i18n/label :t/shared) - " '" - (or (:name @(re-frame/subscribe [:account-by-address to])) - (utils/get-shortened-checksum-address to)) - "'") - (i18n/label (cond - (= command-state constants/command-state-transaction-pending) - :t/status-pending - (= command-state constants/command-state-request-address-for-transaction) - :t/address-requested - (= command-state constants/command-state-request-address-for-transaction-accepted) - :t/address-request-accepted - (= command-state constants/command-state-transaction-sent) - (case transaction-type - :pending :t/status-pending - :failed :t/transaction-failed - :t/status-confirmed) - (= command-state constants/command-state-request-transaction) - :t/address-received)))]]) - -(defn- command-final-status - [command-state _ transaction-type] - [react/view - {:style {:flex-direction :row - :height 28 - :align-items :center - :border-width 1 - :border-color colors/gray-lighter - :border-radius 16 - :padding-horizontal 8 - :margin-right 12 - :margin-bottom 2}} - (if (or (= command-state constants/command-state-request-address-for-transaction-declined) - (= command-state constants/command-state-request-transaction-declined) - (= :failed transaction-type)) - [icons/icon :tiny-icons/tiny-warning-background - {:width 16 - :height 16 - :container-style {:margin-right 6}}] - (if (= :pending transaction-type) - [icons/icon :tiny-icons/tiny-pending - {:color colors/gray - :width 16 - :height 16 - :container-style {:margin-right 6}}] - [icons/icon :tiny-icons/tiny-check - {:width 16 - :height 16 - :container-style {:margin-right 6}}])) - [react/text - {:style (merge {:margin-right 4 - :line-height 16 - :font-size 13} - (if (= transaction-type :pending) - {:color colors/gray} - {:font-weight "500"}))} - (i18n/label - (if (or (= command-state constants/command-state-request-address-for-transaction-declined) - (= command-state constants/command-state-request-transaction-declined)) - :t/transaction-declined - (case transaction-type - :pending :t/status-pending - :failed :t/transaction-failed - :t/status-confirmed)))]]) - -(defn- command-status-and-timestamp - [command-state direction to timestamp-str transaction-type] - [react/view - {:style {:flex-direction :row - :align-items :flex-end - :justify-content :space-between}} - (if (final-status? command-state) - [command-final-status command-state direction transaction-type] - [command-pending-status command-state direction to transaction-type]) - [react/text - {:style {:font-size 10 - :line-height 12 - :text-align-vertical :bottom - :color colors/gray}} - timestamp-str]]) - -(defn- command-actions - [accept-label on-accept on-decline] - [react/view - [react/touchable-highlight - {:on-press #(do (react/dismiss-keyboard!) - (on-accept)) - :style {:border-color colors/gray-lighter - :border-top-width 1 - :margin-top 8 - :margin-horizontal -12 - :padding-horizontal 15 - :padding-vertical 10}} - [react/text - {:style {:text-align :center - :color colors/blue - :font-weight "500" - :font-size 15 - :line-height 22}} - (i18n/label accept-label)]] - (when on-decline - [react/touchable-highlight - {:on-press on-decline - :style {:border-color colors/gray-lighter - :border-top-width 1 - :margin-horizontal -12 - :padding-top 10}} - [react/text - {:style {:text-align :center - :color colors/blue - :font-size 15 - :line-height 22}} - (i18n/label :t/decline)]])]) - -(defn- command-transaction-info - [contract value] - (let [{:keys [symbol symbol-display icon decimals color] :as token} - (if (seq contract) - (get @(re-frame/subscribe [:wallet/all-tokens]) - contract - transactions/default-erc20-token) - @(re-frame/subscribe [:ethereum/native-currency])) - symbol (or symbol-display symbol) - amount (money/internal->formatted value symbol decimals) - {:keys [code]} - @(re-frame/subscribe [:wallet/currency]) - prices @(re-frame/subscribe [:prices]) - amount-fiat (money/fiat-amount-value amount symbol (keyword code) prices)] - [react/view - {:style {:flex-direction :row - :margin-top 8 - :margin-bottom 12}} - (if icon - [react/image - (-> icon - (assoc-in [:style :height] 24) - (assoc-in [:style :width] 24))] - [react/view - {:style {:margin-right 14 - :padding-vertical 2 - :justify-content :flex-start - :max-width 40 - :align-items :center - :align-self :stretch}} - [chat-icon/custom-icon-view-list (:name token) color 24]]) - [react/view {:style {:margin-left 6}} - [react/text - {:style {:margin-bottom 2 - :font-size 20 - :line-height 24}} - (str (money/to-fixed amount) " " (name symbol))] - [react/text - {:style {:font-size 12 - :line-height 16 - :color colors/gray}} - (str amount-fiat " " code)]]])) - -(defn calculate-direction - [outgoing command-state] - (if (#{constants/command-state-request-address-for-transaction-accepted - constants/command-state-request-address-for-transaction-declined - constants/command-state-request-transaction} - command-state) - (if outgoing :incoming :outgoing) - (if outgoing :outgoing :incoming))) - -(defn command-content - [wrapper - {:keys [message-id - chat-id - outgoing - command-parameters - timestamp-str] - :as message}] - (let [{:keys [contract value address command-state transaction-hash]} command-parameters - direction (calculate-direction outgoing command-state) - transaction (when transaction-hash - @(re-frame/subscribe - [:wallet/account-by-transaction-hash - transaction-hash]))] - [wrapper (assoc message :outgoing (= direction :outgoing)) - [react/touchable-highlight - {:on-press #(when (:address transaction) - (re-frame/dispatch [:wallet.ui/show-transaction-details - transaction-hash (:address transaction)]))} - [react/view - {:padding-horizontal 12 - :padding-bottom 10 - :padding-top 10 - :margin-top 4 - :border-width 1 - :border-color colors/gray-lighter - :border-radius 16 - (case direction - :outgoing :border-bottom-right-radius - :incoming :border-bottom-left-radius) - 4 - :background-color colors/white} - [react/text - {:style {:font-size 13 - :line-height 18 - :font-weight "500" - :color colors/gray}} - (case direction - :outgoing (str "↑ " (i18n/label :t/outgoing-transaction)) - :incoming (str "↓ " (i18n/label :t/incoming-transaction)))] - [command-transaction-info contract value] - [command-status-and-timestamp - ;; If :type is nil it most likely means the transaction is pending, as those - ;; are not stored and will be gone after logout - command-state direction address timestamp-str (or (:type transaction) :pending)] - (when (not outgoing) - (cond - (= command-state constants/command-state-request-transaction) - [command-actions - :t/sign-and-send - #(re-frame/dispatch - [:wallet.ui/accept-request-transaction-button-clicked-from-command - chat-id - command-parameters]) - #(re-frame/dispatch [::commands/decline-request-transaction message-id])] - - (= command-state - constants/command-state-request-address-for-transaction-accepted) - [command-actions - :t/sign-and-send - #(re-frame/dispatch - [:wallet.ui/accept-request-transaction-button-clicked-from-command - chat-id - command-parameters])] - - (= command-state constants/command-state-request-address-for-transaction) - [command-actions - :t/accept-and-share-address - #(re-frame/dispatch - [::commands/prepare-accept-request-address-for-transaction - message]) - #(re-frame/dispatch - [::commands/decline-request-address-for-transaction - message-id])]))]]])) diff --git a/src/status_im/ui/screens/chat/message/datemark.cljs b/src/status_im/ui/screens/chat/message/datemark.cljs deleted file mode 100644 index 731554638f..0000000000 --- a/src/status_im/ui/screens/chat/message/datemark.cljs +++ /dev/null @@ -1,19 +0,0 @@ -(ns status-im.ui.screens.chat.message.datemark - (:require [clojure.string :as string] - [quo2.components.markdown.text :as quo2.text] - [quo2.foundations.colors :as quo2.colors] - [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.styles.message.datemark :as style])) - -(defn chat-datemark - [value] - [react/touchable-without-feedback - {:on-press (fn [_] - (react/dismiss-keyboard!))} - [react/view style/datemark-mobile - [quo2.text/text - {:weight :medium - :accessibility-label :message-datemark-text - :style {:color quo2.colors/neutral-50}} - (string/capitalize value)] - [react/view (style/divider)]]]) diff --git a/src/status_im/ui/screens/chat/message/datemark_old.cljs b/src/status_im/ui/screens/chat/message/datemark_old.cljs deleted file mode 100644 index 26f21b110b..0000000000 --- a/src/status_im/ui/screens/chat/message/datemark_old.cljs +++ /dev/null @@ -1,13 +0,0 @@ -(ns status-im.ui.screens.chat.message.datemark-old - (:require [clojure.string :as string] - [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.styles.message.datemark-old :as style])) - -(defn chat-datemark - [value] - [react/touchable-without-feedback - {:on-press (fn [_] - (react/dismiss-keyboard!))} - [react/view style/datemark-mobile - [react/text {:style (style/datemark-text)} - (string/capitalize value)]]]) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/message/link_preview.cljs b/src/status_im/ui/screens/chat/message/link_preview.cljs deleted file mode 100644 index df018266a2..0000000000 --- a/src/status_im/ui/screens/chat/message/link_preview.cljs +++ /dev/null @@ -1,181 +0,0 @@ -(ns status-im.ui.screens.chat.message.link-preview - (:require [clojure.string :as string] - [quo.core :as quo] - [re-frame.core :as re-frame] - [status-im.chat.models.link-preview :as link-preview] - [status-im.constants :as constants] - [i18n.i18n :as i18n] - [status-im.react-native.resources :as resources] - [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.message.styles :as styles] - [status-im.ui.screens.communities.icon :as communities.icon] - [utils.security.core :as security]) - (:require-macros [status-im.utils.views :refer [defview letsubs]])) - -(defn link-belongs-to-domain - [link domain] - (cond - (string/starts-with? link (str "https://" domain)) true - (string/starts-with? link (str "https://www." domain)) true - :else false)) - -(defn community-id-from-link - [link] - (nth (re-find constants/regx-community-universal-link link) 4)) - -(defn domain-info-if-whitelisted - [link whitelist] - (first (filter - #(link-belongs-to-domain link (:address %)) - whitelist))) - -(defn link-extended-info - [link whitelist enabled-list] - (let [domain-info (domain-info-if-whitelisted link whitelist) - community-id (community-id-from-link link)] - (if-not community-id - {:whitelisted (not (nil? domain-info)) - :enabled (contains? enabled-list (:title domain-info)) - :link link} - {:whitelisted true - :enabled true - :link link - :community true}))) - -(defn previewable-link - [links whitelist enabled-list] - (->> links - (map #(link-extended-info % whitelist enabled-list)) - (filter #(:whitelisted %)) - (first))) - -(defview link-preview-enable-request - [] - [react/view (styles/link-preview-request-wrapper) - [react/view {:margin 12} - [react/image - {:source (resources/get-theme-image :unfurl) - :style styles/link-preview-request-image}] - [quo/text - {:size :small - :align :center - :style {:margin-top 6}} - (i18n/label :t/enable-link-previews)] - [quo/text - {:size :small - :color :secondary - :align :center - :style {:margin-top 2}} - (i18n/label :t/once-enabled-share-metadata)]] - [quo/separator] - [quo/button - {:on-press #(re-frame/dispatch [:open-modal :link-preview-settings]) - :type :secondary} - (i18n/label :enable)] - [quo/separator] - [quo/button - {:on-press #(re-frame/dispatch - [::link-preview/should-suggest-link-preview false]) - :type :secondary} - (i18n/label :t/dont-ask)]]) - -(defn is-gif? - [url] - (string/ends-with? url ".gif")) - -(defview link-preview-loader - [link outgoing timeline] - (letsubs [cache [:link-preview/cache]] - (let [{:keys [site title thumbnailUrl error] :as preview-data} (get cache link)] - (if (not preview-data) - (do - (re-frame/dispatch - [::link-preview/load-link-preview-data link]) - nil) - (when-not error - [react/touchable-highlight - {:style (when-not (is-gif? thumbnailUrl) {:align-self :stretch}) - :on-press #(when (security/safe-link? link) - (re-frame/dispatch - [:browser.ui/message-link-pressed link]))} - [react/view (styles/link-preview-wrapper outgoing timeline) - (when-not (string/blank? thumbnailUrl) - [react/image - {:source {:uri thumbnailUrl} - :style (styles/link-preview-image outgoing - (select-keys preview-data - [:height :width])) - :accessibility-label :member-photo}]) - (when-not (is-gif? thumbnailUrl) - [:<> - [quo/text - {:size :small - :style styles/link-preview-title} - title] - [quo/text - {:size :small - :color :secondary - :style styles/link-preview-site} - site]])]]))))) - -(defview community-preview - [community outgoing timeline] - (let [{:keys [name members description verified]} community - members-count (count members)] - [react/view (styles/link-preview-wrapper outgoing timeline) - (if verified - [quo/text - {:size :small - :color :link - :style styles/community-preview-header} - (i18n/label :t/verified-community)] - [quo/text - {:size :small - :color :secondary - :style styles/community-preview-header} - (i18n/label :t/community)]) - [quo/separator] - [react/view {:flex-direction :row :align-self :flex-start :margin 12} - [communities.icon/community-icon community] - [react/view {:flex 1 :flex-direction :column :margin-left 12} - [quo/text {:weight :bold :size :large} name] - [quo/text description] - [quo/text - {:size :small - :color :secondary} - (i18n/label-pluralize members-count :t/community-members {:count members-count})]]] - [quo/separator] - [quo/button - {:on-press #(re-frame/dispatch [:navigate-to - :community - {:from-chat true - :community-id (:id community)}]) - :type :secondary} - (i18n/label :t/view)]])) - -(defview community-preview-loader - [community-link outgoing timeline] - (letsubs [cache [:link-preview/cache]] - {:component-did-mount (fn [] - (let [community (get cache community-link) - community-id (community-id-from-link community-link)] - (when-not community - (re-frame/dispatch - [::link-preview/resolve-community-info community-id]))))} - (when-let [community (get cache community-link)] - [community-preview community outgoing timeline]))) - -(defview link-preview-wrapper - [links outgoing timeline] - (letsubs - [ask-user? [:link-preview/link-preview-request-enabled] - whitelist [:link-previews-whitelist] - enabled-sites [:link-preview/enabled-sites]] - (when links - (let [link-info (previewable-link links whitelist enabled-sites) - {:keys [link whitelisted enabled community]} link-info - link-whitelisted (and link whitelisted)] - (cond - community [community-preview-loader link outgoing timeline] - (and link-whitelisted enabled) [link-preview-loader link outgoing timeline] - (and link-whitelisted ask-user?) [link-preview-enable-request]))))) diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index 6268f18079..e69de29bb2 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -1,841 +0,0 @@ -(ns status-im.ui.screens.chat.message.message - (:require - [quo.core :as quo] - [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [status-im.chat.models.images :as images] - [status-im.constants :as constants] - [i18n.i18n :as i18n] - [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.icons.icons :as icons] - [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.components.reply :as components.reply] - [status-im.ui.screens.chat.image.preview.views :as preview] - [status-im.ui.screens.chat.message.audio-old :as message.audio] - [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.link-preview :as link-preview] - [status-im.ui.screens.chat.message.reactions-old :as reactions] - [status-im.ui.screens.chat.photos :as photos] - [status-im.ui.screens.chat.sheets :as sheets] - [status-im.ui.screens.chat.styles.message.message-old :as style] - [status-im.ui.screens.chat.utils :as chat.utils] - [status-im.ui.screens.communities.icon :as communities.icon] - [status-im.utils.config :as config] - [utils.security.core :as security]) - (:require-macros [status-im.utils.views :refer [defview letsubs]])) - -(defn message-timestamp-anim - [anim-opacity show-timestamp?] - (animation/start - (animation/anim-sequence - [(animation/timing - anim-opacity - {:toValue 1 - :duration 100 - :easing (.-ease ^js animation/easing) - :useNativeDriver true}) - (animation/timing - anim-opacity - {:toValue 0 - :delay 2000 - :duration 100 - :easing (.-ease ^js animation/easing) - :useNativeDriver true})]) - #(reset! show-timestamp? false))) - -(defview mention-element - [from] - (letsubs [contact-name [:contacts/contact-name-by-identity from]] - contact-name)) - -(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 - [react/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 colors/gray colors/white) - :accessibility-label (name outgoing-status)}]) - (when edited-at - [react/text {:style (style/message-status-text (and outgoing (not pinned)))} edited-at-text])])) - -(defn message-timestamp - [{:keys [timestamp-str in-popover?] :as message} show-timestamp?] - (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)] - [react/animated-view {:style (style/message-timestamp-wrapper message) :opacity anim-opacity} - (when @show-timestamp? (message-timestamp-anim anim-opacity show-timestamp?)) - [react/text - {:style (style/message-timestamp-text) - :accessibility-label :message-timestamp} - timestamp-str]]))) - -(defn quoted-message - [_ {:keys [from parsed-text image audio sticker id] :as message} outgoing current-public-key public? - pinned chat-id] - (let [contact-name [:contacts/contact-name-by-identity from] - replied-message (get @(re-frame/subscribe [:chats/chat-messages chat-id]) id)] ;; the message - ;; replied to - [react/view {:style (style/quoted-message-container (and outgoing (not pinned)))} - [react/view {:style style/quoted-message-author-container} - [chat.utils/format-reply-author - from - contact-name - current-public-key - (partial style/quoted-message-author (and outgoing (not pinned))) - (and outgoing (not pinned))]] - (cond - (and image (not public?)) ;; Disabling images for public-chats - [fast-image/fast-image - {:style {:width 56 - :height 56 - :background-color :black - :border-radius 4} - :source {:uri image}}] - (and audio (not public?)) ;; Disabling audio for public-chats - [react/view {:style (style/message-view message) :accessibility-label :audio-message} - [react/view {:style (style/message-view-content)} - [react/view {:style (style/style-message-text outgoing)} - [message.audio/message-content message] - [message-status message]]]] - sticker - (if replied-message - [fast-image/fast-image - {:style {:margin 4 :width 56 :height 56} - ;; Get sticker url of the message replied to - :source {:uri (((replied-message :content) :sticker) :url)}}] - ;; Let the user know if the message was deleted - [react/text {:style (style/quoted-message-text (and outgoing (not pinned)))} - ;; This hardcorded text can be modified to come from the parsed-text. Also, translations can be - ;; added. - "This message was deleted!"]) - :else [react/text - {:style (style/quoted-message-text (and outgoing - (not pinned))) - :number-of-lines 5} - (components.reply/get-quoted-text-with-mentions parsed-text)])])) - -(defn render-inline - [message-text outgoing pinned content-type acc {:keys [type literal destination]}] - (case type - "" - (conj acc literal) - - "code" - (conj acc - [quo/text - {:max-font-size-multiplier react/max-font-size-multiplier - :style (style/inline-code-style) - :monospace true} - literal]) - - "emph" - (conj acc [react/text-class (style/emph-style (and outgoing (not pinned))) literal]) - - "strong" - (conj acc [react/text-class (style/strong-style (and outgoing (not pinned))) literal]) - - "strong-emph" - (conj acc [quo/text (style/strong-emph-style (and outgoing (not pinned))) literal]) - - "del" - (conj acc [react/text-class (style/strikethrough-style (and outgoing (not pinned))) literal]) - - "link" - (conj acc - [react/text-class - {:style - {:color (if (and outgoing (not pinned)) colors/white-persist colors/blue) - :text-decoration-line :underline} - :on-press - #(when (and (security/safe-link? destination) - (security/safe-link-text? message-text)) - (re-frame/dispatch - [:browser.ui/message-link-pressed destination]))} - destination]) - - "mention" - (conj acc - [react/text-class - {:style {:color (cond - (= content-type constants/content-type-system-text) colors/black - (and outgoing (not pinned)) colors/mention-outgoing - :else colors/mention-incoming)} - :on-press (when-not (= content-type constants/content-type-system-text) - #(re-frame/dispatch [:chat.ui/show-profile literal]))} - [mention-element literal]]) - "status-tag" - (conj - acc - [react/text-class - {:style {:color (if (and outgoing (not pinned)) colors/white-persist colors/blue) - :text-decoration-line :underline} - :on-press - #(re-frame/dispatch - [:chat.ui/start-public-chat literal])} - "#" - literal]) - - (conj acc literal))) - -(defn render-block - [{:keys [content outgoing content-type pinned in-popover?]} acc - {:keys [type ^js literal children]}] - (case type - - "paragraph" - (conj acc - (reduce - (fn [acc e] (render-inline (:text content) outgoing pinned content-type acc e)) - [react/text-class (style/text-style (and outgoing (not pinned)) content-type in-popover?)] - children)) - - "blockquote" - (conj acc - [react/view (style/blockquote-style (and outgoing (not pinned))) - [react/text-class (style/blockquote-text-style (and outgoing (not pinned))) - (.substring literal 0 (.-length literal))]]) - - "codeblock" - (conj acc - [react/view {:style style/codeblock-style} - [quo/text - {:max-font-size-multiplier react/max-font-size-multiplier - :style style/codeblock-text-style - :monospace true} - (.substring literal 0 (dec (.-length literal)))]]) - - acc)) - -(defn render-parsed-text - [message tree] - (reduce (fn [acc e] (render-block message acc e)) [:<>] tree)) - -(defn render-parsed-text-with-message-status - [{:keys [outgoing edited-at in-popover?] :as message} tree] - (let [elements (render-parsed-text message tree) - message-status [react/text {:style (style/message-status-placeholder)} - (str (if (and outgoing (not in-popover?)) " " " ") - (when (and (not in-popover?) edited-at) edited-at-text))] - last-element (peek elements)] - ;; Using `nth` here as slightly faster than `first`, roughly 30% - ;; It's worth considering pure js structures for this code path as - ;; it's perfomance critical - (if (= react/text-class (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 - [{:keys [outgoing content-type content] :as message}] - [react/view (style/message-view message) - [react/text - {:style {:color (if outgoing colors/white-persist colors/black)}} - (if (seq (:text content)) - (:text content) - (str "Unhandled content-type " content-type))]]) - -(defn message-not-sent-text - [chat-id message-id] - [react/touchable-highlight - {:on-press - (fn [] - (re-frame/dispatch - [:bottom-sheet/show-sheet - {:content (sheets/options chat-id message-id) - :content-height 200}]) - (react/dismiss-keyboard!))} - [react/view style/not-sent-view - [react/text {:style style/not-sent-text} - (i18n/label :t/status-not-sent-tap)] - [react/view style/not-sent-icon - [icons/icon :main-icons/warning {:color 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))))) - -(def pin-icon-width 9) - -(def pin-icon-height 15) - -(defn pinned-by-indicator - [outgoing display-photo? pinned-by] - [react/view - {:style (style/pin-indicator outgoing display-photo?) - :accessibility-label :pinned-by} - [react/view {:style (style/pinned-by-text-icon-container)} - [react/view {:style (style/pin-icon-container)} - [icons/icon :main-icons/pin - {:color colors/gray - :height pin-icon-height - :width pin-icon-width - :background-color :red}]] - [quo/text - {:weight :regular - :size :small - :color :main - :style (style/pinned-by-text)} - (i18n/label :t/pinned-by)]] - [quo/text - {:weight :medium - :size :small - :color :main - :style (style/pin-author-text)} - (pin-author-name pinned-by)]]) - -(defn message-delivery-status - [{:keys [chat-id message-id outgoing-status message-type]}] - (when (and (not= constants/message-type-private-group-system-message message-type) - (= outgoing-status :not-sent)) - [message-not-sent-text chat-id message-id])) - -(defview message-author-name - [from opts] - (letsubs [contact-with-names [:contacts/contact-by-identity from]] - (chat.utils/format-author-old contact-with-names opts))) - -(defview message-my-name - [opts] - (letsubs [contact-with-names [:multiaccount/contact]] - (chat.utils/format-author-old contact-with-names opts))) - -(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) - [react/view - {:style (assoc (style/message-wrapper message) - :margin-vertical 10 - :margin-left 8 - :width 271)} - (when verified - [react/view (style/community-verified) - [react/text - {:style {:font-size 13 - :color colors/blue}} (i18n/label :t/communities-verified)]]) - [react/view (style/community-message verified) - [react/view - {:width 62 - :padding-left 14} - (if (= community-id constants/status-community-id) - [react/image - {:source (resources/get-image :status-logo) - :style {:width 40 - :height 40}}] - [communities.icon/community-icon community])] - [react/view {:padding-right 14 :flex 1} - [react/text {:style {:font-weight "700" :font-size 17}} - name] - [react/text description]]] - [react/view (style/community-view-button) - [react/touchable-highlight - {:on-press #(re-frame/dispatch [:navigate-to - :community - {:community-id (:id community)}])} - [react/text - {:style {:text-align :center - :color colors/blue}} (i18n/label :t/view)]]]]))) - -(defn message-content-wrapper - "Author, userpic and delivery wrapper" - [{:keys [first-in-group? display-photo? display-username? - identicon - from outgoing in-popover?] - :as message} content {:keys [modal close-modal]}] - [react/view - {:style (style/message-wrapper message) - :pointer-events :box-none - :accessibility-label :chat-item} - [react/view - {:style (style/message-body message) - :pointer-events :box-none} - (when display-photo? - [react/view (style/message-author-userpic outgoing) - (when first-in-group? - [react/touchable-highlight - {:on-press #(do (when modal (close-modal)) - (re-frame/dispatch [:chat.ui/show-profile from]))} - [photos/member-photo from identicon]])]) - [react/view {:style (style/message-author-wrapper outgoing display-photo? in-popover?)} - (when display-username? - [react/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}]]) - ;;MESSAGE CONTENT - content - [link-preview/link-preview-wrapper (:links (:content message)) outgoing false]]] - ; delivery status - [react/view (style/delivery-status outgoing) - [message-delivery-status message]]]) - -(def image-max-width 260) -(def image-max-height 192) - -(defn image-set-size - [dimensions] - (fn [^js evt] - (let [width (.-width (.-nativeEvent evt)) - height (.-height (.-nativeEvent evt))] - (if (< width height) - ;; if width less than the height we reduce width proportionally to height - (let [k (/ height image-max-height)] - (when (not= (/ width k) (first @dimensions)) - (reset! dimensions {:width (/ width k) :height image-max-height :loaded true}))) - (swap! dimensions assoc :loaded true))))) - -(defn message-content-image - [{:keys [content outgoing in-popover?] :as message} - {:keys [on-long-press]}] - (let [dimensions (reagent/atom {:width image-max-width :height image-max-height :loaded false}) - visible (reagent/atom false) - uri (:image content)] - (fn [] - (let [style-opts {:outgoing outgoing - :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))}] - [react/touchable-highlight - {:on-press (fn [] - (reset! visible true) - (react/dismiss-keyboard!)) - :on-long-press on-long-press - :disabled in-popover?} - [react/view - {:style (style/image-message style-opts) - :accessibility-label :image-message} - (when (or (:error @dimensions) (not (:loaded @dimensions))) - [react/view - (merge (dissoc style-opts :opacity) - {:flex 1 :align-items :center :justify-content :center :position :absolute}) - (if (:error @dimensions) - [icons/icon :main-icons/cancel] - [react/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}}] - [react/view {:style (style/image-message-border style-opts)}]]]])))) - -(defmulti ->message :content-type) - -(defmethod ->message constants/content-type-command - [message] - [message.command/command-content message-content-wrapper message]) - -(defmethod ->message constants/content-type-gap - [message] - [message.gap/gap message]) - -(defmethod ->message constants/content-type-system-text - [{:keys [content] :as message}] - [react/view {:accessibility-label :chat-item} - [react/view (style/system-message-body message) - [react/view (style/message-view message) - [react/view (style/message-view-content) - [render-parsed-text message (:parsed-text content)]]]]]) - -(def message-height-px 200) -(def max-message-height-px 150) - -(defn pin-message - [{:keys [chat-id pinned] :as message}] - (let [pinned-messages @(re-frame/subscribe [:chats/pinned chat-id])] - (if (and (not pinned) (> (count pinned-messages) 2)) - (do - (js/setTimeout (fn [] (re-frame/dispatch [:dismiss-keyboard])) 500) - (re-frame/dispatch [:pin-message/show-pin-limit-modal chat-id])) - (re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned (not pinned))])))) - -(defn on-long-press-fn - [on-long-press {:keys [pinned message-pin-enabled outgoing edit-enabled show-input?] :as message} - content] - (on-long-press - (concat - (when (and outgoing edit-enabled) - [{:on-press #(re-frame/dispatch [:chat.ui/edit-message message]) - :label (i18n/label :t/edit) - :id :edit}]) - (when show-input? - [{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message]) - :label (i18n/label :t/message-reply) - :id :reply}]) - [{:on-press #(react/copy-to-clipboard - (components.reply/get-quoted-text-with-mentions - (get content :parsed-text))) - :label (i18n/label :t/sharing-copy-to-clipboard) - :id :copy}] - (when message-pin-enabled - [{:on-press #(pin-message message) - :label (if pinned (i18n/label :t/unpin) (i18n/label :t/pin)) - :id (if pinned :unpin :pin)}]) - (when (and outgoing config/delete-message-enabled?) - [{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message message]) - :label (i18n/label :t/delete) - :id :delete}])))) - -(defn collapsible-text-message - [{:keys [mentioned]} _] - (let [collapsed? (reagent/atom false) - collapsible? (reagent/atom false) - show-timestamp? (reagent/atom false)] - (fn [{:keys [content outgoing current-public-key public? pinned in-popover? chat-id] :as message} - on-long-press modal] - (let [max-height (when-not (or outgoing modal) - (if @collapsible? - (if @collapsed? message-height-px nil) - message-height-px))] - [react/touchable-highlight - (when-not modal - {:on-press (fn [_] - (react/dismiss-keyboard!) - (reset! show-timestamp? true)) - :delay-long-press 100 - :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))) - :disabled in-popover?}) - [react/view (style/message-view-wrapper outgoing) - [message-timestamp message show-timestamp?] - [react/view {:style (style/message-view message)} - [react/view - {:style (style/message-view-content) - :max-height max-height} - (let [response-to (:response-to content)] - [react/view - {:on-layout - #(when (and (> (.-nativeEvent.layout.height ^js %) max-message-height-px) - (not @collapsible?) - (not outgoing) - (not modal)) - (reset! collapsed? true) - (reset! collapsible? true))} - (when (and (seq response-to) (:quoted-message message)) - [quoted-message response-to (:quoted-message message) outgoing current-public-key - public? pinned chat-id]) - [render-parsed-text-with-message-status message (:parsed-text content)]]) - (when-not @collapsible? [message-status message]) - (when (and @collapsible? (not modal)) - (if @collapsed? - (let [color (if pinned - colors/pin-background - (if mentioned colors/mentioned-background colors/blue-light))] - [react/touchable-highlight - {:on-press #(swap! collapsed? not) - :style {:position :absolute :bottom 0 :left 0 :right 0 :height 72}} - [react/linear-gradient - {:colors [(str color "00") color] - :start {:x 0 :y 0} - :end {:x 0 :y 0.9}} - [react/view - {:height 72 - :align-self :center - :justify-content :flex-end - :padding-bottom 10} - [react/view (style/collapse-button) - [icons/icon :main-icons/dropdown - {:color colors/white}]]]]]) - [react/touchable-highlight - {:on-press #(swap! collapsed? not) - :style {:align-self :center :margin 5}} - [react/view (style/collapse-button) - [icons/icon :main-icons/dropdown-up - {:color colors/white}]]]))]]]])))) - -(defmethod ->message constants/content-type-text - [message {:keys [on-long-press modal] :as reaction-picker}] - [message-content-wrapper message - [collapsible-text-message message on-long-press modal] - reaction-picker]) - -(defmethod ->message constants/content-type-community - [message] - [community-content message]) - -(defmethod ->message constants/content-type-status - [{:keys [content content-type pinned] :as message}] - [message-content-wrapper message - [react/view style/status-container - [react/text {:style (style/status-text)} - (reduce - (fn [acc e] (render-inline (:text content) false pinned content-type acc e)) - [react/text-class {:style (style/status-text)}] - (-> content :parsed-text peek :children))]]]) - -(defmethod ->message constants/content-type-emoji - [] - (let [show-timestamp? (reagent/atom false)] - (fn [{:keys [content current-public-key outgoing edit-enabled public? pinned in-popover? - message-pin-enabled content-type edited-at] - :as message} - {:keys [on-long-press modal] - :as reaction-picker}] - ;; Makes sure to render a text-message and not an emoji-message if it has been edited with text - (if (= content-type constants/content-type-text) - [message-content-wrapper message - [collapsible-text-message message on-long-press modal] reaction-picker] - (let [response-to (:response-to content)] - [message-content-wrapper message - [react/touchable-highlight - (when-not modal - {:disabled in-popover? - :on-press (fn [] - (react/dismiss-keyboard!) - (reset! show-timestamp? true)) - :delay-long-press 100 - :on-long-press (fn [] - (on-long-press - (concat - (when (and outgoing edit-enabled) - [{:on-press #(re-frame/dispatch [:chat.ui/edit-message message]) - :label (i18n/label :t/edit) - :id :edit}]) - [{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message]) - :id :reply - :label (i18n/label :t/message-reply)} - {:on-press #(react/copy-to-clipboard (get content :text)) - :id :copy - :label (i18n/label :t/sharing-copy-to-clipboard)}] - (when message-pin-enabled - [{:on-press #(pin-message message) - :label (if pinned - (i18n/label :t/unpin) - (i18n/label :t/pin))}]) - (when (and outgoing config/delete-message-enabled?) - [{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message - message]) - :label (i18n/label :t/delete) - :id :delete}]))))}) - [react/view (style/message-view-wrapper outgoing) - [message-timestamp message show-timestamp?] - [react/view (style/message-view message) - [react/view {:style (style/message-view-content)} - [react/view {:style (style/style-message-text outgoing)} - (when (and (seq response-to) (:quoted-message message)) - [quoted-message response-to (:quoted-message message) outgoing current-public-key - public? pinned]) - [react/text {:style (style/emoji-message message)} - (if edited-at (str (content :text) " ") (str (content :text)))]] - [message-status message]]]]] - reaction-picker]))))) - -(defmethod ->message constants/content-type-sticker - [{:keys [content from outgoing in-popover?] - :as message} - {:keys [on-long-press modal] - :as reaction-picker}] - (let [pack (get-in content [:sticker :pack])] - [message-content-wrapper message - [react/touchable-highlight - (when-not modal - {:disabled in-popover? - :accessibility-label :sticker-message - :on-press (fn [_] - (when pack - (re-frame/dispatch [:stickers/open-sticker-pack (str pack)])) - (react/dismiss-keyboard!)) - :delay-long-press 100 - :on-long-press (fn [] - (on-long-press - (concat - (when-not outgoing - [{:on-press #(when pack - (re-frame/dispatch [:chat.ui/show-profile from])) - :label (i18n/label :t/view-details)}]) - [{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message]) - :id :reply - :label (i18n/label :t/message-reply)}] - (if (and outgoing config/delete-message-enabled?) - [{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message - message]) - :label (i18n/label :t/delete) - :id :delete}] - []))))}) - [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 - [{:keys [content in-popover? outgoing] :as message} - {:keys [on-long-press modal] - :as reaction-picker}] - [message-content-wrapper message - [message-content-image message - {:modal modal - :disabled in-popover? - :delay-long-press 100 - :on-long-press (fn [] - (on-long-press - (concat - [{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message]) - :id :reply - :label (i18n/label :t/message-reply)} - {:on-press #(re-frame/dispatch [:chat.ui/save-image-to-gallery - (:image content)]) - :id :save - :label (i18n/label :t/save)} - {:on-press #(images/download-image-http - (get-in message [:content :image]) - preview/share) - :id :share - :label (i18n/label :t/share)}] - (when (and outgoing config/delete-message-enabled?) - [{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message message]) - :label (i18n/label :t/delete) - :id :delete}]))))}] - reaction-picker]) - -(defmethod ->message constants/content-type-audio - [] - (let [show-timestamp? (reagent/atom false)] - (fn [{:keys [outgoing] :as message} - {:keys [on-long-press modal] - :as reaction-picker}] - [message-content-wrapper message - [react/touchable-highlight - (when-not modal - {:on-long-press - (fn [] - (on-long-press - (concat - [{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message]) - :id :reply - :label (i18n/label :t/message-reply)}] - (when (and outgoing config/delete-message-enabled?) - [{:on-press #(re-frame/dispatch [:chat.ui/soft-delete-message message]) - :label (i18n/label :t/delete) - :id :delete}]) - []))) - :on-press (fn [] - (reset! show-timestamp? true))}) - [react/view (style/message-view-wrapper (:outgoing message)) - [message-timestamp message show-timestamp?] - [react/view {:style (style/message-view message) :accessibility-label :audio-message} - [react/view {:style (style/message-view-content)} - [message.audio/message-content message] [message-status message]]]]] - reaction-picker]))) - -(defn contact-request-status-pending - [] - [react/view {:style {:flex-direction :row}} - [quo/text - {:style {:margin-right 5.27} - :weight :medium - :color :secondary} - (i18n/label :t/contact-request-pending)] - [react/activity-indicator - {:animating true - :size :small - :color colors/gray}]]) - -(defn contact-request-status-accepted - [] - [quo/text - {:style {:color colors/green} - :weight :medium} - (i18n/label :t/contact-request-accepted)]) - -(defn contact-request-status-declined - [] - [quo/text - {:style {:color colors/red} - :weight :medium} - (i18n/label :t/contact-request-declined)]) - -(defn contact-request-status-label - [state] - [react/view {:style (style/contact-request-status-label state)} - (case state - constants/contact-request-message-state-pending [contact-request-status-pending] - constants/contact-request-message-state-accepted [contact-request-status-accepted] - constants/contact-request-message-state-declined [contact-request-status-declined])]) - -(defmethod ->message constants/content-type-contact-request - [{:keys [outgoing] :as message} _] - [react/view {:style (style/content-type-contact-request outgoing)} - [react/image - {:source (resources/get-image :hand-wave) - :style {:width 112 - :height 97}}] - [quo/text - {:style {:margin-top 6} - :weight :bold - :size :large} - (i18n/label :t/contact-request)] - [react/view {:style {:padding-horizontal 16}} - [quo/text - {:style {:margin-top 2 - :margin-bottom 14}} - (get-in message [:content :text])]] - [contact-request-status-label (:contact-request-state message)]]) - -(defmethod ->message :default - [message] - [message-content-wrapper message - [unknown-content-type message]]) - -(defn chat-message - [{:keys [outgoing display-photo? pinned pinned-by] :as message} space-keeper] - [:<> - [reactions/with-reaction-picker - {:message message - :reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message) - (:chat-id message)]) - :picker-on-open (fn [] - (space-keeper true)) - :picker-on-close (fn [] - (space-keeper false)) - :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}])) - :render ->message}] - (when pinned - [react/view {:style (style/pin-indicator-container outgoing)} - [pinned-by-indicator outgoing display-photo? pinned-by]])]) diff --git a/src/status_im/ui/screens/chat/message/pinned_message.cljs b/src/status_im/ui/screens/chat/message/pinned_message.cljs deleted file mode 100644 index a5a6038fd5..0000000000 --- a/src/status_im/ui/screens/chat/message/pinned_message.cljs +++ /dev/null @@ -1,101 +0,0 @@ -(ns status-im.ui.screens.chat.message.pinned-message - (:require [quo.core :as quo] - [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [i18n.i18n :as i18n] - [status-im.ui.components.list.views :as list] - [status-im.ui.components.react :as react] - [status-im.ui.screens.chat.message.message :as message] - [utils.re-frame :as rf])) - -(def selected-unpin (reagent/atom nil)) - -(defn render-pin-fn - [{:keys [message-id outgoing] :as message} - _ - _ - {:keys [group-chat public? current-public-key space-keeper]}] - [react/touchable-without-feedback - {:style {:width "100%"} - :on-press #(reset! selected-unpin message-id)} - [react/view - {:style {:flex-direction :row - :align-items :center - :justify-content :space-between - :flex 1 - :padding-right 20}} - [message/chat-message - (assoc message - :group-chat group-chat - :public? public? - :current-public-key current-public-key - :show-input? false - :pinned false - :display-username? (not outgoing) - :display-photo? false - :last-in-group? false - :in-popover? true) - space-keeper] - [react/view - {:style {:position :absolute - :right 18 - :padding-top 4}} - [quo/radio {:value (= @selected-unpin message-id)}]]]]) - -(def list-key-fn #(or (:message-id %) (:value %))) - -(defn pinned-messages-limit-list - [chat-id] - (let [pinned-messages @(re-frame/subscribe [:chats/pinned-sorted-list chat-id])] - [list/flat-list - {:key-fn list-key-fn - :data (reverse pinned-messages) - :render-data {:chat-id chat-id} - :render-fn render-pin-fn - :on-scroll-to-index-failed identity - :style {:flex-grow 0 - :border-top-width 1 - :border-bottom-width 1 - :border-top-color colors/gray-lighter - :border-bottom-color colors/gray-lighter} - :content-container-style {:padding-bottom 10 - :padding-top 10}}])) - -(defn pin-limit-popover - [] - (let [{:keys [message]} (rf/sub [:popover/popover])] - [react/view {:style {:flex-shrink 1}} - [react/view - {:style {:height 60 - :justify-content :center}} - [react/text - {:style {:padding-horizontal 40 - :text-align :center}} - (i18n/label :t/pin-limit-reached)]] - [pinned-messages-limit-list (message :chat-id)] - [react/view - {:flex-direction :row - :padding-horizontal 16 - :height 60 - :justify-content :space-between - :align-items :center} - [quo/button - {:on-press #(do - (reset! selected-unpin nil) - (re-frame/dispatch [:hide-popover])) - :type :secondary} - (i18n/label :t/cancel)] - [quo/button - {:on-press #(do - (re-frame/dispatch [:pin-message/send-pin-message - {:chat-id (message :chat-id) - :message-id @selected-unpin - :pinned false}]) - (re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned true)]) - (re-frame/dispatch [:hide-popover]) - (reset! selected-unpin nil)) - :type :secondary - :disabled (nil? @selected-unpin) - :theme (if (nil? @selected-unpin) :disabled :negative)} - (i18n/label :t/unpin)]]])) diff --git a/src/status_im/ui/screens/chat/message/reactions.cljs b/src/status_im/ui/screens/chat/message/reactions.cljs deleted file mode 100644 index b404eb5d68..0000000000 --- a/src/status_im/ui/screens/chat/message/reactions.cljs +++ /dev/null @@ -1,106 +0,0 @@ -(ns status-im.ui.screens.chat.message.reactions - (:require [quo.animated :as animated] - [quo.react :as react] - [quo.react-native :as rn] - [reagent.core :as reagent] - [status-im.ui.screens.chat.message.reactions-picker :as reaction-picker] - [status-im.ui.screens.chat.message.reactions-row :as reaction-row])) - -(defn measure-in-window - [ref cb] - (.measureInWindow ^js ref cb)) - -(defn get-picker-position - [^js ref cb] - (some-> ref - react/current-ref - (measure-in-window - (fn [x y width height] - (cb {:top y - :left x - :width width - :height height}))))) - -(defn extract-id - [reactions id] - (->> reactions - (filter (fn [{:keys [emoji-id]}] (= emoji-id id))) - first - :emoji-reaction-id)) - -(defn with-reaction-picker - [] - (let [ref (react/create-ref) - animated-state (animated/value 0) - spring-animation (animated/with-spring-transition - animated-state - (:jump animated/springs)) - animation (animated/with-timing-transition - animated-state - {:duration reaction-picker/animation-duration - :easing (:ease-in-out animated/easings)}) - visible (reagent/atom false) - actions (reagent/atom nil) - position (reagent/atom {})] - (fn [{:keys [message reactions outgoing outgoing-status render send-emoji retract-emoji - picker-on-open - picker-on-close timeline]}] - (let [own-reactions (reduce (fn [acc {:keys [emoji-id own]}] - (if own (conj acc emoji-id) acc)) - [] - reactions) - on-emoji-press (fn [emoji-id] - (let [active ((set own-reactions) emoji-id)] - (if active - (retract-emoji {:emoji-id emoji-id - :emoji-reaction-id (extract-id reactions emoji-id)}) - (send-emoji {:emoji-id emoji-id})))) - on-close (fn [] - (animated/set-value animated-state 0) - (js/setTimeout - (fn [] - (reset! actions nil) - (reset! visible false) - (picker-on-close)))) - on-open (fn [pos] - (picker-on-open) - (reset! position pos) - (reset! visible true))] - [:<> - [rn/view - {:ref ref - :collapsable false} - [render message - {:modal false - :on-long-press (fn [act] - (when (or (not outgoing) - (and outgoing (= outgoing-status :sent))) - (reset! actions act) - (get-picker-position ref on-open)))}] - [reaction-row/message-reactions message reactions timeline #(on-emoji-press %) on-open]] - (when @visible - [rn/modal - {:on-request-close on-close - :on-show (fn [] - (js/requestAnimationFrame - #(animated/set-value animated-state 1))) - :transparent true} - [reaction-picker/modal - {:outgoing (:outgoing message) - :display-photo (:display-photo? message) - :animation animation - :spring spring-animation - :top (:top @position) - :message-height (:height @position) - :on-close on-close - :actions @actions - :own-reactions own-reactions - :timeline timeline - :send-emoji (fn [emoji] - (on-close) - (js/setTimeout #(on-emoji-press emoji) - reaction-picker/animation-duration))} - [render message - {:modal true - :on-long-press #() - :close-modal on-close}]]])])))) diff --git a/src/status_im/ui/screens/chat/message/reactions_old.cljs b/src/status_im/ui/screens/chat/message/reactions_old.cljs deleted file mode 100644 index 0d37f1b5f1..0000000000 --- a/src/status_im/ui/screens/chat/message/reactions_old.cljs +++ /dev/null @@ -1,106 +0,0 @@ -(ns status-im.ui.screens.chat.message.reactions-old - (:require [quo.animated :as animated] - [quo.react :as react] - [quo.react-native :as rn] - [reagent.core :as reagent] - [status-im.ui.screens.chat.message.reactions-picker :as reaction-picker] - [status-im.ui.screens.chat.message.reactions-row-old :as reaction-row])) - -(defn measure-in-window - [ref cb] - (.measureInWindow ^js ref cb)) - -(defn get-picker-position - [^js ref cb] - (some-> ref - react/current-ref - (measure-in-window - (fn [x y width height] - (cb {:top y - :left x - :width width - :height height}))))) - -(defn- extract-id - [reactions id] - (->> reactions - (filter (fn [{:keys [emoji-id]}] (= emoji-id id))) - first - :emoji-reaction-id)) - -(defn with-reaction-picker - [] - (let [ref (react/create-ref) - animated-state (animated/value 0) - spring-animation (animated/with-spring-transition - animated-state - (:jump animated/springs)) - animation (animated/with-timing-transition - animated-state - {:duration reaction-picker/animation-duration - :easing (:ease-in-out animated/easings)}) - visible (reagent/atom false) - actions (reagent/atom nil) - position (reagent/atom {})] - (fn [{:keys [message reactions outgoing outgoing-status render send-emoji retract-emoji - picker-on-open - picker-on-close timeline]}] - (let [own-reactions (reduce (fn [acc {:keys [emoji-id own]}] - (if own (conj acc emoji-id) acc)) - [] - reactions) - on-emoji-press (fn [emoji-id] - (let [active ((set own-reactions) emoji-id)] - (if active - (retract-emoji {:emoji-id emoji-id - :emoji-reaction-id (extract-id reactions emoji-id)}) - (send-emoji {:emoji-id emoji-id})))) - on-close (fn [] - (animated/set-value animated-state 0) - (js/setTimeout - (fn [] - (reset! actions nil) - (reset! visible false) - (picker-on-close)))) - on-open (fn [pos] - (picker-on-open) - (reset! position pos) - (reset! visible true))] - [:<> - [rn/view - {:ref ref - :collapsable false} - [render message - {:modal false - :on-long-press (fn [act] - (when (or (not outgoing) - (and outgoing (= outgoing-status :sent))) - (reset! actions act) - (get-picker-position ref on-open)))}] - [reaction-row/message-reactions message reactions timeline]] - (when @visible - [rn/modal - {:on-request-close on-close - :on-show (fn [] - (js/requestAnimationFrame - #(animated/set-value animated-state 1))) - :transparent true} - [reaction-picker/modal - {:outgoing (:outgoing message) - :display-photo (:display-photo? message) - :animation animation - :spring spring-animation - :top (:top @position) - :message-height (:height @position) - :on-close on-close - :actions @actions - :own-reactions own-reactions - :timeline timeline - :send-emoji (fn [emoji] - (on-close) - (js/setTimeout #(on-emoji-press emoji) - reaction-picker/animation-duration))} - [render message - {:modal true - :on-long-press #() - :close-modal on-close}]]])])))) diff --git a/src/status_im/ui/screens/chat/message/reactions_picker.cljs b/src/status_im/ui/screens/chat/message/reactions_picker.cljs deleted file mode 100644 index c6b5ed7756..0000000000 --- a/src/status_im/ui/screens/chat/message/reactions_picker.cljs +++ /dev/null @@ -1,137 +0,0 @@ -(ns status-im.ui.screens.chat.message.reactions-picker - (:require [cljs-bean.core :as bean] - [quo.animated :as animated] - [quo.components.safe-area :as safe-area] - [quo.core :as quo] - [quo.react :as react] - [quo.react-native :as rn] - [reagent.core :as reagent] - [status-im.constants :as constants] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.screens.chat.message.styles :as styles])) - -(def tabbar-height 36) -(def text-input-height 54) - -(def animation-duration 150) - -(def scale 0.8) -(def translate-x 27) -(def translate-y -24) - -(def id-icon - {"edit" :main-icons/edit - "pin" :main-icons/pin - "unpin" :main-icons/pin - "copy" :main-icons/copy - "reply" :main-icons/reply - "save" :main-icons/download - "share" :main-icons/share-default - "delete" :main-icons/delete}) - -(defn picker - [{:keys [outgoing actions own-reactions on-close send-emoji timeline]}] - [rn/view {:style (styles/container-style {:outgoing outgoing :timeline timeline})} - [rn/view {:style (styles/reactions-picker-row)} - (doall - (for [[id resource] constants/reactions-old - :let [active (own-reactions id)]] - ^{:key id} - [rn/touchable-opacity - {:accessibility-label (str "pick-emoji-" id) - :on-press #(send-emoji id)} - [rn/view {:style (styles/reaction-button active)} - [rn/image - {:source resource - :style {:height 32 - :width 32}}]]]))] - (when (seq actions) - [rn/view {:style (styles/quick-actions-container)} - (doall - (for [action actions - :let [{:keys [id label on-press]} (bean/bean action)]] - ^{:key id} - [rn/touchable-opacity - {:on-press (fn [] - (on-close) - (js/setTimeout on-press animation-duration))} - [rn/view {:style (styles/quick-actions-row)} - [quo/text - {:color (if (= id "delete") :negative :link) - :weight :medium} label] - (when-let [icon (get id-icon id)] - [icons/icon icon - {:color (if (= id "delete") :red :blue)}])]]))])]) - -(def modal - (reagent/adapt-react-class - (fn [props] - (let [{outgoing :outgoing - animation :animation - spring :spring - top :top - message-height :messageHeight - display-photo :displayPhoto - on-close :onClose - actions :actions - send-emoji :sendEmoji - own-reactions :ownReactions - children :children - timeline :timeline} - (bean/bean props) - {bottom-inset :bottom} (safe-area/use-safe-area) - {window-height :height} (rn/use-window-dimensions) - - {picker-height :height - on-picker-layout :on-layout} - (rn/use-layout) - - full-height (+ message-height picker-height top) - max-height (- window-height bottom-inset tabbar-height text-input-height) - top-delta (max 0 (- full-height max-height)) - translation-x (if (and outgoing (not timeline)) - translate-x - (* -1 translate-x))] - (reagent/as-element - [:<> - [rn/view - {:style {:position :absolute - :flex 1 - :top 0 - :bottom 0 - :left 0 - :right 0}} - [rn/touchable-without-feedback - {:on-press on-close} - [animated/view - {:style {:flex 1 - :opacity animation - :background-color "rgba(0,0,0,0.5)"}}]]] - [animated/view - {:pointer-events :box-none - :style {:top (- top top-delta) - :left 0 - :right 0 - :position :absolute - :opacity animation - :transform [{:translateY (animated/mix animation top-delta 0)}]}} - (into [:<>] (react/get-children children)) - [animated/view - {:on-layout on-picker-layout - :pointer-events :box-none - :style (merge (styles/picker-wrapper-style - {:display-photo? display-photo - :timeline timeline - :outgoing (and outgoing (not timeline))}) - {:opacity animation - :transform [{:translateX (animated/mix spring translation-x 0)} - {:translateY (animated/mix spring translate-y 0)} - {:scale (animated/mix spring scale 1)}]})} - [picker - {:outgoing (and outgoing (not timeline)) - :timeline timeline - :actions actions - :on-close on-close - :own-reactions (into #{} (js->clj own-reactions)) - :send-emoji send-emoji - :animation animation}]]]]))))) diff --git a/src/status_im/ui/screens/chat/message/reactions_row.cljs b/src/status_im/ui/screens/chat/message/reactions_row.cljs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/status_im/ui/screens/chat/message/reactions_row_old.cljs b/src/status_im/ui/screens/chat/message/reactions_row_old.cljs deleted file mode 100644 index 2c94265ab3..0000000000 --- a/src/status_im/ui/screens/chat/message/reactions_row_old.cljs +++ /dev/null @@ -1,28 +0,0 @@ -(ns status-im.ui.screens.chat.message.reactions-row-old - (:require [quo.core :as quo] - [quo.react-native :as rn] - [status-im.constants :as constants] - [status-im.ui.screens.chat.message.styles :as styles])) - -(defn reaction - [{:keys [outgoing]} {:keys [own emoji-id quantity]} timeline] - [rn/view - {:style (styles/reaction-style {:outgoing (and outgoing (not timeline)) - :own own})} - [rn/image - {:source (get constants/reactions-old emoji-id) - :style {:width 16 - :height 16 - :margin-right 4}}] - [quo/text - {:accessibility-label (str "emoji-" emoji-id "-is-own-" own) - :style (styles/reaction-quantity-style {:own own})} - quantity]]) - -(defn message-reactions - [message reactions timeline] - (when (seq reactions) - [rn/view {:style (styles/reactions-row-old message timeline)} - (for [emoji-reaction reactions] - ^{:key (str emoji-reaction)} - [reaction message emoji-reaction timeline])])) diff --git a/src/status_im/ui/screens/chat/message/styles.cljs b/src/status_im/ui/screens/chat/message/styles.cljs index 127cb7f0bb..9bf5eaaa8f 100644 --- a/src/status_im/ui/screens/chat/message/styles.cljs +++ b/src/status_im/ui/screens/chat/message/styles.cljs @@ -3,20 +3,6 @@ [status-im.ui.components.react :as react] [status-im.ui.screens.chat.styles.photos :as photos])) -(defn picker-wrapper-style - [{:keys [display-photo? outgoing timeline]}] - (merge {:flex-direction :row - :flex 1 - :padding-top 4 - :padding-right 8} - (if outgoing - {:justify-content :flex-end} - {:justify-content :flex-start}) - (when-not timeline - (if display-photo? - {:padding-left (+ 16 photos/default-size)} - {:padding-left 8})))) - (defn container-style [{:keys [outgoing timeline]}] (merge {:border-top-left-radius 16 @@ -31,72 +17,11 @@ {:border-top-right-radius 4} {:border-top-left-radius 4})))) -(defn reactions-picker-row - [] - {:flex-direction :row - :padding-vertical 8 - :padding-horizontal 8}) - -(defn quick-actions-container - [] - {:flex-direction :column - :justify-content :space-evenly - :border-top-width 1 - :border-top-color (:ui-01 @colors/theme)}) - -(defn quick-actions-row - [] - {:flex-direction :row - :padding-horizontal 16 - :padding-vertical 12 - :justify-content :space-between - :border-top-width 1 - :border-top-color (:ui-01 @colors/theme)}) - -(defn reaction-style - [{:keys [outgoing own]}] - (merge {:border-top-left-radius 10 - :border-top-right-radius 10 - :border-bottom-right-radius 10 - :border-bottom-left-radius 10 - :flex-direction :row - :margin-vertical 2 - :padding-right 8 - :padding-left 2 - :padding-vertical 2} - (if own - {:background-color (:interactive-01 @colors/theme)} - {:background-color (:interactive-02 @colors/theme)}) - (if outgoing - {:border-top-right-radius 2 - :margin-left 4} - {:border-top-left-radius 2 - :margin-right 4}))) - -(defn reaction-quantity-style - [{:keys [own]}] - {:font-size 12 - :line-height 16 - :color (if own - colors/white - (:text-01 @colors/theme))}) - (def screen-width (-> "window" react/get-dimensions :width)) -(defn reactions-row-old - [{:keys [outgoing display-photo?]} timeline] - (merge {:flex-direction :row - :padding-right 8} - (if (and outgoing (not timeline)) - {:justify-content :flex-end} - {:justify-content :flex-start}) - (if (or display-photo? timeline) - {:padding-left (+ 30 photos/default-size (when timeline 8))} - {:padding-left 30}))) - (defn reactions-row [timeline margin-top] {:flex-direction :row @@ -108,49 +33,9 @@ :max-width (- screen-width (+ 30 photos/default-size (when timeline 8))) :margin-left (+ 30 photos/default-size (when timeline 8))}) -(defn reaction-button - [active] - (merge {:width 40 - :height 40 - :border-radius 20 - :justify-content :center - :align-items :center - :margin-horizontal 1 - :border-width 1 - :border-color :transparent} - (when active - {:background-color (:interactive-02 @colors/theme) - ;; FIXME: Use broder color here - :border-color "rgba(67, 96, 223, 0.2)"}))) - -(defn link-preview-request-wrapper - [] - {:border-radius 16 - :border-width 1 - :border-color colors/gray-lighter - :margin-vertical 4 - :background-color (:ui-background @colors/theme)}) - -(def link-preview-request-image - {:width 132 - :height 94 - :align-self :center}) - (def community-preview-header {:margin 8 :margin-left 12}) -(defn link-preview-wrapper - [outgoing timeline] - {:overflow :hidden - :border-top-left-radius 16 - :border-top-right-radius 16 - :border-bottom-left-radius (if timeline 16 (if outgoing 16 4)) - :border-bottom-right-radius (if timeline 16 (if outgoing 4 16)) - :border-width 1 - :border-color colors/gray-lighter - :background-color colors/white - :margin-vertical 4}) - (defn scale-dimensions "Scale a given height and width to be maximum percentage allowed of the screen width" [{:keys [height width] :as dimensions}] @@ -177,8 +62,3 @@ (def link-preview-title {:margin-horizontal 12 :margin-top 10}) - -(def link-preview-site - {:margin-horizontal 12 - :margin-top 2 - :margin-bottom 10}) diff --git a/src/status_im/ui/screens/chat/photos.cljs b/src/status_im/ui/screens/chat/photos.cljs index 215b6840b7..934df1b9c2 100644 --- a/src/status_im/ui/screens/chat/photos.cljs +++ b/src/status_im/ui/screens/chat/photos.cljs @@ -40,13 +40,3 @@ [photo path {:size style/default-size :accessibility-label :own-account-photo}])) - -(defn member-identicon - [identicon] - (let [size style/default-size] - [react/view {:style (style/photo-container size)} - [fast-image/fast-image - {:source {:uri identicon} - :style (style/photo size) - :accessibility-label :member-photo}] - [react/view {:style (style/photo-border size)}]])) diff --git a/src/status_im/ui/screens/chat/pinned_messages.cljs b/src/status_im/ui/screens/chat/pinned_messages.cljs deleted file mode 100644 index 8777a7222e..0000000000 --- a/src/status_im/ui/screens/chat/pinned_messages.cljs +++ /dev/null @@ -1,133 +0,0 @@ -(ns status-im.ui.screens.chat.pinned-messages - (:require [quo.animated :as animated] - [quo.react :as quo.react] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [i18n.i18n :as i18n] - [status-im.ui.components.connectivity.view :as connectivity] - [status-im.ui.components.list.views :as list] - [status-im.ui.components.react :as react] - [status-im.ui.components.topbar :as topbar] - [status-im.ui.screens.chat.components.accessory :as accessory] - [status-im.ui.screens.chat.message.message :as message] - [status-im.ui.screens.chat.styles.main :as style] - [status-im.ui.screens.chat.views :as chat] - [utils.datetime :as datetime] - [status-im.utils.platform :as platform])) - -(defn pins-topbar - [chat] - (let [{:keys [group-chat chat-id chat-name]} chat - pinned-messages @(re-frame/subscribe [:chats/pinned chat-id]) - [first-name _] (when-not group-chat - @(re-frame.core/subscribe - [:contacts/contact-two-names-by-identity chat-id]))] - [topbar/topbar - {:show-border? true - :title (if group-chat chat-name first-name) - :subtitle (if (= (count pinned-messages) 0) - (i18n/label :t/no-pinned-messages) - (i18n/label-pluralize (count pinned-messages) :t/pinned-messages-count))}])) - -(defn get-space-keeper-ios - [bottom-space panel-space active-panel text-input-ref] - (fn [state] - ;; NOTE: Only iOS now because we use soft input resize screen on android - (when platform/ios? - (cond - (and state - (< @bottom-space @panel-space) - (not @active-panel)) - (reset! bottom-space @panel-space) - - (and (not state) - (< @panel-space @bottom-space)) - (do - (some-> ^js (quo.react/current-ref text-input-ref) - .focus) - (reset! panel-space @bottom-space) - (reset! bottom-space 0)))))) - -(defn pinned-messages-empty - [] - [react/view - {:style {:flex 1 - :align-items :center - :justify-content :center}} - [react/text {:style style/intro-header-description} - (i18n/label :t/pinned-messages-empty)]]) - -(defonce messages-list-ref (atom nil)) - -(def list-ref #(reset! messages-list-ref %)) - -(def list-key-fn #(or (:message-id %) (:value %))) - -(defn render-fn - [{:keys [outgoing whisper-timestamp] :as message} - _ - _ - {:keys [group-chat public? current-public-key space-keeper show-input? message-pin-enabled - edit-enabled in-pinned-view?]}] - [react/view {:style (when (and platform/android? (not in-pinned-view?)) {:scaleY -1})} - [message/chat-message - (assoc message - :incoming-group (and group-chat (not outgoing)) - :group-chat group-chat - :public? public? - :current-public-key current-public-key - :show-input? show-input? - :message-pin-enabled message-pin-enabled - :edit-enabled edit-enabled - :display-username? (not outgoing) - :pinned true - :timestamp-str (datetime/timestamp->time whisper-timestamp)) - space-keeper]]) - -(defn pinned-messages-view - [{:keys [chat pan-responder space-keeper]}] - (let [{:keys [group-chat chat-id public? community-id admins]} chat - pinned-messages @(re-frame/subscribe - [:chats/pinned-sorted-list chat-id])] - (if (= (count pinned-messages) 0) - [pinned-messages-empty] - ;;do not use anonymous functions for handlers - [list/flat-list - (merge - pan-responder - {:key-fn list-key-fn - :ref list-ref - :data (reverse pinned-messages) - :render-data (chat/get-render-data {:group-chat group-chat - :chat-id chat-id - :public? public? - :community-id community-id - :admins admins - :space-keeper space-keeper - :show-input? false - :edit-enabled false - :in-pinned-view? true}) - :render-fn render-fn - :content-container-style {:padding-top 16 - :padding-bottom 16}})]))) - -(defn pinned-messages - [] - (let [{:keys [chat-id]} @(re-frame/subscribe [:get-screen-params])] - (fn [] - (let [bottom-space (reagent/atom 0) - panel-space (reagent/atom 52) - active-panel (reagent/atom nil) - position-y (animated/value 0) - pan-state (animated/value 0) - text-input-ref (quo.react/create-ref) - pan-responder (accessory/create-pan-responder position-y pan-state) - space-keeper (get-space-keeper-ios bottom-space panel-space active-panel text-input-ref) - chat @(re-frame/subscribe [:chat-by-id chat-id])] - [:<> - [pins-topbar chat] - [connectivity/loading-indicator] - [pinned-messages-view - {:chat chat - :pan-responder pan-responder - :space-keeper space-keeper}]])))) diff --git a/src/status_im/ui/screens/chat/sheets.cljs b/src/status_im/ui/screens/chat/sheets.cljs index 3cfbde0538..e65a09776a 100644 --- a/src/status_im/ui/screens/chat/sheets.cljs +++ b/src/status_im/ui/screens/chat/sheets.cljs @@ -3,7 +3,6 @@ [re-frame.core :as re-frame] [status-im.constants :as constants] [i18n.i18n :as i18n] - [status-im.multiaccounts.core :as multiaccounts] [status-im.ui.components.chat-icon.screen :as chat-icon] [status-im.ui.components.list-selection :as list-selection] [status-im.ui.components.react :as react] @@ -191,52 +190,3 @@ :accessibility-label :delete-transaccent-button :on-press #(hide-sheet-and-dispatch [:chat.ui/delete-message-not-used-any-more chat-id message-id])}]])) - -(defn image-long-press - [{:keys [content identicon from outgoing cant-be-replied] :as message} hide] - (let [contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])] - [react/view - (when-not outgoing - [quo/list-item - {:theme :accent - :icon [chat-icon/contact-icon-contacts-tab - (multiaccounts/displayed-photo {:identicon identicon - :public-key from})] - :title contact-name - :subtitle (i18n/label :t/view-profile) - :accessibility-label :view-chat-details-button - :chevron true - :on-press #(do - (hide) - (re-frame/dispatch [:chat.ui/show-profile from]))}]) - (when-not cant-be-replied - [quo/list-item - {:theme :accent - :title (i18n/label :t/message-reply) - :icon :main-icons/reply - :on-press #(do - (hide) - (re-frame/dispatch [:chat.ui/reply-to-message message]))}]) - ;; we have only base64 string for image, so we need to find a way how to copy it - #_[quo/list-item - {:theme :accent - :title :t/sharing-copy-to-clipboard - :icon :main-icons/copy - :on-press (fn [] - (re-frame/dispatch [:bottom-sheet/hide]) - (react/copy-to-clipboard (:image content)))}] - [quo/list-item - {:theme :accent - :title (i18n/label :t/save) - :icon :main-icons/download - :on-press (fn [] - (hide) - (re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)]))}] - ;; we have only base64 string for image, so we need to find a way how to share it - #_[quo/list-item - {:theme :accent - :title :t/sharing-share - :icon :main-icons/share - :on-press (fn [] - (re-frame/dispatch [:bottom-sheet/hide]) - (list-selection/open-share {:message (:image content)}))}]])) diff --git a/src/status_im/ui/screens/chat/styles/main.cljs b/src/status_im/ui/screens/chat/styles/main.cljs index 661d2b5e36..96de9d7553 100644 --- a/src/status_im/ui/screens/chat/styles/main.cljs +++ b/src/status_im/ui/screens/chat/styles/main.cljs @@ -1,17 +1,11 @@ (ns status-im.ui.screens.chat.styles.main - (:require [quo.design-system.colors :as colors] - [status-im.ui.components.emoji-thumbnail.utils :as emoji-utils])) + (:require [quo.design-system.colors :as colors])) (def toolbar-container {:flex 1 :align-items :center :flex-direction :row}) -(def pins-name-view - {:flex 1 - :justify-content :center - :align-items :center}) - (def chat-name-view {:flex 1 :justify-content :center}) @@ -48,57 +42,6 @@ :padding-vertical 50 :margin-right 6}) -(defn intro-header-container - [loading-messages? no-messages?] - (if (or loading-messages? no-messages?) - {:flex 1 - :flex-direction :column - :justify-content :center - :align-items :center} - {:flex 1 - :flex-direction :column - :justify-content :center - :align-items :center})) - -(defn intro-header-icon - [diameter color] - {:width diameter - :height diameter - :align-items :center - :justify-content :center - :border-radius (/ diameter 2) - :background-color color - :border-width 0.5 - :border-color "rgba(0,0,0,0.1)"}) - -(def intro-header-icon-text - {:color colors/white - :font-size 52 - :font-weight "700" - :opacity 0.8 - :line-height 72}) - -(defn emoji-intro-header-icon-text - [size] - {:font-size (emoji-utils/emoji-font-size size) - :margin-top (emoji-utils/emoji-top-margin-for-vertical-alignment size)}) ;; Required for vertical alignment bug - Check function defination for more info - -(defn intro-header-chat-name - [] - {:font-size 22 - :font-weight "700" - :line-height 28 - :text-align :center - :margin-bottom 8 - :margin-horizontal 32 - :color colors/black}) - -(def intro-header-description-container - {:flex-wrap :wrap - :align-items :flex-start - :flex-direction :row - :margin-horizontal 32}) - (def loading-text {:color colors/gray :font-size 15 @@ -107,51 +50,6 @@ :margin-right 4 :text-align :center}) -(def intro-header-description - {:color colors/gray - :line-height 22 - :text-align :center - :margin-horizontal 32}) - -(def group-chat-join-footer - {:flex 1 - :justify-content :center}) - -(def group-chat-join-container - {:flex 1 - :padding-bottom 40 - :align-items :center - :justify-content :center}) - -(def are-you-friends-bubble - {:border-radius 8 - :border-width 1 - :margin-top 4 - :border-color colors/gray-lighter - :align-self :flex-start - :padding-vertical 12 - :margin-horizontal 8 - :padding-horizontal 16 - :margin-bottom 50}) - -(def are-you-friends-text - {:line-height 22 - :text-align :center - :font-size 15 - :color colors/gray}) - -(def share-my-profile - {:color colors/blue - :text-align :center - :margin-top 11 - :line-height 22 - :font-size 15}) - -(def tribute-received-note - {:font-size 13 - :line-height 18 - :text-align :center}) - (def contact-request {:width "100%" :justify-content :center diff --git a/src/status_im/ui/screens/chat/styles/message/audio_old.cljs b/src/status_im/ui/screens/chat/styles/message/audio_old.cljs deleted file mode 100644 index cccc477380..0000000000 --- a/src/status_im/ui/screens/chat/styles/message/audio_old.cljs +++ /dev/null @@ -1,51 +0,0 @@ -(ns status-im.ui.screens.chat.styles.message.audio-old - (:require [quo.design-system.colors :as colors] - [status-im.ui.screens.chat.styles.message.message-old :as message.style] - [status-im.utils.platform :as platform])) - -(defn container - [window-width] - {:width (* window-width 0.60) - :flex-direction :column - :justify-content :space-between}) - -(def play-pause-slider-container - {:flex-direction :row - :align-items :center}) - -(def slider-container - {:flex-direction :column - :align-items :stretch - :flex-grow 1}) - -(defn slider - [outgoing] - {:style (merge {:margin-left 12 - :height 34} - (when platform/ios? {:margin-bottom 4})) - :thumb-tint-color (if outgoing - colors/white - colors/blue) - :minimum-track-tint-color (if outgoing - colors/white - colors/blue) - :maximum-track-tint-color (if outgoing - colors/white-transparent - colors/gray-transparent-40)}) - -(defn play-pause-container - [outgoing? loading?] - {:background-color (if outgoing? colors/white-persist colors/blue) - :width 28 - :height 28 - :padding (if loading? 4 2) - :border-radius 15}) - -(def times-container - {:flex-direction :row - :justify-content :space-between}) - -(defn timestamp - [outgoing] - (merge (message.style/audio-message-timestamp-text outgoing) - {:margin-left 40})) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/styles/message/datemark.cljs b/src/status_im/ui/screens/chat/styles/message/datemark.cljs deleted file mode 100644 index ca6aadfda2..0000000000 --- a/src/status_im/ui/screens/chat/styles/message/datemark.cljs +++ /dev/null @@ -1,24 +0,0 @@ -(ns status-im.ui.screens.chat.styles.message.datemark - (:require [quo2.foundations.colors :as quo2.colors])) - -(def datemark-mobile - {:flex 1 - :justify-content :center - :margin-vertical 16 - :padding-left 65}) - -(defn divider - [] - {:flex 1 - :width "100%" - :height 1 - :padding-left 53 - :background-color (quo2.colors/theme-colors quo2.colors/divider-light quo2.colors/divider-dark) - :margin-top 5}) - -(defn datemark-text - [] - {:color quo2.colors/neutral-50 - :font-size 14 - :line-height 16 - :font-weight "500"}) diff --git a/src/status_im/ui/screens/chat/styles/message/datemark_old.cljs b/src/status_im/ui/screens/chat/styles/message/datemark_old.cljs deleted file mode 100644 index 3e8e9960bc..0000000000 --- a/src/status_im/ui/screens/chat/styles/message/datemark_old.cljs +++ /dev/null @@ -1,12 +0,0 @@ -(ns status-im.ui.screens.chat.styles.message.datemark-old - (:require [quo.design-system.colors :as colors])) - -(def datemark-mobile - {:flex 1 - :align-items :center - :margin-top 16 - :height 22}) - -(defn datemark-text - [] - {:color colors/gray}) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/styles/message/message_old.cljs b/src/status_im/ui/screens/chat/styles/message/message_old.cljs deleted file mode 100644 index 19e0bf0021..0000000000 --- a/src/status_im/ui/screens/chat/styles/message/message_old.cljs +++ /dev/null @@ -1,536 +0,0 @@ -(ns status-im.ui.screens.chat.styles.message.message-old - (:require [quo.design-system.colors :as colors] - [status-im.constants :as constants] - [status-im.ui.components.react :as react] - [status-im.ui.components.typography :as typography] - [status-im.ui.screens.chat.styles.photos :as photos])) - -(defn style-message-text - [outgoing] - {:color (if outgoing colors/white-persist colors/text)}) - -(defn system-message-body - [_] - {:margin-top 4 - :margin-left 8 - :margin-right 8 - :align-self :center - :align-items :center}) - -(defn message-body - [{:keys [outgoing]}] - (let [align (if outgoing :flex-end :flex-start) - direction (if outgoing :row-reverse :row)] - {:flex-direction direction - :margin-top 4 - :align-self align - :align-items align})) - -(def message-timestamp - {:font-size 10}) - -(defn message-status-placeholder - [] - (merge message-timestamp {:opacity 0 :color "rgba(0,0,0,0)"})) - -(defn message-timestamp-wrapper - [{:keys [last-in-group? outgoing group-chat]}] - {:justify-content :center - (if outgoing :margin-right :margin-left) 12 ;; horizontal margin is only required at the adjust side - ;; of the message. - :margin-top (if (and last-in-group? - (or outgoing - (not group-chat))) - 16 - 0) ;; Add gap between message groups - :opacity 0}) - -(defn message-timestamp-text - [] - (merge message-timestamp - {:color colors/gray - :text-align :center})) - -(defn message-status-text - [outgoing] - {:font-size 10 - :line-height 10 - :color (if outgoing - colors/white-transparent-70-persist - colors/gray)}) - -(defn audio-message-timestamp-text - [outgoing] - (merge message-timestamp - {:line-height 10 - :color (if outgoing - colors/white-transparent-70-persist - colors/gray)})) - -(defn message-wrapper - [{:keys [outgoing in-popover?]}] - (if (and outgoing (not in-popover?)) - {:margin-left 96} - {:margin-right 96})) - -(defn message-author-wrapper - [outgoing display-photo? in-popover?] - (let [align (if (and outgoing (not in-popover?)) :flex-end :flex-start)] - (merge {:flex-direction :column - :flex-shrink 1 - :align-items align} - (if (and outgoing (not in-popover?)) - {:margin-right 8} - (when-not display-photo? - {:margin-left 8}))))) - -(defn delivery-status - [outgoing] - (if outgoing - {:align-self :flex-end - :padding-right 8} - {:align-self :flex-start - :padding-left 8})) - -(defn pin-indicator - [outgoing display-photo?] - (merge - {:flex-direction :row - :border-top-left-radius (if outgoing 12 4) - :border-top-right-radius (if outgoing 4 12) - :border-bottom-left-radius 12 - :border-bottom-right-radius 12 - :padding-left 8 - :padding-right 10 - :padding-vertical 5 - :background-color colors/gray-lighter - :justify-content :center - :max-width "80%"} - (if outgoing - {:align-self :flex-end - :align-items :flex-end} - {:align-self :flex-start - :align-items :flex-start}) - (when display-photo? - {:margin-left 44}))) - -(defn pin-indicator-container - [outgoing] - (merge - {:margin-top 2 - :align-items :center - :justify-content :center} - (if outgoing - {:align-self :flex-end - :align-items :flex-end - :padding-right 8} - {:align-self :flex-start - :align-items :flex-start - :padding-left 8}))) - -(defn pinned-by-text-icon-container - [] - {:flex-direction :row - :align-items :flex-start - :top 5 - :left 8 - :position :absolute}) - -(defn pin-icon-container - [] - {:flex-direction :row - :margin-top 1}) - -(defn pin-author-text - [] - {:margin-left 2 - :margin-right 12 - :padding-right 0 - :left 12 - :flex-direction :row - :flex-shrink 1 - :align-self :flex-start - :overflow :hidden}) - -(defn pinned-by-text - [] - {:margin-left 5}) - -(def message-author-touchable - {:margin-left 12 - :flex-direction :row}) - -(defn message-author-userpic - [outgoing] - (merge - {:width (+ 16 photos/default-size) ;; 16 is for the padding - :align-self :flex-end} - (if outgoing - {:padding-left 8} - {:padding-horizontal 8 - :padding-right 8}))) - -(def delivery-text - {:color colors/gray - :margin-top 2 - :font-size 12}) - -(def not-sent-view - {:flex-direction :row - :margin-bottom 2 - :padding-top 2}) - -(def not-sent-text - (assoc delivery-text - :color colors/red - :text-align :right - :padding-top 4)) - -(def not-sent-icon - {:padding-top 3 - :padding-left 3}) - -(defn emoji-message - [{:keys [incoming-group outgoing]}] - {:font-size 28 - :line-height 34 ;TODO: Smaller crops the icon on the top - :margin-right (if outgoing 18 0) ;; Margin to display outgoing message status - :margin-top (if incoming-group 4 0)}) - -(defn collapse-button - [] - {:height 24 - :width 24 - :background-color colors/blue - :border-radius 12 - :align-items :center - :justify-content :center - :elevation 4 - :shadow-opacity 1 - :shadow-radius 16 - :shadow-color (:shadow-01 @colors/theme) - :shadow-offset {:width 0 :height 4}}) - -(defn message-view-wrapper - [outgoing] - {:align-self :flex-end - :flex-direction (if outgoing :row :row-reverse)}) - -(defn message-view - [{:keys [content-type outgoing group-chat last-in-group? mentioned pinned]}] - (merge - {:border-top-left-radius 16 - :border-top-right-radius 16 - :border-bottom-right-radius 16 - :border-bottom-left-radius 16 - :padding-top 6 - :padding-horizontal 12 - :border-radius 8 - :margin-top (if (and last-in-group? - (or outgoing - (not group-chat))) - 16 - 0)} - (if outgoing - {:border-bottom-right-radius 4} - {:border-bottom-left-radius 4}) - - (cond - pinned {:background-color colors/pin-background} - (= content-type constants/content-type-system-text) nil - outgoing {:background-color colors/blue} - mentioned {:background-color colors/mentioned-background - :border-color colors/mentioned-border - :border-width 1} - :else {:background-color colors/blue-light}) - - (when (= content-type constants/content-type-emoji) - {:flex-direction :row}))) - -(defn message-view-content - [] - {:padding-bottom 6 - :overflow :hidden}) - -(def status-container - {:padding-horizontal 5}) - -(defn status-text - [] - {:margin-top 9 - :font-size 14 - :color colors/gray}) - -(defn message-author-name - [chosen?] - {:font-size (if chosen? 13 12) - :font-weight (if chosen? "500" "400") - :padding-top 6 - :padding-left 12 - :text-align-vertical :center}) - -(defn quoted-message-container - [outgoing] - {:margin-bottom 6 - :padding-bottom 6 - :border-bottom-color (if outgoing - colors/white-transparent-10 - colors/black-transparent) - :border-bottom-width 2 - :border-bottom-left-radius 2 - :border-bottom-right-radius 2}) - -(def quoted-message-author-container - {:flex-direction :row - :align-items :center - :justify-content :flex-start}) - -(defn quoted-message-author - [outgoing chosen?] - (assoc (message-author-name chosen?) - :padding-bottom 6 - :padding-top 0 - :padding-left 0 - :line-height 18 - :font-weight "500" - :color (if outgoing - colors/white-transparent-70-persist - colors/gray))) - -(defn quoted-message-text - [outgoing] - {:font-size 14 - :color (if outgoing - colors/white-transparent-70-persist - colors/gray)}) - -;; Markdown styles - -(defn default-text-style - [] - {:max-font-size-multiplier react/max-font-size-multiplier - :style (assoc (typography/default-style) - :line-height - 22)}) - -(defn outgoing-text-style - [] - (update (default-text-style) - :style - assoc - :color colors/white-persist)) - -(defn system-text-style - [] - (update (default-text-style) - :style assoc - :color colors/gray - :line-height 20 - :font-size 14 - :text-align :center - :font-weight "400")) - -(defn text-style - [outgoing content-type in-popover?] - (merge - (when in-popover? {:number-of-lines 2}) - (cond - (= content-type constants/content-type-system-text) (system-text-style) - outgoing (outgoing-text-style) - :else (default-text-style)))) - -(defn emph-text-style - [] - (update (default-text-style) - :style - assoc - :font-style :italic)) - -(defn outgoing-emph-text-style - [] - (update (emph-text-style) - :style - assoc - :color colors/white-persist)) - -(defn emph-style - [outgoing] - (if outgoing - (outgoing-emph-text-style) - (emph-text-style))) - -(defn strong-text-style - [] - (update (default-text-style) - :style - assoc - :font-weight "700")) - -(defn outgoing-strong-text-style - [] - (update (strong-text-style) - :style - assoc - :color colors/white-persist)) - -(defn strong-style - [outgoing] - (if outgoing - (outgoing-strong-text-style) - (strong-text-style))) - -(defn strong-emph-style - [outgoing] - (update (strong-style outgoing) - :style - assoc - :font-style :italic)) - -(defn strikethrough-style - [outgoing] - (cond-> (update (default-text-style) - :style - assoc - :text-decoration-line :line-through) - outgoing - (update :style assoc :color colors/white-persist))) - -(def code-block-background "#2E386B") - -(defn inline-code-style - [] - {:color colors/white-persist - :background-color code-block-background}) - -(def codeblock-style - {:padding 10 - :background-color code-block-background - :border-radius 4}) - -(def codeblock-text-style - {:color colors/white-persist}) - -(defn default-blockquote-style - [] - {:style {:border-left-width 2 - :padding-left 3 - :border-left-color colors/gray-transparent-40}}) - -(defn outgoing-blockquote-style - [] - (update (default-blockquote-style) - :style - assoc - :border-left-color colors/white-transparent-70-persist)) - -(defn blockquote-style - [outgoing] - (if outgoing - (outgoing-blockquote-style) - (default-blockquote-style))) - -(defn default-blockquote-text-style - [] - (update (default-text-style) - :style - assoc - :line-height 19 - :font-size 14 - :color colors/black-transparent-50)) - -(defn outgoing-blockquote-text-style - [] - (update (default-blockquote-text-style) - :style - assoc - :color colors/white-transparent-70-persist)) - -(defn blockquote-text-style - [outgoing] - (if outgoing - (outgoing-blockquote-text-style) - (default-blockquote-text-style))) - -(defn image-message - [{:keys [outgoing width height]}] - {:overflow :hidden - :border-top-left-radius 16 - :border-top-right-radius 16 - :border-bottom-left-radius (if outgoing 16 4) - :border-bottom-right-radius (if outgoing 4 16) - :width width - :height height}) - -(defn image-message-border - [opts] - (merge (image-message opts) - {:opacity (:opacity opts) - :border-width 1 - :top 0 - :left 0 - :position :absolute - :background-color :transparent - :border-color colors/black-transparent})) - -(defn community-verified - [] - {:border-right-width 1 - :border-left-width 1 - :border-top-width 1 - :border-left-color colors/gray-lighter - :border-right-color colors/gray-lighter - :border-top-left-radius 10 - :border-top-right-radius 10 - :padding-vertical 8 - :padding-horizontal 15 - :border-top-color colors/gray-lighter}) - -(defn community-message - [verified] - {:flex-direction :row - :padding-vertical 12 - :border-top-left-radius (when-not verified 10) - :border-top-right-radius (when-not verified 10) - :border-right-width 1 - :border-left-width 1 - :border-top-width 1 - :border-color colors/gray-lighter}) - -(defn community-view-button - [] - {:border-width 1 - :padding-vertical 8 - :border-bottom-left-radius 10 - :border-bottom-right-radius 10 - :border-color colors/gray-lighter}) - -(defn contact-request-status-label - [state] - {:width 136 - :border-radius 8 - :flex 1 - :justify-content :center - :align-items :center - :background-color (when (= :retry state) - colors/blue-light) - :border-width 1 - :border-color (case state - constants/contact-request-message-state-accepted colors/green-transparent-10 - constants/contact-request-message-state-declined colors/red-light - constants/contact-request-message-state-pending colors/gray-lighter) - :padding-vertical 10 - :padding-horizontal 16}) - -(defn content-type-contact-request - [outgoing] - {:width 168 - :min-height 224.71 - :border-radius 8 - :border-width 1 - :border-color colors/gray-lighter - :align-items :center - :padding-bottom 10 - :margin-vertical 4 - :align-self (if outgoing :flex-end :flex-start) - :margin-right (if outgoing 8 0) - :margin-left (if outgoing 0 8)}) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/toolbar_content.cljs b/src/status_im/ui/screens/chat/toolbar_content.cljs deleted file mode 100644 index 118f1cd362..0000000000 --- a/src/status_im/ui/screens/chat/toolbar_content.cljs +++ /dev/null @@ -1,58 +0,0 @@ -(ns status-im.ui.screens.chat.toolbar-content - (:require [quo.react-native :as rn] - [re-frame.core :as re-frame] - [status-im.constants :as constants] - [i18n.i18n :as i18n] - [status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [status-im.ui.screens.chat.styles.main :as st])) - -(defn- group-last-activity - [{:keys [contacts public?]}] - [rn/view {:flex-direction :row} - [rn/text {:style st/toolbar-subtitle} - (if public? - (i18n/label :t/public-group-status) - (let [cnt (count contacts)] - (if (zero? cnt) - (i18n/label :members-active-none) - (i18n/label-pluralize cnt :t/members-active))))]]) - -(defn one-to-one-name - [from] - (let [[first-name _] @(re-frame.core/subscribe [:contacts/contact-two-names-by-identity from])] - [rn/text - {:style st/chat-name-text - :number-of-lines 1 - :accessibility-label :chat-name-text} - first-name])) - -(defn contact-indicator - [contact-id] - (let [added? @(re-frame/subscribe [:contacts/contact-added? contact-id])] - [rn/view {:flex-direction :row} - [rn/text {:style st/toolbar-subtitle} - (if added? - (i18n/label :chat-is-a-contact) - (i18n/label :chat-is-not-a-contact))]])) - -(defn toolbar-content-view-inner - [chat-info] - (let [{:keys [group-chat invitation-admin color chat-id contacts chat-type chat-name public? emoji]} - chat-info] - [rn/view {:style st/toolbar-container} - [rn/view {:margin-right 10} - [chat-icon.screen/chat-icon-view-toolbar chat-id group-chat chat-name color emoji 36]] - [rn/view {:style st/chat-name-view} - (if group-chat - [rn/text - {:style st/chat-name-text - :number-of-lines 1 - :accessibility-label :chat-name-text} - chat-name] - [one-to-one-name chat-id]) - (when-not group-chat - [contact-indicator chat-id]) - (when (and group-chat (not invitation-admin) (not= chat-type constants/community-chat-type)) - [group-last-activity - {:contacts contacts - :public? public?}])]])) diff --git a/src/status_im/ui/screens/chat/utils.cljs b/src/status_im/ui/screens/chat/utils.cljs index 0a942475ec..0efb2e16c0 100644 --- a/src/status_im/ui/screens/chat/utils.cljs +++ b/src/status_im/ui/screens/chat/utils.cljs @@ -1,12 +1,9 @@ (ns status-im.ui.screens.chat.utils (:require [quo.design-system.colors :as colors] - [status-im.ethereum.stateofus :as stateofus] [i18n.i18n :as i18n] [status-im.multiaccounts.core :as multiaccounts] [status-im.ui.components.react :as react])) -(def ^:private reply-symbol "↪ ") - (defn format-author-old ([contact] (format-author-old contact nil)) ([{:keys [names] :as contact} {:keys [modal profile? you?]}] @@ -63,29 +60,3 @@ (if (and max-length (> (count first-name) max-length)) (str (subs first-name 0 max-length) "...") first-name)])))) - -(defn format-reply-author - [from username current-public-key style outgoing] - (let [contact-name (str reply-symbol username)] - (or (and (= from current-public-key) - [react/text {:style (style true)} - (str reply-symbol (i18n/label :t/You))]) - (if (or (= (aget contact-name 0) "@") - ;; in case of replies - (= (aget contact-name 1) "@")) - (let [trimmed-name (subs contact-name 0 81)] - [react/text - {:number-of-lines 2 - :style (merge {:color colors/blue - :font-size 13 - :line-height 18 - :font-weight "500"})} - (or (stateofus/username trimmed-name) trimmed-name)]) - [react/text - {:style (merge {:color (if outgoing - colors/white-transparent-70-persist - colors/gray) - :font-size 12 - :line-height 18 - :font-weight "400"})} - contact-name])))) diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs deleted file mode 100644 index 518783d7a8..0000000000 --- a/src/status_im/ui/screens/chat/views.cljs +++ /dev/null @@ -1,536 +0,0 @@ -(ns status-im.ui.screens.chat.views - (:require - [clojure.string :as string] - [quo.animated :as animated] - [quo.core :as quo] - [quo.design-system.colors :as colors] - [quo.react :as quo.react] - [quo.react-native :as rn] - [re-frame.core :as rf] - re-frame.db - [reagent.core :as reagent] - [status-im.constants :as constants] - [i18n.i18n :as i18n] - [status-im.react-native.resources :as resources] - [status-im.ui.components.chat-icon.screen :as chat-icon.screen] - [status-im.ui.components.connectivity.view :as connectivity] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.list.views :as list] - [status-im.ui.components.react :as react] - [status-im.ui.components.toolbar :as toolbar] - [status-im.ui.screens.chat.audio-message.views :as audio-message] - [status-im.ui.screens.chat.components.accessory :as accessory] - [status-im.ui.screens.chat.components.contact-request :as contact-request] - [status-im.ui.screens.chat.components.edit :as edit] - [status-im.ui.screens.chat.components.input :as components] - [status-im.ui.screens.chat.components.reply :as reply] - [status-im.ui.screens.chat.extensions.views :as extensions] - [status-im.ui.screens.chat.group :as chat.group] - [status-im.ui.screens.chat.image.views :as image] - [status-im.ui.screens.chat.message.datemark :as message-datemark] - [status-im.ui.screens.chat.message.gap :as gap] - [status-im.ui.screens.chat.message.message :as message] - [status-im.ui.screens.chat.sheets :as sheets] - [status-im.ui.screens.chat.state :as state] - [status-im.ui.screens.chat.stickers.views :as stickers] - [status-im.ui.screens.chat.styles.main :as style] - [status-im.ui.screens.chat.toolbar-content :as toolbar-content] - [status-im.utils.platform :as platform] - [status-im.utils.utils :as utils] - [status-im2.navigation.state :as navigation.state] - [utils.debounce :as debounce])) - -(defn invitation-requests - [chat-id admins] - (let [current-pk @(rf/subscribe [:multiaccount/public-key]) - admin? (get admins current-pk)] - (when admin? - (let [invitations @(rf/subscribe [:group-chat/pending-invitations-by-chat-id chat-id])] - (when (seq invitations) - [react/touchable-highlight - {:on-press #(rf/dispatch [:navigate-to :group-chat-invite]) - :accessibility-label :invitation-requests-button} - [react/view {:style (style/add-contact)} - [react/text {:style style/add-contact-text} - (i18n/label :t/group-membership-request)]]]))))) - -(defn add-contact-bar - [public-key] - (when-not (or @(rf/subscribe [:contacts/contact-added? public-key]) - @(rf/subscribe [:contacts/contact-blocked? public-key])) - [react/touchable-highlight - {:on-press - #(rf/dispatch [:contact.ui/add-to-contact-pressed public-key]) - :accessibility-label :add-to-contacts-button} - [react/view {:style (style/add-contact)} - [icons/icon :main-icons/add - {:color colors/blue}] - [react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]])) - -(defn contact-request - [] - (let [contact-request @(rf/subscribe [:chats/sending-contact-request])] - [react/view {:style style/contact-request} - [react/image - {:source (resources/get-image :hand-wave) - :style {:width 112 - :height 96.71 - :margin-top 17}}] - [quo/text - {:style {:margin-top 14} - :weight :bold - :size :large} - (i18n/label :t/say-hi)] - [quo/text - {:style {:margin-top 2 - :margin-bottom 14}} - (i18n/label :t/send-contact-request-message)] - (when-not contact-request - [react/view - {:style {:padding-horizontal 16 - :padding-bottom 8}} - [quo/button - {:style {:width "100%"} - :accessibility-label :contact-request--button - :on-press #(rf/dispatch [:chat.ui/send-contact-request])} - (i18n/label :t/contact-request)]])])) - -(defn chat-intro - [{:keys [chat-id - chat-name - chat-type - group-chat - invitation-admin - contact-name - color - loading-messages? - no-messages? - contact-request-state - emoji]}] - [react/view - {:style (style/intro-header-container loading-messages? no-messages?) - :accessibility-label :history-chat} - ;; Icon section - [react/view - {:style {:margin-top 52 - :margin-bottom 24}} - [chat-icon.screen/emoji-chat-intro-icon-view - chat-name chat-id group-chat emoji - {:default-chat-icon (style/intro-header-icon 120 color) - :default-chat-icon-text (if (string/blank? emoji) - style/intro-header-icon-text - (style/emoji-intro-header-icon-text 120)) - :size 120}]] - ;; Chat title section - [react/text {:style (style/intro-header-chat-name)} - (if group-chat chat-name contact-name)] - ;; Description section - (if group-chat - [chat.group/group-chat-description-container - {:chat-id chat-id - :invitation-admin invitation-admin - :loading-messages? loading-messages? - :chat-name chat-name - :chat-type chat-type - :no-messages? no-messages?}] - [react/text {:style (assoc style/intro-header-description :margin-bottom 32)} - (str (i18n/label :t/empty-chat-description-one-to-one) contact-name)]) - (when - (= chat-type constants/one-to-one-chat-type) - (or (= contact-request-state constants/contact-request-state-none) - (= contact-request-state constants/contact-request-state-received) - (= contact-request-state constants/contact-request-state-dismissed))) - [contact-request]]) - -(defn chat-intro-one-to-one - [{:keys [chat-id] :as opts}] - (let [contact @(rf/subscribe [:contacts/contact-by-identity chat-id]) - contact-names @(rf/subscribe [:contacts/contact-two-names-by-identity - chat-id])] - [chat-intro - (assoc opts - :contact-name (first contact-names) - :contact-request-state (or (:contact-request-state contact) - constants/contact-request-state-none))])) - -(defn chat-intro-header-container - [{:keys [group-chat invitation-admin - chat-type - synced-to - color chat-id chat-name - public? emoji]} - no-messages] - [react/touchable-without-feedback - {:style {:flex 1 - :align-items :flex-start} - :on-press (fn [_] - (react/dismiss-keyboard!))} - (let [opts - {:chat-id chat-id - :group-chat group-chat - :invitation-admin invitation-admin - :chat-type chat-type - :chat-name chat-name - :public? public? - :color color - :loading-messages? (not (pos? synced-to)) - :no-messages? no-messages - :emoji emoji}] - (if group-chat - [chat-intro opts] - [chat-intro-one-to-one opts]))]) - -(defonce messages-list-ref (atom nil)) - -(defn on-viewable-items-changed - [^js e] - (when @messages-list-ref - (reset! state/first-not-visible-item - (when-let [^js last-visible-element (aget (.-viewableItems e) - (dec (.-length ^js (.-viewableItems e))))] - (let [index (.-index last-visible-element) - ;; Get first not visible element, if it's a datemark/gap - ;; we might unnecessarely add messages on receiving as - ;; they do not have a clock value, but most of the times - ;; it will be a message - first-not-visible (aget (.-data ^js (.-props ^js @messages-list-ref)) (inc index))] - (when (and first-not-visible - (= :message (:type first-not-visible))) - first-not-visible)))))) - -(defn bottom-sheet - [input-bottom-sheet] - (case input-bottom-sheet - :stickers - [stickers/stickers-view] - :extensions - [extensions/extensions-view] - :images - [image/image-view] - :audio - [audio-message/audio-message-view] - nil)) - -(defn invitation-bar - [chat-id] - (let [{:keys [state chat-id] :as invitation} - (first @(rf/subscribe [:group-chat/invitations-by-chat-id chat-id])) - {:keys [retry? message]} @(rf/subscribe [:chats/current-chat-membership]) - message-length (count message)] - [react/view {:margin-horizontal 16 :margin-top 10} - (cond - (and invitation (= constants/invitation-state-requested state) (not retry?)) - [toolbar/toolbar - {:show-border? true - :center - [quo/button - {:type :secondary - :disabled true} - (i18n/label :t/request-pending)]}] - - (and invitation (= constants/invitation-state-rejected state) (not retry?)) - [toolbar/toolbar - {:show-border? true - :right - [quo/button - {:type :secondary - :accessibility-label :retry-button - :on-press #(rf/dispatch [:group-chats.ui/membership-retry])} - (i18n/label :t/mailserver-retry)] - :left - [quo/button - {:type :secondary - :accessibility-label :remove-group-button - :on-press #(rf/dispatch [:group-chats.ui/remove-chat-confirmed chat-id])} - (i18n/label :t/remove-group)]}] - :else - [toolbar/toolbar - {:show-border? true - :center - [quo/button - {:type :secondary - :accessibility-label :introduce-yourself-button - :disabled (or (string/blank? message) - (> message-length chat.group/message-max-length)) - :on-press #(rf/dispatch [:send-group-chat-membership-request])} - (i18n/label :t/request-membership)]}])])) - -(defn get-space-keeper-ios - [bottom-space panel-space active-panel text-input-ref] - (fn [state] - ;; NOTE: Only iOs now because we use soft input resize screen on android - (when platform/ios? - (cond - (and state - (< @bottom-space @panel-space) - (not @active-panel)) - (reset! bottom-space @panel-space) - - (and (not state) - (< @panel-space @bottom-space)) - (do - (some-> ^js (quo.react/current-ref text-input-ref) - .focus) - (reset! panel-space @bottom-space) - (reset! bottom-space 0)))))) - -(defn get-set-active-panel - [active-panel] - (fn [panel] - (rn/configure-next - (:ease-opacity-200 rn/custom-animations)) - (reset! active-panel panel) - (reagent/flush) - (when panel - (js/setTimeout #(react/dismiss-keyboard!) 100)))) - -(defn list-footer - [{:keys [chat-id] :as chat}] - (let [loading-messages? @(rf/subscribe [:chats/loading-messages? chat-id]) - no-messages? @(rf/subscribe [:chats/chat-no-messages? chat-id]) - all-loaded? @(rf/subscribe [:chats/all-loaded? chat-id])] - [react/view {:style (when platform/android? {:scaleY -1})} - (if (or loading-messages? (not chat-id) (not all-loaded?)) - [react/view {:height 324 :align-items :center :justify-content :center} - [react/activity-indicator {:animating true}]] - [chat-intro-header-container chat no-messages?])])) - -(defn list-header - [{:keys [chat-id chat-type invitation-admin]}] - (when (= chat-type constants/private-group-chat-type) - [react/view {:style (when platform/android? {:scaleY -1})} - [chat.group/group-chat-footer chat-id invitation-admin]])) - -(defn render-fn - [{:keys [outgoing type] :as message} - idx - _ - {:keys [group-chat public? community? current-public-key space-keeper - chat-id show-input? message-pin-enabled edit-enabled in-pinned-view?]}] - [react/view {:style (when (and platform/android? (not in-pinned-view?)) {:scaleY -1})} - (if (= type :datemark) - [message-datemark/chat-datemark (:value message)] - (if (= type :gap) - [gap/gap message idx messages-list-ref false chat-id] - ; message content - [message/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 message-pin-enabled - :edit-enabled edit-enabled) - space-keeper]))]) - -(def list-key-fn #(or (:message-id %) (:value %))) -(def list-ref #(reset! messages-list-ref %)) - -;;TODO this is not really working in pair with inserting new messages because we stop inserting new -;;messages -;;if they outside the viewarea, but we load more here because end is reached,so its slowdown UI because -;;we -;;load and render 20 messages more, but we can't prevent this , because otherwise :on-end-reached will -;;work wrong -(defn list-on-end-reached - [] - (if @state/scrolling - (rf/dispatch [:chat.ui/load-more-messages-for-current-chat]) - (utils/set-timeout #(rf/dispatch [:chat.ui/load-more-messages-for-current-chat]) - (if platform/low-device? 700 200)))) - -(defn get-render-data - [{:keys [group-chat chat-id public? community-id admins space-keeper show-input? edit-enabled - in-pinned-view?]}] - (let [current-public-key @(rf/subscribe [:multiaccount/public-key]) - community @(rf/subscribe [:communities/community community-id]) - group-admin? (get admins current-public-key) - community-admin? (when community (community :admin)) - message-pin-enabled (and (not public?) - (or (not group-chat) - (and group-chat - (or group-admin? - community-admin?))))] - {:group-chat group-chat - :public? public? - :community? (not (nil? community-id)) - :current-public-key current-public-key - :space-keeper space-keeper - :chat-id chat-id - :show-input? show-input? - :message-pin-enabled message-pin-enabled - :edit-enabled edit-enabled - :in-pinned-view? in-pinned-view?})) - -(defn messages-view - [{:keys [chat - bottom-space - pan-responder - space-keeper - show-input?]}] - (let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat - - messages @(rf/subscribe [:chats/raw-chat-messages-stream chat-id]) - one-to-one? (= chat-type constants/one-to-one-chat-type) - contact-added? (when one-to-one? @(rf/subscribe [:contacts/contact-added? chat-id])) - should-send-contact-request? - (and - one-to-one? - (not contact-added?))] - - ;;do not use anonymous functions for handlers - [list/flat-list - (merge - pan-responder - {:key-fn list-key-fn - :ref list-ref - :header [list-header chat] - :footer [list-footer chat] - :data (when-not should-send-contact-request? - messages) - :render-data (get-render-data {:group-chat group-chat - :chat-id chat-id - :public? public? - :community-id community-id - :admins admins - :space-keeper space-keeper - :show-input? show-input? - :edit-enabled true - :in-pinned-view? false}) - :render-fn render-fn - :on-viewable-items-changed on-viewable-items-changed - :on-end-reached list-on-end-reached - :on-scroll-to-index-failed identity ;;don't remove this - :content-container-style {:padding-top (+ bottom-space 16) - :padding-bottom 16} - :scroll-indicator-insets {:top bottom-space} ;;ios only - :keyboard-dismiss-mode :interactive - :keyboard-should-persist-taps :handled - :onMomentumScrollBegin state/start-scrolling - :onMomentumScrollEnd state/stop-scrolling - ;;TODO https://github.com/facebook/react-native/issues/30034 - :inverted (when platform/ios? true) - :style (when platform/android? {:scaleY -1})})])) - -(defn navigate-back-handler - [] - (when (and (not @navigation.state/curr-modal) (= (get @re-frame.db/app-db :view-id) :chat)) - (react/hw-back-remove-listener navigate-back-handler) - (rf/dispatch [:close-chat]) - (rf/dispatch [:navigate-back]))) - -(defn topbar-content - [] - (let [window-width @(rf/subscribe [:dimensions/window-width]) - {:keys [group-chat chat-id] :as chat-info} @(rf/subscribe [:chats/current-chat])] - [react/touchable-highlight - {:on-press #(when-not group-chat - (debounce/dispatch-and-chill [:chat.ui/show-profile chat-id] 1000)) - :style {:flex 1 :width (- window-width 120)}} - [toolbar-content/toolbar-content-view-inner chat-info]])) - -(defn topbar - [] - ;;we don't use topbar component, because we want chat view as simple (fast) as possible - [react/view {:height 56} - [react/touchable-highlight - {:on-press-in navigate-back-handler - :accessibility-label :back-button - :style {:height 56 - :width 40 - :align-items :center - :justify-content :center - :padding-left 16}} - [icons/icon :main-icons/arrow-left {:color colors/black}]] - [react/view {:flex 1 :left 52 :right 52 :top 0 :bottom 0 :position :absolute} - [topbar-content]] - [react/touchable-highlight - {:on-press-in #(rf/dispatch [:bottom-sheet/show-sheet - {:content (fn [] [sheets/current-chat-actions]) - :height 256}]) - :accessibility-label :chat-menu-button - :style {:right 0 - :top 0 - :bottom 0 - :position :absolute - :height 56 - :width 40 - :align-items :center - :justify-content :center - :padding-right 16}} - [icons/icon :main-icons/more {:color colors/black}]]]) - -(defn chat-render - [] - (let [bottom-space (reagent/atom 0) - panel-space (reagent/atom 52) - active-panel (reagent/atom nil) - position-y (animated/value 0) - pan-state (animated/value 0) - text-input-ref (quo.react/create-ref) - on-update #(when-not (zero? %) (reset! panel-space %)) - pan-responder (accessory/create-pan-responder position-y pan-state) - space-keeper (get-space-keeper-ios bottom-space panel-space active-panel text-input-ref) - set-active-panel (get-set-active-panel active-panel) - on-close #(set-active-panel nil)] - (fn [] - (let [{:keys [chat-id - show-input? - group-chat - admins - invitation-admin] - :as chat} - @(rf/subscribe [:chats/current-chat-chat-view]) - max-bottom-space (max @bottom-space - @panel-space)] - [:<> - [topbar] - [connectivity/loading-indicator] - (when chat-id - (when group-chat - [invitation-requests chat-id admins])) - ;;MESSAGES LIST - [messages-view - {:chat chat - :bottom-space max-bottom-space - :pan-responder pan-responder - :space-keeper space-keeper - :show-input? show-input?}] - (when (and group-chat invitation-admin) - [accessory/view - {:y position-y - :on-update-inset on-update} - [invitation-bar chat-id]]) - [components/autocomplete-mentions text-input-ref max-bottom-space] - (when show-input? - ;; NOTE: this only accepts two children - [accessory/view - {:y position-y - :pan-state pan-state - :has-panel (boolean @active-panel) - :on-close on-close - :on-update-inset on-update} - [react/view - [edit/edit-message-auto-focus-wrapper text-input-ref] - [reply/reply-message-auto-focus-wrapper text-input-ref] - ;; We set the key so we can force a re-render as - ;; it does not rely on ratom but just atoms - ^{:key (str @components/chat-input-key "chat-input")} - [components/chat-toolbar - {:chat-id chat-id - :active-panel @active-panel - :set-active-panel set-active-panel - :text-input-ref text-input-ref}] - [contact-request/contact-request-message-auto-focus-wrapper text-input-ref]] - [bottom-sheet @active-panel]])])))) - -(defn chat - [] - (reagent/create-class - {:component-did-mount (fn [] - (react/hw-back-remove-listener navigate-back-handler) - (react/hw-back-add-listener navigate-back-handler)) - :component-will-unmount (fn [] (react/hw-back-remove-listener navigate-back-handler)) - :reagent-render chat-render})) diff --git a/src/status_im/ui/screens/ens/views.cljs b/src/status_im/ui/screens/ens/views.cljs index 7850545876..0bb9f19fef 100644 --- a/src/status_im/ui/screens/ens/views.cljs +++ b/src/status_im/ui/screens/ens/views.cljs @@ -5,7 +5,6 @@ [quo.design-system.colors :as colors] [re-frame.core :as re-frame] [reagent.core :as reagent] - [status-im.constants :as constants] [status-im.ens.core :as ens] [status-im.ethereum.core :as ethereum] [status-im.ethereum.ens :as ethereum.ens] @@ -21,7 +20,6 @@ [status-im.ui.components.react :as react] [status-im.ui.components.toolbar :as toolbar] [status-im.ui.components.topbar :as topbar] - [status-im.ui.screens.chat.message.message :as message] [status-im.ui.screens.chat.photos :as photos] [status-im.ui.screens.chat.utils :as chat.utils] [status-im.ui.screens.profile.components.views :as profile.components] @@ -762,18 +760,12 @@ :action-fn #(re-frame/dispatch [:bottom-sheet/show-sheet {:content (fn [] (name-list names preferred-name))}])}]])] - (let [message {:content {:parsed-text - [{:type "paragraph" - :children [{:literal (i18n/label :t/ens-test-message)}]}]} - :content-type constants/content-type-text - :timestamp-str "9:41 AM"}] - [react/view - [react/view {:padding-left 72} - [my-name]] - [react/view {:flex-direction :row} - [react/view {:padding-left 16 :padding-top 4} - [photos/photo (multiaccounts/displayed-photo account) {:size 36}]] - [message/->message message {:on-long-press identity}]]])]]) + [react/view + [react/view {:padding-left 72} + [my-name]] + [react/view {:flex-direction :row} + [react/view {:padding-left 16 :padding-top 4} + [photos/photo (multiaccounts/displayed-photo account) {:size 36}]]]]]]) (views/defview main [] diff --git a/src/status_im/ui/screens/popover/views.cljs b/src/status_im/ui/screens/popover/views.cljs index 9a8ba49b0d..2203c9ee31 100644 --- a/src/status_im/ui/screens/popover/views.cljs +++ b/src/status_im/ui/screens/popover/views.cljs @@ -7,7 +7,6 @@ [status-im.ui.components.animation :as anim] [status-im.ui.components.react :as react] [status-im.ui.screens.biometric.views :as biometric] - [status-im.ui.screens.chat.message.pinned-message :as pinned-message] [status-im.ui.screens.communities.views :as communities] [status-im.ui.screens.keycard.frozen-card.view :as frozen-card] [status-im.ui.screens.keycard.views :as keycard.views] @@ -181,9 +180,6 @@ (= :password-reset-popover view) [reset-password.views/reset-password-popover] - (= :pin-limit view) - [pinned-message/pin-limit-popover] - (= :fees-warning view) [signing-sheets/fees-warning] diff --git a/src/status_im/ui/screens/profile/contact/views.cljs b/src/status_im/ui/screens/profile/contact/views.cljs index 6a468aa82b..4e9fb22bb6 100644 --- a/src/status_im/ui/screens/profile/contact/views.cljs +++ b/src/status_im/ui/screens/profile/contact/views.cljs @@ -11,14 +11,11 @@ [status-im.ui.components.chat-icon.screen :as chat-icon] [status-im.ui.components.icons.icons :as icons] [status-im.ui.components.keyboard-avoid-presentation :as kb-presentation] - [status-im.ui.components.list.views :as list] - [status-im.ui.components.profile-header.view :as profile-header] [status-im.ui.components.react :as react] [status-im.ui.components.toolbar :as toolbar] [status-im.ui.components.topbar :as topbar] [status-im.ui.screens.profile.components.sheets :as sheets] [status-im.ui.screens.profile.contact.styles :as styles] - [status-im.ui.screens.status.views :as status.views] [status-im.utils.utils :as utils]) (:require-macros [status-im.utils.views :as views])) @@ -210,18 +207,6 @@ [] (let [{:keys [public-key name ens-verified] :as contact} @(re-frame/subscribe [:contacts/current-contact]) - current-chat-id @(re-frame/subscribe - [:chats/current-profile-chat]) - messages @(re-frame/subscribe - [:chats/profile-messages-stream - current-chat-id]) - no-messages? @(re-frame/subscribe [:chats/chat-no-messages? - current-chat-id]) - muted? @(re-frame/subscribe [:chats/muted - public-key]) - pinned-messages @(re-frame/subscribe [:chats/pinned - public-key]) - [first-name second-name] (multiaccounts/contact-two-names contact true) on-share #(re-frame/dispatch [:show-popover (merge @@ -237,43 +222,4 @@ :on-press on-share}] :left-accessories [{:icon :main-icons/close :accessibility-label :back-button - :on-press #(re-frame/dispatch [:navigate-back])}]}] - [list/flat-list - {:key-fn #(or (:message-id %) (:value %)) - :header [:<> - [(profile-header/extended-header - {:on-press on-share - :bottom-separator false - :title first-name - :photo (multiaccounts/displayed-photo contact) - :monospace (not ens-verified) - :subtitle second-name - :public-key public-key})] - [react/view - {:height 1 :background-color colors/gray-lighter :margin-top 8}] - [nickname-settings contact] - [pin-settings public-key (count pinned-messages)] - [react/view {:height 1 :background-color colors/gray-lighter}] - [react/view - {:padding-top 17 - :flex-direction :row - :align-items :stretch - :flex 1} - (for [{:keys [label] :as action} (actions contact muted?) - :when label] - ^{:key label} - [button-item action])] - [react/view - {:height 1 :background-color colors/gray-lighter :margin-top 16}] - (when no-messages? - [react/view {:padding-horizontal 32 :margin-top 32} - [react/view (styles/updates-descr-cont) - [react/text {:style {:color colors/gray :line-height 22}} - (i18n/label :t/status-updates-descr)]]])] - :ref #(reset! status.views/messages-list-ref %) - :on-end-reached #(re-frame/dispatch [:chat.ui/load-more-messages current-chat-id]) - :on-scroll-to-index-failed #() ;;don't remove this - :render-data {:chat-id current-chat-id - :profile true} - :render-fn status.views/render-message - :data messages}]]))) + :on-press #(re-frame/dispatch [:navigate-back])}]}]]))) diff --git a/src/status_im/ui/screens/profile/group_chat/views.cljs b/src/status_im/ui/screens/profile/group_chat/views.cljs index 17151b357f..96800a9177 100644 --- a/src/status_im/ui/screens/profile/group_chat/views.cljs +++ b/src/status_im/ui/screens/profile/group_chat/views.cljs @@ -11,7 +11,6 @@ [status-im.ui.components.profile-header.view :as profile-header] [status-im.ui.components.react :as react] [status-im.ui.components.topbar :as topbar] - [status-im.ui.screens.chat.message.message :as message] [status-im.ui.screens.chat.photos :as photos] [status-im.ui.screens.chat.sheets :as chat.sheets] [status-im.ui.screens.chat.utils :as chat.utils] @@ -111,21 +110,16 @@ (debounce/dispatch-and-chill event 2000)) (defn invitation-sheet - [{:keys [introduction-message id]} contact] + [{:keys [id]} contact] (let [members @(re-frame/subscribe [:contacts/current-chat-contacts]) allow-adding-members? (< (count members) constants/max-group-chat-participants)] [react/view - (let [message {:content {:parsed-text - [{:type "paragraph" - :children [{:literal introduction-message}]}]} - :content-type constants/content-type-text}] - [react/view {:margin-bottom 8 :margin-right 16} - [react/view {:padding-left 72} - (chat.utils/format-author-old contact)] - [react/view {:flex-direction :row :align-items :flex-end} - [react/view {:padding-left 16 :padding-top 4} - [photos/photo (multiaccounts/displayed-photo contact) {:size 36}]] - [message/->message message {:on-long-press identity}]]]) + [react/view {:margin-bottom 8 :margin-right 16} + [react/view {:padding-left 72} + (chat.utils/format-author-old contact)] + [react/view {:flex-direction :row :align-items :flex-end} + [react/view {:padding-left 16 :padding-top 4} + [photos/photo (multiaccounts/displayed-photo contact) {:size 36}]]]] [quo/list-item {:theme :accent :disabled (not allow-adding-members?) diff --git a/src/status_im/ui/screens/screens.cljs b/src/status_im/ui/screens/screens.cljs index d69add1aa2..b16404e3b6 100644 --- a/src/status_im/ui/screens/screens.cljs +++ b/src/status_im/ui/screens/screens.cljs @@ -17,7 +17,6 @@ [status-im.ui.screens.browser.tabs.views :as browser.tabs] [status-im.ui.screens.browser.views :as browser] [status-im.ui.screens.bug-report :as bug-report] - [status-im.ui.screens.chat.pinned-messages :as pin-messages] [status-im.ui.screens.communities.channel-details :as communities.channel-details] [status-im.ui.screens.communities.community :as community] [status-im.ui.screens.communities.community-emoji-thumbnail-picker :as @@ -86,8 +85,6 @@ [status-im.ui.screens.qr-scanner.views :as qr-scanner] [status-im.ui.screens.reset-password.views :as reset-password] [status-im.ui.screens.rpc-usage-info :as rpc-usage-info] - [status-im.ui.screens.status.new.views :as status.new] - [status-im.ui.screens.status.views :as status.views] [status-im.ui.screens.stickers.views :as stickers] [status-im.ui.screens.sync-settings.views :as sync-settings] [status-im.ui.screens.terms-of-service.views :as terms-of-service] @@ -200,11 +197,6 @@ :component onboarding.phrase/wizard-recovery-success} ;;CHAT - ;Pinned messages - {:name :chat-pinned-messages - ;TODO custom subtitle - :options {:topBar {:visible false}} - :component pin-messages/pinned-messages} {:name :group-chat-profile ;;TODO animated-header @@ -388,13 +380,6 @@ :options {:topBar {:visible false}} :component wallet.swap/asset-selector} - ;;MY STATUS - - {:name :status - :on-focus [:init-timeline-chat] - :insets {:top true} - :component status.views/timeline} - ;;PROFILE {:name :my-profile @@ -696,12 +681,6 @@ :options {:topBar {:visible false}} :component wallet.collectibles/nft-details-modal} - ;My Status - {:name :my-status - :insets {:bottom true} - :options {:topBar {:title {:text (i18n/label :t/my-status)}}} - :component status.new/my-status} - ;[Browser] New bookmark {:name :new-bookmark :insets {:bottom true} diff --git a/src/status_im/ui/screens/status/new/styles.cljs b/src/status_im/ui/screens/status/new/styles.cljs deleted file mode 100644 index 1ae16cef62..0000000000 --- a/src/status_im/ui/screens/status/new/styles.cljs +++ /dev/null @@ -1,34 +0,0 @@ -(ns status-im.ui.screens.status.new.styles - (:require [quo.design-system.colors :as colors])) - -(def buttons - {:padding-horizontal 14 - :padding-vertical 10 - :justify-content :space-between - :height 88}) - -(def image - {:width 72 - :height 72 - :background-color :black - :resize-mode :cover - :margin-right 4 - :border-radius 4}) - -(defn photos-buttons - [] - {:height 88 - :border-top-width 1 - :border-top-color colors/gray-lighter - :flex-direction :row - :align-items :center}) - -(def count-container - {:top 0 - :bottom 0 - :left 0 - :right 0 - :align-items :center - :justify-content :center - :position :absolute - :pointerEvents :none}) \ No newline at end of file diff --git a/src/status_im/ui/screens/status/new/views.cljs b/src/status_im/ui/screens/status/new/views.cljs deleted file mode 100644 index 28b1dcb368..0000000000 --- a/src/status_im/ui/screens/status/new/views.cljs +++ /dev/null @@ -1,128 +0,0 @@ -(ns status-im.ui.screens.status.new.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) - (:require [clojure.string :as string] - [quo.components.animated.pressable :as pressable] - [quo.core :as quo] - [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [i18n.i18n :as i18n] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.keyboard-avoid-presentation :as kb-presentation] - [status-im.ui.components.react :as react] - [status-im.ui.components.toolbar :as toolbar] - [status-im.ui.screens.status.new.styles :as styles] - [status-im.ui.screens.status.views :as status.views] - [status-im.utils.platform :as platform])) - -(defn buttons - [] - [react/view styles/buttons - [pressable/pressable - {:type :scale - :accessibility-label :take-picture - :on-press #(re-frame/dispatch [:chat.ui/show-image-picker-camera-timeline])} - [icons/icon :main-icons/camera]] - [react/view {:style {:padding-top 8}} - [pressable/pressable - {:on-press #(re-frame/dispatch [:chat.ui/open-image-picker-timeline]) - :accessibility-label :open-gallery - :type :scale} - [icons/icon :main-icons/gallery]]]]) - -(defn image-preview - [uri] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/camera-roll-pick-timeline uri])} - [react/image - {:style styles/image - :source {:uri uri}}]]) - -(defview photos - [] - (letsubs [camera-roll-photos [:camera-roll/photos]] - {:component-did-mount #(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20])} - [react/scroll-view - {:horizontal true - :style {:max-height 88} - :keyboard-should-persist-taps :handled} - [react/view (styles/photos-buttons) - [buttons] - (for [img camera-roll-photos] - ^{:key (str "image" img)} - [image-preview img])]])) - -(def message-max-length 600) - -(defn my-status - [] - (let [images-opened (reagent/atom false) - scroll (reagent/atom nil) - autoscroll? (reagent/atom false) - scroll-height (reagent/atom nil) - input-text (re-frame/subscribe [:chats/timeline-chat-input-text]) - sending-image (re-frame/subscribe [:chats/timeline-sending-image])] - (fn [] - (let [{:keys [uri]} (first (vals @sending-image)) - text-length (count @input-text)] - [kb-presentation/keyboard-avoiding-view {:style {:flex 1}} - [:<> - [react/scroll-view - {:style {:flex 1} - :ref #(reset! scroll %) - :on-layout #(reset! scroll-height - (.-nativeEvent.layout.height ^js %)) - :keyboard-should-persist-taps :handled} - [react/text-input - {:style {:margin 16} - :scroll-enabled false - :accessibility-label :my-status-input - :max-length (if platform/android? - message-max-length - (when (>= text-length message-max-length) - text-length)) - :auto-focus true - :multiline true - :on-selection-change (fn [args] - (let [selection (.-selection ^js (.-nativeEvent ^js args)) - end (.-end ^js selection)] - (reset! autoscroll? (< (- (count @input-text) end) 10)))) - :on-content-size-change #(when (and @autoscroll? @scroll @scroll-height) - (when-let [height (- (.-nativeEvent.contentSize.height ^js %) - @scroll-height - -40)] - (.scrollTo @scroll #js {:y height :animated true}))) - :on-change-text #(re-frame/dispatch [:chat.ui/set-timeline-input-text %]) - :default-value @input-text - :placeholder (i18n/label :t/whats-on-your-mind)}] - (when uri - [react/view {:margin-horizontal 16 :margin-bottom 16} - [status.views/message-content-image uri true]])] - [react/view - (when @images-opened - [photos]) - [react/view - [toolbar/toolbar - {:show-border? true - :left - [quo/button - {:accessibility-label :open-images-panel-button - :type :secondary - :on-press #(swap! images-opened not)} - [icons/icon :main-icons/photo {:color (if @images-opened colors/blue colors/gray)}]] - :right - [quo/button - {:accessibility-label :send-my-status-button - :type :secondary - :after :main-icon/send - :disabled (or (> text-length message-max-length) - (and (string/blank? @input-text) (not uri))) - :on-press #(do - (re-frame/dispatch [:profile.ui/send-my-status-message]) - (re-frame/dispatch [:navigate-back]))} - (i18n/label :t/wallet-send)]}] - [react/view styles/count-container - [react/text - {:style {:color (if (> text-length message-max-length) - colors/red - colors/gray)}} - (str text-length " / " message-max-length)]]]]]])))) diff --git a/src/status_im/ui/screens/status/styles.cljs b/src/status_im/ui/screens/status/styles.cljs deleted file mode 100644 index 1b02481a76..0000000000 --- a/src/status_im/ui/screens/status/styles.cljs +++ /dev/null @@ -1,13 +0,0 @@ -(ns status-im.ui.screens.status.styles - (:require [quo.design-system.colors :as colors])) - -(defn descr-container - [] - {:border-width 1 - :border-color colors/gray-lighter - :border-top-right-radius 16 - :border-bottom-left-radius 16 - :border-top-left-radius 16 - :border-bottom-right-radius 4 - :padding-horizontal 12 - :padding-vertical 6}) \ No newline at end of file diff --git a/src/status_im/ui/screens/status/views.cljs b/src/status_im/ui/screens/status/views.cljs index 87939b9268..e69de29bb2 100644 --- a/src/status_im/ui/screens/status/views.cljs +++ b/src/status_im/ui/screens/status/views.cljs @@ -1,244 +0,0 @@ -(ns status-im.ui.screens.status.views - (:require [quo.design-system.colors :as colors] - [re-frame.core :as re-frame] - [reagent.core :as reagent] - [status-im.chat.models :as chat] - [status-im.constants :as constants] - [i18n.i18n :as i18n] - [status-im.ui.components.fast-image :as fast-image] - [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.list.views :as list] - [status-im.ui.components.plus-button :as components.plus-button] - [status-im.ui.components.react :as react] - [status-im.ui.components.tabs :as tabs] - [status-im.ui.screens.chat.components.reply :as components.reply] - [status-im.ui.screens.chat.image.preview.views :as preview] - [status-im.ui.screens.chat.message.gap :as gap] - [status-im.ui.screens.chat.message.link-preview :as link-preview] - [status-im.ui.screens.chat.message.message :as message] - [status-im.ui.screens.chat.message.reactions-old :as reactions] - [status-im.ui.screens.chat.photos :as photos] - [status-im.ui.screens.status.styles :as styles] - [utils.datetime :as datetime])) - -(defonce messages-list-ref (atom nil)) -(def image-max-dimension 192) - -(defn image-set-size - [width] - (fn [^js evt] - (reset! width (/ (.-width (.-nativeEvent evt)) - (/ (.-height (.-nativeEvent evt)) image-max-dimension))))) - -(defn message-content-image - [_ _] - (let [width (reagent/atom nil)] - (fn [uri show-close?] - [react/view - {:style {:width @width - :align-items :center - :height image-max-dimension - :max-width :100% - :overflow :hidden - :opacity (if @width 1 0) - :border-radius 16 - :margin-top 8} - :accessibility-label :image-message} - [fast-image/fast-image - {:style {:width @width - :height image-max-dimension} - :on-load (image-set-size width) - :source {:uri uri}}] - [react/view - {:border-width 1 - :top 0 - :left 0 - :width @width - :height image-max-dimension - :border-radius 16 - :position :absolute - :background-color :transparent - :border-color colors/black-transparent}] - (when show-close? - [react/touchable-highlight - {:on-press #(re-frame/dispatch [:chat.ui/cancel-sending-image-timeline]) - :accessibility-label :cancel-send-image - :style {:right 4 :top 12 :position :absolute}} - [react/view - {:width 24 - :height 24 - :background-color colors/black-persist - :border-radius 12 - :align-items :center - :justify-content :center} - [icons/icon :main-icons/close-circle {:color colors/white-persist}]]])]))) - -(defn on-long-press-fn - [on-long-press content image] - (on-long-press - (when-not image - [{:id :copy - :on-press #(react/copy-to-clipboard - (components.reply/get-quoted-text-with-mentions - (get content :parsed-text))) - :label (i18n/label :t/sharing-copy-to-clipboard)}]))) - -(defn image-message - [] - (let [visible (reagent/atom false)] - (fn [{:keys [content] :as message} on-long-press] - [:<> - [preview/preview-image - {:message (assoc message :cant-be-replied true) - :visible @visible - :can-reply false - :on-close #(do (reset! visible false) - (reagent/flush))}] - [react/touchable-highlight - {:on-press (fn [_] - (reset! visible true) - (react/dismiss-keyboard!)) - :on-long-press #(on-long-press-fn on-long-press content true)} - [message-content-image (:image content) false]]]))) - -(defn message-item - [account profile] - (fn [{:keys [content-type content from timestamp outgoing] :as message} - {:keys [modal on-long-press close-modal]}] - - [react/view - (merge {:padding-vertical 8 - :flex-direction :row - :background-color (when modal colors/white) - :padding-horizontal 16} - (when modal - {:border-radius 16})) - [react/touchable-highlight - {:on-press #(do (when modal (close-modal)) - (when profile (re-frame/dispatch [:navigate-back])) - (re-frame/dispatch [:chat.ui/show-profile from]))} - [react/view {:padding-top 2 :padding-right 8} - (if outgoing - [photos/account-photo account] - [photos/member-photo from])]] - [react/view {:flex 1} - [react/view - {:flex-direction :row - :justify-content :space-between - :width :98% - :word-break :break-all} - [react/touchable-highlight - {:on-press #(do (when modal (close-modal)) - (when profile (re-frame/dispatch [:navigate-back])) - (re-frame/dispatch [:chat.ui/show-profile from]))} - (let [message-author-width (* @(re-frame/subscribe [:dimensions/window-width]) 0.75)] - (if outgoing - [react/view {:style {:width message-author-width}} - [message/message-my-name {:profile? true :you? false}]] - [react/view {:style {:width message-author-width}} - [message/message-author-name from {:profile? true}]]))] - [react/text {:style {:font-size 10 :color colors/gray :margin-left :auto}} - (datetime/time-ago (datetime/to-date timestamp))]] - [react/view - (if (= content-type constants/content-type-image) - [image-message message on-long-press] - [react/touchable-highlight - (when-not modal - {:on-long-press #(on-long-press-fn on-long-press content false)}) - [message/render-parsed-text (assoc message :outgoing false) (:parsed-text content)]]) - [link-preview/link-preview-wrapper (:links content) outgoing true]]]])) - -(defn render-message - [{:keys [type] :as message} idx _ {:keys [timeline account chat-id profile]}] - (if (= type :datemark) - nil - (if (= type :gap) - (if timeline - nil - [gap/gap message idx messages-list-ref true chat-id]) - ;; for timeline for reactions we need to use :from as chat-id - (let [chat-id (chat/profile-chat-topic (:from message))] - [react/view - (merge {:accessibility-label :chat-item} - (when (:last-in-group? message) - {:padding-bottom 8 - :margin-bottom 8 - :border-bottom-width 1 - :border-bottom-color colors/gray-lighter})) - [reactions/with-reaction-picker - {:message message - :timeline true - :reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message) - constants/timeline-chat-id]) - :picker-on-open (fn []) - :picker-on-close (fn []) - :send-emoji (fn [{:keys [emoji-id]}] - (re-frame/dispatch [:models.reactions/send-emoji-reaction - {:message-id (:message-id message) - :chat-id chat-id - :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) - :chat-id chat-id - :emoji-id emoji-id - :emoji-reaction-id emoji-reaction-id}])) - :render (message-item account profile)}]])))) - -(def state (reagent/atom {:tab :timeline})) - -(defn tabs - [] - (let [{:keys [tab]} @state] - [react/view - {:flex-direction :row - :padding-horizontal 4 - :margin-top 8} - [tabs/tab-title state :timeline (i18n/label :t/timeline) (= tab :timeline)] - [tabs/tab-title state :status (i18n/label :t/my-status) (= tab :status)]])) - -(defn timeline - [] - (let [messages @(re-frame/subscribe [:chats/timeline-messages-stream]) - loading-messages? @(re-frame/subscribe [:chats/loading-messages? constants/timeline-chat-id]) - no-messages? @(re-frame/subscribe [:chats/chat-no-messages? constants/timeline-chat-id]) - account @(re-frame/subscribe [:multiaccount])] - [react/view {:flex 1} - [react/view - {:height 1 - :background-color colors/gray-lighter}] - (if (and no-messages? loading-messages?) - [react/view {:flex 1 :align-items :center :justify-content :center} - [react/activity-indicator {:animating true}]] - (if no-messages? - [react/view - {:padding-horizontal 32 - :margin-top 64} - [fast-image/fast-image - {:style {:width 140 - :height 140 - :align-self :center} - :source - {:uri - "https://bafybeieayj76s4vjlw5uwdvnakosy46rqyioqsp2ygl6sedivemhkxrbwi.ipfs.cf-ipfs.com"}}] - [react/view (styles/descr-container) - [react/text - {:style {:color colors/gray - :line-height 22}} - (if (= :timeline (:tab @state)) - (i18n/label :t/statuses-descr) - (i18n/label :t/statuses-my-status-descr))]]] - [list/flat-list - {:key-fn #(or (:message-id %) (:value %)) - :render-data {:timeline (= :timeline (:tab @state)) - :account account} - :render-fn render-message - :data messages - :on-end-reached #(re-frame/dispatch [:chat.ui/load-more-messages - constants/timeline-chat-id]) - ;;don't remove :on-scroll-to-index-failed - :on-scroll-to-index-failed #() - :header [react/view {:height 8}] - :footer [react/view {:height 68}]}])) - [components.plus-button/plus-button-old - {:on-press #(re-frame/dispatch [:open-modal :my-status])}]])) diff --git a/src/status_im/ui2/screens/chat/composer/input.cljs b/src/status_im/ui2/screens/chat/composer/input.cljs index 1d139a3816..309b08f27b 100644 --- a/src/status_im/ui2/screens/chat/composer/input.cljs +++ b/src/status_im/ui2/screens/chat/composer/input.cljs @@ -8,7 +8,7 @@ [quo2.foundations.colors :as colors] [re-frame.core :as re-frame] [reagent.core :as reagent] - [status-im.chat.constants :as chat.constants] + [status-im2.common.constants :as chat.constants] [status-im.chat.models.mentions :as mentions] [i18n.i18n :as i18n] [status-im.ui.components.react :as react] diff --git a/src/status_im/ui2/screens/chat/messages/message.cljs b/src/status_im/ui2/screens/chat/messages/message.cljs index 371b494f86..6f7a581e45 100644 --- a/src/status_im/ui2/screens/chat/messages/message.cljs +++ b/src/status_im/ui2/screens/chat/messages/message.cljs @@ -2,7 +2,6 @@ (:require [quo.design-system.colors :as quo.colors] [quo.react-native :as rn] - [quo2.components.avatars.user-avatar :as user-avatar] [quo2.components.icon :as icons] [quo2.components.markdown.text :as text] [quo2.foundations.colors :as colors] @@ -16,9 +15,7 @@ [status-im.ui.components.react :as react] [status-im.ui.screens.chat.image.preview.views :as preview] [status-im.ui.screens.chat.message.audio :as message.audio] - [status-im.ui.screens.chat.message.command :as message.command] [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.sheets :as sheets] [status-im.ui.screens.chat.styles.message.message :as style] [status-im.ui.screens.chat.utils :as chat.utils] @@ -34,8 +31,6 @@ [quo2.core :as quo]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) -(def edited-at-text (str " ⌫ " (i18n/label :t/edited))) - (defn system-text? [content-type] (= content-type constants/content-type-system-text)) @@ -208,46 +203,6 @@ (assoc props :accessibility-label :message-timestamp) (datetime/to-short-str timestamp)]]))]) -(defn message-content-wrapper - "Author, userpic and delivery wrapper" - [{:keys [last-in-group? timestamp pinned from chat-id] - :as message} content] - (let [response-to (:response-to (:content message)) - 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])] - [rn/view - {:style (style/message-wrapper message) - :pointer-events :box-none - :accessibility-label :chat-item} - (when (and (seq response-to) (:quoted-message message)) - [quoted-message {:message-id response-to :chat-id chat-id} (:quoted-message message)]) - [rn/view - {:style (style/message-body) - :pointer-events :box-none} - ;; AVATAR - [rn/view {:style {:width 40}} - (when (or (and (seq response-to) (:quoted-message message)) last-in-group? pinned) - [react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/show-profile from])} - [user-avatar/user-avatar - {:full-name display-name - :profile-picture photo-path - :status-indicator? true - :online? online? - :size :small - :ring? false}]])] - [rn/view {:style (style/message-author-wrapper)} - ;; AUTHOR NAME - (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-height 192) @@ -265,10 +220,6 @@ (defmulti ->message :content-type) -(defmethod ->message constants/content-type-command - [message] - [message.command/command-content message-content-wrapper message]) - (defmethod ->message constants/content-type-gap [message] [message.gap/gap message]) diff --git a/src/status_im2/common/constants.cljs b/src/status_im2/common/constants.cljs index 249b514814..2b7bbf2f0d 100644 --- a/src/status_im2/common/constants.cljs +++ b/src/status_im2/common/constants.cljs @@ -223,3 +223,16 @@ 3 72.5 4 72.5 5 72.5}}) + +(def ^:const spam-message-frequency-threshold 4) +(def ^:const spam-interval-ms 1000) +(def ^:const default-cooldown-period-ms 10000) +(def ^:const cooldown-reset-threshold 3) +(def ^:const cooldown-periods-ms + {1 2000 + 2 5000 + 3 10000}) + +(def ^:const max-text-size 4096) +;; any message that comes after this amount of ms will be grouped separately +(def ^:const group-ms 300000) diff --git a/src/status_im2/contexts/chat/messages/delete_message/events.cljs b/src/status_im2/contexts/chat/messages/delete_message/events.cljs index af735b0e18..b96b4e99fb 100644 --- a/src/status_im2/contexts/chat/messages/delete_message/events.cljs +++ b/src/status_im2/contexts/chat/messages/delete_message/events.cljs @@ -2,7 +2,7 @@ (:require [i18n.i18n :as i18n] [quo2.foundations.colors :as colors] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [taoensso.timbre :as log] [utils.datetime :as datetime] [utils.re-frame :as rf])) diff --git a/src/status_im2/contexts/chat/messages/delete_message_for_me/events.cljs b/src/status_im2/contexts/chat/messages/delete_message_for_me/events.cljs index 754a9d6400..b48ba1ecd3 100644 --- a/src/status_im2/contexts/chat/messages/delete_message_for_me/events.cljs +++ b/src/status_im2/contexts/chat/messages/delete_message_for_me/events.cljs @@ -2,7 +2,7 @@ (:require [i18n.i18n :as i18n] [quo2.foundations.colors :as colors] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [taoensso.timbre :as log] [utils.datetime :as datetime] [utils.re-frame :as rf])) diff --git a/src/status_im/chat/models/message_list.cljs b/src/status_im2/contexts/chat/messages/list/events.cljs similarity index 75% rename from src/status_im/chat/models/message_list.cljs rename to src/status_im2/contexts/chat/messages/list/events.cljs index a5a80cbf36..30880867c8 100644 --- a/src/status_im/chat/models/message_list.cljs +++ b/src/status_im2/contexts/chat/messages/list/events.cljs @@ -1,12 +1,12 @@ -(ns status-im.chat.models.message-list - (:require ["functional-red-black-tree" :as rb-tree] - [status-im.constants :as constants] +(ns status-im2.contexts.chat.messages.list.events + (:require [utils.red-black-tree :as red-black-tree] [utils.datetime :as datetime] - [utils.re-frame :as rf])) + [utils.re-frame :as rf] + [status-im2.common.constants :as constants])) (defn- add-datemark [{:keys [whisper-timestamp] :as msg}] - ;;TODO this is slow + ;;NOTE(performance) this is slow (assoc msg :datemark (datetime/day-relative whisper-timestamp))) (defn- add-timestamp @@ -40,9 +40,6 @@ add-datemark add-timestamp)) -;; any message that comes after this amount of ms will be grouped separately -(def ^:private group-ms 300000) - (defn same-group? "Whether a message is in the same group as the one after it. We check the time, and the author" @@ -51,7 +48,7 @@ (not (:system-message? a)) (not (:system-message? b)) (= (:from a) (:from b)) - (<= (js/Math.abs (- (:whisper-timestamp a) (:whisper-timestamp b))) group-ms))) + (<= (js/Math.abs (- (:whisper-timestamp a) (:whisper-timestamp b))) constants/group-ms))) (defn display-photo? "We display photos for other users, and not in 1-to-1 chats" @@ -126,50 +123,31 @@ (not one-to-one?)) :last-in-group? last-in-group?))) -(defn get-prev-element - "Get previous item in the iterator, and wind it back to the initial state" - [^js iter] - (.prev iter) - (let [e (.-value iter)] - (.next iter) - e)) - -(defn get-next-element - "Get next item in the iterator, and wind it back to the initial state" - [^js iter] - (.next iter) - (let [e (.-value iter)] - (.prev iter) - e)) - (defn update-message "Update the message and siblings with positional info" - [^js tree message] - (let [^js iter (.find tree message) - ^js previous-message (when (.-hasPrev iter) - (get-prev-element iter)) - ^js next-message (when (.-hasNext iter) - (get-next-element iter)) - ^js message-with-pos-data (add-group-info message previous-message next-message)] - (cond-> (.update iter message-with-pos-data) + [tree message] + (let [iter (red-black-tree/find tree message) + previous-message (red-black-tree/get-prev iter) + next-message (red-black-tree/get-next iter) + message-with-pos-data (add-group-info message previous-message next-message)] + (cond-> (red-black-tree/update iter message-with-pos-data) next-message - (-> ^js (.find next-message) - (.update (update-next-message message-with-pos-data next-message))) + (-> (red-black-tree/find next-message) + (red-black-tree/update (update-next-message message-with-pos-data next-message))) (and previous-message (not= :datemark (:type previous-message))) - (-> ^js (.find previous-message) - (.update (update-previous-message message-with-pos-data previous-message)))))) + (-> (red-black-tree/find previous-message) + (red-black-tree/update (update-previous-message message-with-pos-data previous-message)))))) (defn remove-message "Remove a message in the list" - [^js tree prepared-message] - (let [iter (.find tree prepared-message)] + [tree prepared-message] + (let [iter (red-black-tree/find tree prepared-message)] (if (not iter) tree - (let [^js new-tree (.remove iter) - ^js next-message (when (.-hasNext iter) - (get-next-element iter))] + (let [new-tree (red-black-tree/remove iter) + next-message (red-black-tree/get-next iter)] (if (not next-message) new-tree (update-message new-tree next-message)))))) @@ -179,13 +157,13 @@ its positional metadata, and update the left & right messages if necessary, this operation is O(logN) for insertion, and O(logN) for the updates, as we need to re-find (there's probably a better way)" - [^js old-message-list prepared-message] - (let [^js tree (.insert old-message-list prepared-message prepared-message)] + [old-message-list prepared-message] + (let [tree (red-black-tree/insert old-message-list prepared-message)] (update-message tree prepared-message))) (defn add [message-list message] - (insert-message (or message-list (rb-tree compare-fn)) (prepare-message message))) + (insert-message (or message-list (red-black-tree/tree compare-fn)) (prepare-message message))) (defn add-many [message-list messages] @@ -194,9 +172,9 @@ messages)) (defn ->seq - [^js message-list] + [message-list] (if message-list - (array-seq (.-values message-list)) + (array-seq (red-black-tree/get-values message-list)) [])) ;; NOTE(performance): this is too expensive, probably we could mark message somehow and just hide it in diff --git a/src/status_im/chat/models/message_list_test.cljs b/src/status_im2/contexts/chat/messages/list/events_test.cljs similarity index 98% rename from src/status_im/chat/models/message_list_test.cljs rename to src/status_im2/contexts/chat/messages/list/events_test.cljs index 5862687e3d..a3e9483ff0 100644 --- a/src/status_im/chat/models/message_list_test.cljs +++ b/src/status_im2/contexts/chat/messages/list/events_test.cljs @@ -1,6 +1,6 @@ -(ns status-im.chat.models.message-list-test +(ns status-im2.contexts.chat.messages.list.events-test (:require [cljs.test :refer-macros [deftest is testing]] - [status-im.chat.models.message-list :as s] + [status-im2.contexts.chat.messages.list.events :as s] [taoensso.tufte :as tufte :refer-macros [defnp profile]])) (deftest message-stream-tests diff --git a/src/status_im/ui/screens/chat/state.cljs b/src/status_im2/contexts/chat/messages/list/state.cljs similarity index 83% rename from src/status_im/ui/screens/chat/state.cljs rename to src/status_im2/contexts/chat/messages/list/state.cljs index f83cde1e0a..6e19c93547 100644 --- a/src/status_im/ui/screens/chat/state.cljs +++ b/src/status_im2/contexts/chat/messages/list/state.cljs @@ -1,4 +1,4 @@ -(ns status-im.ui.screens.chat.state) +(ns status-im2.contexts.chat.messages.list.state) (defonce first-not-visible-item (atom nil)) diff --git a/src/status_im2/contexts/chat/messages/list/view.cljs b/src/status_im2/contexts/chat/messages/list/view.cljs index 4714da37c0..b886806226 100644 --- a/src/status_im2/contexts/chat/messages/list/view.cljs +++ b/src/status_im2/contexts/chat/messages/list/view.cljs @@ -1,20 +1,19 @@ (ns status-im2.contexts.chat.messages.list.view (:require [i18n.i18n :as i18n] [oops.core :as oops] - [quo.react-native :as quo.react] [quo2.core :as quo] [react-native.background-timer :as background-timer] [react-native.core :as rn] [react-native.platform :as platform] [reagent.core :as reagent] - [status-im.ui.screens.chat.group :as chat.group] - [status-im.ui.screens.chat.state :as state] + [utils.re-frame :as rf] [status-im2.contexts.chat.messages.content.view :as message] [status-im2.common.constants :as constants] - [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])) + [status-im2.common.not-implemented :as not-implemented] + [status-im.ui.screens.chat.group :as chat.group] + [status-im2.contexts.chat.messages.list.state :as state] + [status-im.ui.screens.chat.message.gap :as message.gap])) (defonce messages-list-ref (atom nil)) @@ -37,7 +36,7 @@ threshold-percentage-to-show-floating-scroll-down-button) reached-threshold? (> y threshold-height)] (when (not= reached-threshold? @show-floating-scroll-down-button) - (quo.react/configure-next (:ease-in-ease-out quo.react/layout-animation-presets)) + (rn/configure-next (:ease-in-ease-out rn/layout-animation-presets)) (reset! show-floating-scroll-down-button reached-threshold?)))) (defn on-viewable-items-changed diff --git a/src/status_im2/contexts/chat/messages/pin/events.cljs b/src/status_im2/contexts/chat/messages/pin/events.cljs index 0865d3284c..08663b9d0e 100644 --- a/src/status_im2/contexts/chat/messages/pin/events.cljs +++ b/src/status_im2/contexts/chat/messages/pin/events.cljs @@ -1,6 +1,6 @@ (ns status-im2.contexts.chat.messages.pin.events (:require [re-frame.core :as re-frame] - [status-im.chat.models.message-list :as message-list] + [status-im2.contexts.chat.messages.list.events :as message-list] [status-im.constants :as constants] [status-im.data-store.pin-messages :as data-store.pin-messages] [status-im.transport.message.protocol :as protocol] diff --git a/src/status_im2/subs/chat/messages.cljs b/src/status_im2/subs/chat/messages.cljs index d076332984..e2b29b06e0 100644 --- a/src/status_im2/subs/chat/messages.cljs +++ b/src/status_im2/subs/chat/messages.cljs @@ -1,7 +1,7 @@ (ns status-im2.subs.chat.messages (:require [re-frame.core :as re-frame] [status-im.chat.db :as chat.db] - [status-im.chat.models.message-list :as models.message-list] + [status-im2.contexts.chat.messages.list.events :as models.message-list] [status-im.chat.models.reactions :as models.reactions] [utils.datetime :as datetime] [status-im2.common.constants :as constants])) diff --git a/src/utils/red_black_tree.cljs b/src/utils/red_black_tree.cljs new file mode 100644 index 0000000000..4958c7f827 --- /dev/null +++ b/src/utils/red_black_tree.cljs @@ -0,0 +1,51 @@ +(ns utils.red-black-tree + (:refer-clojure :exclude [remove update find]) + (:require ["functional-red-black-tree" :as red-black-tree])) + +(def tree ^js red-black-tree) + +(defn find + [^js tree item] + (.find tree item)) + +(defn insert + [^js tree item] + (.insert tree item)) + +(defn update + [^js iter item] + (.update iter item)) + +(defn remove + [^js iter] + (.remove iter)) + +(defn get-values + [^js tree] + (.-values ^js tree)) + +(defn get-prev-element + "Get previous item in the iterator, and wind it back to the initial state" + [^js iter] + (.prev iter) + (let [e (.-value iter)] + (.next iter) + e)) + +(defn get-prev + [^js iter] + (when (.-hasPrev iter) + (get-prev-element iter))) + +(defn get-next-element + "Get next item in the iterator, and wind it back to the initial state" + [^js iter] + (.next iter) + (let [e (.-value iter)] + (.prev iter) + e)) + +(defn get-next + [^js iter] + (when (.-hasNext iter) + (get-next-element iter)))