Base chat dedesign

Signed-off-by: Brian Sztamfater <brian@status.im>
This commit is contained in:
Brian Sztamfater 2022-07-07 13:07:37 -03:00
parent 236bbff493
commit 22f92677fa
No known key found for this signature in database
GPG Key ID: 59EB921E0706B48F
60 changed files with 2414 additions and 391 deletions

View File

@ -2,7 +2,7 @@ PODS:
- boost-for-react-native (1.63.0)
- BVLinearGradient (2.5.6):
- React
- CryptoSwift (1.4.3)
- CryptoSwift (1.5.1)
- DoubleConversion (1.1.6)
- FBLazyVector (0.63.4)
- FBReactNativeSpec (0.63.4):
@ -349,7 +349,7 @@ PODS:
- React
- RNReactNativeHapticFeedback (1.9.0):
- React
- RNReanimated (2.1.0):
- RNReanimated (2.3.3):
- DoubleConversion
- FBLazyVector
- FBReactNativeSpec
@ -375,7 +375,6 @@ PODS:
- React-RCTNetwork
- React-RCTSettings
- React-RCTText
- React-RCTVibration
- ReactCommon/turbomodule/core
- Yoga
- RNShare (7.0.1):
@ -468,7 +467,7 @@ DEPENDENCIES:
- RNSVG (from `../node_modules/react-native-svg`)
- secp256k1 (from `https://github.com/status-im/secp256k1.swift.git`)
- SQLCipher (~> 3.0)
- SSZipArchive
- SSZipArchive (= 2.4.3)
- TouchID (from `../node_modules/react-native-touch-id`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
@ -631,14 +630,14 @@ CHECKOUT OPTIONS:
SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CryptoSwift: a0799ee936271bd2253a006f1e4523df21845000
CryptoSwift: c4f2debceb38bf44c80659afe009f71e23e4a082
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 2d7c14bbcd0c3139c6258f813895cb61d7860fcc
glog: 502275bc0747df92346edbab1f40dacde2ec86d4
HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352
Keycard: 07f1b4d4fadcf1218084cb3e1bb3a8bac3870c5a
Keycard: ac6df4d91525c3c82635ac24d4ddd9a80aca5fc8
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
Permission-Camera: afad27bf90337684d4a86f3825112d648c8c4d3b
Permission-Microphone: 0ffabc3fe1c75cfb260525ee3f529383c9f4368c
@ -666,7 +665,7 @@ SPEC CHECKSUMS:
react-native-shake: de052eaa3eadc4a326b8ddd7ac80c06e8d84528c
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
react-native-status: 45dbf1302ce3c258b459dfab137cd1c2c68c295d
react-native-status: 21f75d492fd311dc111303da38a7a2b23a8a8466
react-native-status-keycard: 961d01ca190889ddf220206822fd752f8f4f3f7a
react-native-webview: 28a8636d97ee641f2ee8f20492d7a6c269c1d703
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
@ -693,7 +692,7 @@ SPEC CHECKSUMS:
RNLanguages: 962e562af0d34ab1958d89bcfdb64fafc37c513e
RNPermissions: ad71dd4f767ec254f2cd57592fbee02afee75467
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
RNReanimated: 70f662b5232dd5d19ccff581e919a54ea73df51c
RNReanimated: 69eda0e8790a2ee00de2fff03e89361e9bac749a
RNShare: 2dc2fcac3f7321cfd6b60a23ed4bf4d549f86f5f
RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
@ -705,6 +704,6 @@ SPEC CHECKSUMS:
TouchID: ba4c656d849cceabc2e4eef722dea5e55959ecf4
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
PODFILE CHECKSUM: 1a5b8878f89edd08eb4d37898a3a8721a7bb3388
PODFILE CHECKSUM: a1de9468266e7f0b5273acea713782ab759690f1
COCOAPODS: 1.11.0
COCOAPODS: 1.11.3

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -193,5 +193,19 @@
(def switcher-background-opa-90 (alpha switcher-background 0.9))
(def switcher-background-opa-95 (alpha switcher-background 0.95))
;;General
;; background
(def ui-background-02-light "#F5F9FA")
;; divider
(def divider-light "#EDF2f4")
(def divider-dark "#0E1620")
;; Visibility status
(def color-online "#26A69A")
(defn theme-colors [light dark]
(if (theme/dark?) dark light))

View File

@ -29,4 +29,4 @@
(def font-bold {:font-family "Inter-Bold"}) ; 700
(def monospace {:font-family "InterStatus-Regular"})
(def monospace {:font-family "InterStatus-Regular"})

View File

@ -63,6 +63,25 @@
[react/view {:style dot-styles
:accessibility-label dot-accessibility-label}])]))
(defn profile-photo-plus-dot-view-old
[{:keys [public-key photo-container photo-path community?]}]
(let [photo-path (if (nil? photo-path)
@(re-frame.core/subscribe [:chats/photo-path public-key])
photo-path)
photo-container (if (nil? photo-container)
styles/container-chat-list photo-container)
size (:width photo-container)
identicon? (when photo-path (profile.db/base64-png? photo-path))
dot-styles (visibility-status-utils/icon-visibility-status-dot-old
public-key size identicon?)
dot-accessibility-label (:accessibility-label dot-styles)]
[react/view {:style photo-container
:accessibility-label :profile-photo}
[photos/photo photo-path {:size size}]
(when-not community?
[react/view {:style dot-styles
:accessibility-label dot-accessibility-label}])]))
(defn emoji-chat-icon-view
[chat-id group-chat name emoji styles]
[react/view (:container styles)
@ -73,6 +92,16 @@
[profile-photo-plus-dot-view {:public-key chat-id
:photo-container (:default-chat-icon styles)}])])
(defn emoji-chat-icon-view-old
[chat-id group-chat name emoji styles]
[react/view (:container styles)
(if group-chat
(if (string/blank? emoji)
[default-chat-icon name styles]
[emoji-chat-icon emoji styles])
[profile-photo-plus-dot-view-old {:public-key chat-id
:photo-container (:default-chat-icon styles)}])])
(defn chat-icon-view-toolbar
[chat-id group-chat name color emoji]
[emoji-chat-icon-view chat-id group-chat name emoji
@ -163,10 +192,10 @@
(styles/emoji-chat-icon-text size))} override-styles)]
[react/view (:container styles)
(if (and photo-path (seq photo-path))
[profile-photo-plus-dot-view {:photo-path photo-path
:public-key public-key
:photo-container (:container styles)
:community? community?}]
[profile-photo-plus-dot-view-old {:photo-path photo-path
:public-key public-key
:photo-container (:container styles)
:community? community?}]
(if (string/blank? emoji)
[default-chat-icon name styles]
[emoji-chat-icon emoji styles]))

View File

@ -2,9 +2,24 @@
(:require [quo.design-system.colors :as colors]
[quo.core :as quo]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.icons :as icons]))
[status-im.ui.components.icons.icons :as icons]
[quo2.components.button :as quo2.button]))
(def action-button-container
{:align-items :center
:justify-content :center
:height 32
:border-radius 16
:overflow :hidden})
(defn action-button []
{:width 32
:height 32
:border-radius 18
:align-items :center
:justify-content :center})
(def action-button-container-old
{:position :absolute
:z-index 2
:align-items :center
@ -14,7 +29,7 @@
:bottom 16
:height 40})
(defn action-button []
(defn action-button-old []
{:width 40
:height 40
:background-color colors/blue
@ -31,10 +46,23 @@
(defn plus-button [{:keys [on-press loading accessibility-label]}]
[react/view action-button-container
[quo/button {:type :scale
:accessibility-label (or accessibility-label :plus-button)
:on-press on-press}
[quo2.button/button {:type :primary
:size 32
:width 32
:accessibility-label (or accessibility-label :plus-button)
:on-press on-press}
[react/view (action-button)
(if loading
[react/activity-indicator {:color colors/white-persist
:animating true}]
[icons/icon :main-icons/add {:color colors/white-persist}])]]])
(defn plus-button-old [{:keys [on-press loading accessibility-label]}]
[react/view action-button-container-old
[quo/button {:type :scale
:accessibility-label (or accessibility-label :plus-button)
:on-press on-press}
[react/view (action-button-old)
(if loading
[react/activity-indicator {:color colors/white-persist
:animating true}]

View File

@ -2,9 +2,53 @@
(:require [reagent.core :as reagent]
[status-im.i18n.i18n :as i18n]
[quo.core :as quo]
[quo.design-system.colors :as colors]))
[quo.design-system.colors :as colors]
[quo2.foundations.colors :as quo2.colors]))
(defn search-input [{:keys [search-active?]}]
(let [input-ref (atom nil)
search-active? (or search-active? (reagent/atom nil))]
(fn [{:keys [on-focus on-change on-blur on-cancel search-filter auto-focus]}]
[quo/text-input {:placeholder (i18n/label :t/search)
:accessibility-label :search-input
:blur-on-submit true
:multiline false
:get-ref #(reset! input-ref %)
:default-value search-filter
:auto-focus auto-focus
:on-cancel on-cancel
:show-cancel true
:auto-correct false
:auto-capitalize :none
:container-style {:border-radius 10
:border-width 1
:border-color (:ui-01 @colors/theme)
:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)
:overflow :hidden}
:input-style {:height 32
:padding-top 2
:padding-bottom 2
:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)}
:before {:icon :main-icons/search2
:style {:padding-horizontal 8
:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)}
:on-press #(some-> ^js @input-ref (.focus))
:icon-opts {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/white)}}
:on-focus #(do
(when on-focus
(on-focus search-filter))
(reset! search-active? true))
:on-blur #(do
(when on-blur
(on-blur))
(reset! search-active? false))
:on-change (fn [e]
(let [^js native-event (.-nativeEvent ^js e)
text (.-text native-event)]
(when on-change
(on-change text))))}])))
(defn search-input-old [{:keys [search-active?]}]
(let [input-ref (atom nil)
search-active? (or search-active? (reagent/atom nil))]
(fn [{:keys [on-focus on-change on-blur on-cancel search-filter auto-focus]}]
@ -38,4 +82,4 @@
(let [^js native-event (.-nativeEvent ^js e)
text (.-text native-event)]
(when on-change
(on-change text))))}])))
(on-change text))))}])))

View File

@ -1,6 +1,7 @@
(ns status-im.ui.components.topbar
(:require [re-frame.core :as re-frame]
[quo.core :as quo]))
[quo.core :as quo]
[quo2.foundations.colors :as quo2.colors]))
(def default-button-width 48)
@ -20,7 +21,9 @@
label
(assoc :label label)))
(defn topbar [{:keys [navigation use-insets right-accessories modal? content]
(defn topbar [{:keys [navigation use-insets right-accessories modal? content border-bottom? new-ui?] ;; remove new-ui? key, temp fix
:or {border-bottom? true
new-ui? false}
:as props}]
(let [navigation (if (= navigation :none)
nil
@ -31,7 +34,10 @@
:title-component content
:insets (when use-insets insets)
:left-width (when navigation
default-button-width)}
default-button-width)
:border-bottom border-bottom?}
props
(when (seq right-accessories)
{:right-accessories right-accessories}))])]))
{:right-accessories right-accessories})
(when new-ui?
{:background (quo2.colors/theme-colors quo2.colors/white quo2.colors/divider-dark)}))])]))

View File

@ -71,5 +71,5 @@
:key-fn :browser-id
:render-fn list-item}]
[components.plus-button/plus-button
[components.plus-button/plus-button-old
{:on-press #(re-frame/dispatch [:browser.ui/open-empty-tab])}]]))

View File

@ -171,16 +171,16 @@
(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)]
(defn- play-pause-button [state-ref on-press]
(let [color colors/blue]
(if (= (:general @state-ref) :preparing)
[react/view {:style (style/play-pause-container outgoing true)}
[react/view {:style (style/play-pause-container 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)
{:container-style (style/play-pause-container false)
:accessibility-label :play-pause-audio-message-button
:color color}]])))
@ -193,7 +193,7 @@
:message-id @current-player-message-id}))
nil)
(defview message-content [{:keys [audio audio-duration-ms message-id outgoing]}]
(defview message-content [{:keys [audio audio-duration-ms message-id]}]
(letsubs [state (reagent/atom nil)
progress (reagent/atom 0)
progress-anim (anim/create-value 0)
@ -218,9 +218,9 @@
: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)]
[play-pause-button state #(play-pause base-params audio)]
[react/view style/slider-container
[slider/animated-slider (merge (style/slider outgoing)
[slider/animated-slider (merge (style/slider)
{:minimum-value 0
:maximum-value (:duration @state)
:value progress-anim
@ -229,7 +229,7 @@
: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)}
[react/text {:style (style/timestamp)}
(let [time (cond
(or (:slider-seeking @state) (> (:seek-to-ms @state) 0)) (:seek-to-ms @state)
(#{:playing :paused :seeking} (:general @state)) @progress

View File

@ -0,0 +1,238 @@
(ns status-im.ui.screens.chat.message.audio-old
(:require-macros [status-im.utils.views :refer [defview letsubs]])
(:require [status-im.utils.utils :as utils]
[reagent.core :as reagent]
[goog.string :as gstring]
[status-im.audio.core :as audio]
[status-im.utils.fx :as fx]
[status-im.ui.screens.chat.styles.message.audio-old :as style]
[status-im.ui.components.animation :as anim]
[quo.design-system.colors :as colors]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[status-im.ui.components.slider :as slider]
["react-native-blob-util" :default ReactNativeBlobUtil]
[status-im.utils.platform :as platform]
[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}]])))
(fx/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)))]]]))))

View File

@ -1,12 +1,17 @@
(ns status-im.ui.screens.chat.message.datemark
(:require [status-im.ui.components.react :as react]
[clojure.string :as string]
[status-im.ui.screens.chat.styles.message.datemark :as style]))
[status-im.ui.screens.chat.styles.message.datemark :as style]
[quo2.components.text :as quo2.text]
[quo2.foundations.colors :as quo2.colors]))
(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)]]])
[quo2.text/text {:weight :medium
:accessibility-label :message-datemark-text
:style {:color quo2.colors/neutral-50}}
(string/capitalize value)]
[react/view (style/divider)]]])

View File

@ -0,0 +1,12 @@
(ns status-im.ui.screens.chat.message.datemark-old
(:require [status-im.ui.components.react :as react]
[clojure.string :as string]
[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)]]])

View File

@ -73,13 +73,13 @@
: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])]))
(when edited-at [react/text {:style (style/message-status-text)} edited-at-text])]))
(defn message-timestamp
[{:keys [timestamp-str in-popover?] :as message} show-timestamp?]
[{:keys [timestamp-str in-popover?]} 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}
[react/animated-view {:style (style/message-timestamp-wrapper) :opacity anim-opacity}
(when @show-timestamp? (message-timestamp-anim anim-opacity show-timestamp?))
[react/text
{:style (style/message-timestamp-text)
@ -87,16 +87,16 @@
timestamp-str]])))
(defview quoted-message
[_ {:keys [from parsed-text image]} outgoing current-public-key public? pinned]
[_ {:keys [from parsed-text image]} current-public-key public? pinned]
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
[react/view {:style (style/quoted-message-container (and outgoing (not pinned)))}
[react/view {:style (style/quoted-message-container)}
[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))]]
(partial style/quoted-message-author (not pinned))
false]]
(if (and image
;; Disabling images for public-chats
(not public?))
@ -105,11 +105,11 @@
:background-color :black
:border-radius 4}
:source {:uri image}}]
[react/text {:style (style/quoted-message-text (and outgoing (not pinned)))
[react/text {:style (style/quoted-message-text)
: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]}]
(defn render-inline [message-text content-type acc {:keys [type literal destination]}]
(case type
""
(conj acc literal)
@ -121,22 +121,22 @@
literal])
"emph"
(conj acc [react/text-class (style/emph-style (and outgoing (not pinned))) literal])
(conj acc [react/text-class (style/emph-style) literal])
"strong"
(conj acc [react/text-class (style/strong-style (and outgoing (not pinned))) literal])
(conj acc [react/text-class (style/strong-style) literal])
"strong-emph"
(conj acc [quo/text (style/strong-emph-style (and outgoing (not pinned))) literal])
(conj acc [quo/text (style/strong-emph-style) literal])
"del"
(conj acc [react/text-class (style/strikethrough-style (and outgoing (not pinned))) literal])
(conj acc [react/text-class (style/strikethrough-style) literal])
"link"
(conj acc
[react/text-class
{:style
{:color (if (and outgoing (not pinned)) colors/white-persist colors/blue)
{:color colors/blue
:text-decoration-line :underline}
:on-press
#(when (and (security/safe-link? destination)
@ -149,14 +149,13 @@
(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)
{:style {:color colors/blue
:text-decoration-line :underline}
:on-press
#(re-frame/dispatch
@ -166,19 +165,19 @@
(conj acc literal)))
(defn render-block [{:keys [content outgoing content-type pinned in-popover?]} acc
(defn render-block [{:keys [content content-type 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?)]
(fn [acc e] (render-inline (:text content) content-type acc e))
[react/text-class (style/text-style 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)))
(conj acc [react/view (style/blockquote-style)
[react/text-class (style/blockquote-text-style)
(.substring literal 0 (.-length literal))]])
"codeblock"
@ -193,10 +192,10 @@
(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]
(defn render-parsed-text-with-message-status [{:keys [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))]
(str (if (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
@ -208,10 +207,10 @@
(conj elements message-status))))
(defn unknown-content-type
[{:keys [outgoing content-type content] :as message}]
[{:keys [content-type content] :as message}]
[react/view (style/message-view message)
[react/text
{:style {:color (if outgoing colors/white-persist colors/black)}}
{:style {:color colors/white-persist}}
(if (seq (:text content))
(:text content)
(str "Unhandled content-type " content-type))]])
@ -242,8 +241,8 @@
(def pin-icon-height 15)
(defn pinned-by-indicator [outgoing display-photo? pinned-by]
[react/view {:style (style/pin-indicator outgoing display-photo?)
(defn pinned-by-indicator [display-photo? pinned-by]
[react/view {:style (style/pin-indicator display-photo?)
:accessibility-label :pinned-by}
[react/view {:style (style/pinned-by-text-icon-container)}
[react/view {:style (style/pin-icon-container)}
@ -309,33 +308,40 @@
(defn message-content-wrapper
"Author, userpic and delivery wrapper"
[{:keys [first-in-group? display-photo? display-username?
[{:keys [last-in-group?
identicon
from outgoing in-popover?]
from in-popover? timestamp-str]
: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)
[react/view {:style (style/message-body)
: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}]])
[react/view (style/message-author-userpic)
(when last-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)}
(when last-in-group?
[react/view {:style {:flex-direction :row :align-items :center}}
[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}]]
[react/text
{:style (merge
{:padding-left 5
:margin-top 2}
(style/message-timestamp-text))
:accessibility-label :message-timestamp}
timestamp-str]])
;;MESSAGE CONTENT
content
[link-preview/link-preview-wrapper (:links (:content message)) outgoing false]]]
[link-preview/link-preview-wrapper (:links (:content message)) false false]]]
; delivery status
[react/view (style/delivery-status outgoing)
[react/view (style/delivery-status)
[message-delivery-status message]]])
(def image-max-width 260)
@ -353,13 +359,13 @@
(swap! dimensions assoc :loaded true)))))
(defn message-content-image
[{:keys [content outgoing in-popover?] :as message}
[{:keys [content 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
(let [style-opts {:outgoing false
:opacity (if (:loaded @dimensions) 1 0)
:width (:width @dimensions)
:height (:height @dimensions)}]
@ -405,9 +411,6 @@
[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))
@ -443,62 +446,31 @@
:label (i18n/label :t/delete)
:id :delete}]))))
(defn collapsible-text-message [{:keys [mentioned]} _]
(defn collapsible-text-message [_ _]
(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?] :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])
[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}]]]))]]]]))))
(fn [{:keys [content current-public-key public? pinned in-popover?] :as message} on-long-press modal]
[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
[message-timestamp message show-timestamp?]
[react/view {:style (style/message-view message)}
[react/view {:style (style/message-view-content)}
(let [response-to (:response-to content)]
[react/view
(when (and (seq response-to) (:quoted-message message))
[quoted-message response-to (:quoted-message message) current-public-key public? pinned])
[render-parsed-text-with-message-status message (:parsed-text content)]])]]]])))
(defmethod ->message constants/content-type-text
[message {:keys [on-long-press modal] :as reaction-picker}]
@ -511,12 +483,12 @@
[community-content message])
(defmethod ->message constants/content-type-status
[{:keys [content content-type pinned] :as message}]
[{:keys [content content-type] :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))
(fn [acc e] (render-inline (:text content) content-type acc e))
[react/text-class {:style (style/status-text)}]
(-> content :parsed-text peek :children))]]])
@ -544,11 +516,11 @@
: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))}]))))})
[react/view (style/message-view-wrapper outgoing)
[react/view style/message-view-wrapper
[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)}
[react/view {:style (style/style-message-text)}
(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)}
@ -624,7 +596,7 @@
[])))
:on-press (fn []
(reset! show-timestamp? true))})
[react/view (style/message-view-wrapper (:outgoing message))
[react/view style/message-view-wrapper
[message-timestamp message show-timestamp?]
[react/view {:style (style/message-view message) :accessibility-label :audio-message}
[react/view {:style (style/message-view-content)}
@ -659,8 +631,8 @@
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)}
[message _]
[react/view {:style (style/content-type-contact-request)}
[react/image {:source (resources/get-image :hand-wave)
:style {:width 112
:height 97}}]
@ -678,7 +650,7 @@
[message-content-wrapper message
[unknown-content-type message]])
(defn chat-message [{:keys [outgoing display-photo? pinned pinned-by] :as message} space-keeper]
(defn chat-message [{:keys [display-photo? pinned pinned-by] :as message} space-keeper]
[:<>
[reactions/with-reaction-picker
{:message message
@ -698,5 +670,5 @@
: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]])])
[react/view {:style (style/pin-indicator-container)}
[pinned-by-indicator display-photo? pinned-by]])])

View File

@ -0,0 +1,702 @@
(ns status-im.ui.screens.chat.message.message-old
(:require [re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.i18n.i18n :as i18n]
[status-im.react-native.resources :as resources]
[quo.design-system.colors :as colors]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.message.audio-old :as message.audio]
[status-im.chat.models.reactions :as models.reactions]
[status-im.ui.screens.chat.message.command :as message.command]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.chat.sheets :as sheets]
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im.ui.screens.chat.styles.message.message-old :as style]
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.utils.security :as security]
[status-im.ui.screens.chat.message.reactions :as reactions]
[status-im.ui.screens.chat.image.preview.views :as preview]
[quo.core :as quo]
[status-im.utils.config :as config]
[reagent.core :as reagent]
[status-im.ui.screens.chat.components.reply :as components.reply]
[status-im.ui.screens.chat.message.link-preview :as link-preview]
[status-im.ui.screens.communities.icon :as communities.icon]
[status-im.ui.components.animation :as animation]
[status-im.chat.models.images :as images]
[status-im.chat.models.pin-message :as models.pin-message]
[status-im.ui.components.fast-image :as fast-image])
(: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]])))
(defview quoted-message
[_ {:keys [from parsed-text image]} outgoing current-public-key public? pinned]
(letsubs [contact-name [:contacts/contact-name-by-identity from]]
[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))]]
(if (and image
;; Disabling images for public-chats
(not public?))
[fast-image/fast-image {:style {:width 56
:height 56
:background-color :black
:border-radius 4}
:source {:uri image}}]
[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 [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 [:show-popover {:view :pin-limit
:message message
:prevent-closing? true}]))
(re-frame/dispatch [::models.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?] :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])
[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 public? pinned in-popover? message-pin-enabled] :as message}
{:keys [on-long-press modal]
:as 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
[{: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))}]))))})
[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)}
(:text content)]]
[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
(when-not outgoing
[{:on-press #(when pack
(re-frame/dispatch [:chat.ui/show-profile from]))
:label (i18n/label :t/view-details)}])))})
[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 (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}]
[])))
: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]])])

View File

@ -8,7 +8,7 @@
[status-im.chat.models.pin-message :as models.pin-message]
[status-im.ui.components.list.views :as list]
[status-im.utils.handlers :refer [<sub]]
[status-im.ui.screens.chat.message.message :as message]))
[status-im.ui.screens.chat.message.message-old :as message]))
(def selected-unpin (reagent/atom nil))

View File

@ -81,8 +81,8 @@
{:justify-content :flex-end}
{:justify-content :flex-start})
(if (or display-photo? timeline)
{:padding-left (+ 16 photos/default-size (when timeline 8))}
{:padding-left 8})))
{:padding-left (+ 30 photos/default-size (when timeline 8))}
{:padding-left 30})))
(defn reaction-button [active]
(merge {:width 40

View File

@ -12,7 +12,7 @@
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.chat.views :as chat]
[status-im.ui.components.list.views :as list]
[status-im.ui.screens.chat.message.message :as message]
[status-im.ui.screens.chat.message.message-old :as message]
[status-im.utils.datetime :as time]))
(defn pins-topbar [chat]

View File

@ -17,22 +17,16 @@
:align-items :stretch
:flex-grow 1})
(defn slider [outgoing]
(defn slider []
{: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)})
:thumb-tint-color colors/white
:minimum-track-tint-color colors/white
:maximum-track-tint-color colors/white-transparent})
(defn play-pause-container [outgoing? loading?]
{:background-color (if outgoing? colors/white-persist colors/blue)
(defn play-pause-container [loading?]
{:background-color colors/white-persist
:width 28
:height 28
:padding (if loading? 4 2)
@ -42,6 +36,6 @@
{:flex-direction :row
:justify-content :space-between})
(defn timestamp [outgoing]
(merge (message.style/audio-message-timestamp-text outgoing)
(defn timestamp []
(merge (message.style/audio-message-timestamp-text)
{:margin-left 40}))

View File

@ -0,0 +1,47 @@
(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}))

View File

@ -1,11 +1,22 @@
(ns status-im.ui.screens.chat.styles.message.datemark
(:require [quo.design-system.colors :as colors]))
(:require [quo2.foundations.colors :as quo2.colors]))
(def datemark-mobile
{:flex 1
:align-items :center
:margin-top 16
:height 22})
: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 colors/gray})
{:color quo2.colors/neutral-50
:font-size 14
:line-height 16
:font-weight "500"})

View File

@ -0,0 +1,11 @@
(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})

View File

@ -3,11 +3,11 @@
[quo.design-system.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.styles.photos :as photos]
[status-im.ui.components.typography :as typography]))
[quo2.foundations.colors :as quo2.colors]))
(defn style-message-text
[outgoing]
{:color (if outgoing colors/white-persist colors/text)})
[]
{:color colors/text})
(defn system-message-body
[_]
@ -18,9 +18,9 @@
:align-items :center})
(defn message-body
[{:keys [outgoing]}]
(let [align (if outgoing :flex-end :flex-start)
direction (if outgoing :row-reverse :row)]
[]
(let [align :flex-start
direction :row]
{:flex-direction direction
:margin-top 4
:align-self align
@ -33,14 +33,10 @@
[]
(merge message-timestamp {:opacity 0 :color "rgba(0,0,0,0)"}))
(defn message-timestamp-wrapper [{:keys [last-in-group? outgoing group-chat]}]
(defn message-timestamp-wrapper []
{: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
:margin-left 12 ;; horizontal margin is only required at the adjust side of the message.
:margin-top 0
:opacity 0})
(defn message-timestamp-text []
@ -48,49 +44,38 @@
{:color colors/gray
:text-align :center}))
(defn message-status-text [outgoing]
(defn message-status-text []
{:font-size 10
:line-height 10
:color (if outgoing
colors/white-transparent-70-persist
colors/gray)})
:color colors/gray})
(defn audio-message-timestamp-text
[outgoing]
[]
(merge message-timestamp
{:line-height 10
:color (if outgoing
colors/white-transparent-70-persist
colors/gray)}))
:color colors/gray}))
(defn message-wrapper [{:keys [outgoing in-popover?]}]
(if (and outgoing (not in-popover?))
{:margin-left 96}
{:margin-right 96}))
(defn message-wrapper [{:keys [in-popover?]}]
(if (not in-popover?)
{:margin-left 10
:padding-right 5}
{:margin-right 10}))
(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 message-author-wrapper []
{:flex-direction :column
:flex-shrink 1
:align-items :flex-start
:margin-left 4})
(defn delivery-status [outgoing]
(if outgoing
{:align-self :flex-end
:padding-right 8}
{:align-self :flex-start
:padding-left 8}))
(defn delivery-status []
{:align-self :flex-start
:padding-left 8})
(defn pin-indicator [outgoing display-photo?]
(defn pin-indicator [display-photo?]
(merge
{:flex-direction :row
:border-top-left-radius (if outgoing 12 4)
:border-top-right-radius (if outgoing 4 12)
:border-top-left-radius 4
:border-top-right-radius 12
:border-bottom-left-radius 12
:border-bottom-right-radius 12
:padding-left 8
@ -98,27 +83,18 @@
: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})
:max-width "80%"
: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 pin-indicator-container []
{:margin-top 2
:justify-content :center
:align-self :flex-start
:align-items :flex-start
:padding-left 8})
(defn pinned-by-text-icon-container []
{:flex-direction :row
@ -145,17 +121,14 @@
{:margin-left 5})
(def message-author-touchable
{:margin-left 12
{:margin-left 0
:flex-direction :row})
(defn message-author-userpic [outgoing]
(defn message-author-userpic []
(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})))
{:width (+ 16 photos/default-size)} ;; 16 is for the padding
{:padding-left 8
:padding-right 8}))
(def delivery-text
{:color colors/gray
@ -178,10 +151,10 @@
:padding-left 3})
(defn emoji-message
[{:keys [incoming-group outgoing]}]
[{:keys [incoming-group]}]
{: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-right 0 ;; Margin to display outgoing message status
:margin-top (if incoming-group 4 0)})
(defn collapse-button []
@ -193,37 +166,25 @@
:shadow-color (:shadow-01 @colors/theme)
:shadow-offset {:width 0 :height 4}})
(defn message-view-wrapper [outgoing]
(def message-view-wrapper
{:align-self :flex-end
:flex-direction (if outgoing :row :row-reverse)})
:flex-direction :row-reverse})
(defn message-view
[{:keys [content-type outgoing group-chat last-in-group? mentioned pinned]}]
[{:keys [content-type 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})
{:border-radius 10}
(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})
(= content-type constants/content-type-audio) {:background-color colors/blue
:padding-horizontal 12
:padding-top 6}
:else {:background-color colors/white})
(when (= content-type constants/content-type-emoji)
{:flex-direction :row})))
@ -247,12 +208,10 @@
:padding-left 12
:text-align-vertical :center})
(defn quoted-message-container [outgoing]
(defn quoted-message-container []
{:margin-bottom 6
:padding-bottom 6
:border-bottom-color (if outgoing
colors/white-transparent-10
colors/black-transparent)
:border-bottom-color colors/black-transparent
:border-bottom-width 2
:border-bottom-left-radius 2
:border-bottom-right-radius 2})
@ -262,29 +221,31 @@
:align-items :center
:justify-content :flex-start})
(defn quoted-message-author [outgoing chosen?]
(defn quoted-message-author [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)))
:color colors/gray))
(defn quoted-message-text [outgoing]
(defn quoted-message-text []
{:font-size 14
:color (if outgoing
colors/white-transparent-70-persist
colors/gray)})
:color colors/gray})
(defn message-default-style []
{:font-family "Inter-Regular"
:color (quo2.colors/theme-colors quo2.colors/black quo2.colors/white)
:font-size 15
:line-height 21.75
:letter-spacing -0.135})
;; Markdown styles
(defn default-text-style []
{:max-font-size-multiplier react/max-font-size-multiplier
:style (assoc (typography/default-style)
:line-height 22)})
:style (message-default-style)})
(defn outgoing-text-style []
(update (default-text-style) :style
@ -298,12 +259,11 @@
:text-align :center
:font-weight "400"))
(defn text-style [outgoing content-type in-popover?]
(defn text-style [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 []
@ -314,10 +274,8 @@
(update (emph-text-style) :style
assoc :color colors/white-persist))
(defn emph-style [outgoing]
(if outgoing
(outgoing-emph-text-style)
(emph-text-style)))
(defn emph-style []
(emph-text-style))
(defn strong-text-style []
(update (default-text-style) :style
@ -327,20 +285,17 @@
(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-style []
(outgoing-strong-text-style)
(strong-text-style))
(defn strong-emph-style [outgoing]
(update (strong-style outgoing) :style
(defn strong-emph-style []
(update (strong-style) :style
assoc :font-style :italic))
(defn strikethrough-style [outgoing]
(defn strikethrough-style []
(cond-> (update (default-text-style) :style
assoc :text-decoration-line :line-through)
outgoing
(update :style assoc :color colors/white-persist)))
assoc :text-decoration-line :line-through)))
(def code-block-background "#2E386B")
@ -366,10 +321,8 @@
assoc
:border-left-color colors/white-transparent-70-persist))
(defn blockquote-style [outgoing]
(if outgoing
(outgoing-blockquote-style)
(default-blockquote-style)))
(defn blockquote-style []
(default-blockquote-style))
(defn default-blockquote-text-style []
(update (default-text-style) :style
@ -383,20 +336,16 @@
assoc
:color colors/white-transparent-70-persist))
(defn blockquote-text-style [outgoing]
(if outgoing
(outgoing-blockquote-text-style)
(default-blockquote-text-style)))
(defn blockquote-text-style []
(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})
[{:keys [width height]}]
{:overflow :hidden
:border-radius 8
:width width
:height height})
(defn image-message-border [opts]
(merge (image-message opts)
@ -453,7 +402,7 @@
:padding-vertical 10
:padding-horizontal 16})
(defn content-type-contact-request [outgoing]
(defn content-type-contact-request []
{:width 168
:min-height 224.71
:border-radius 8
@ -462,6 +411,6 @@
: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)})
:align-self :flex-start
:margin-right 0
:margin-left 8})

View File

@ -0,0 +1,467 @@
(ns status-im.ui.screens.chat.styles.message.message-old
(:require [status-im.constants :as constants]
[quo.design-system.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.styles.photos :as photos]
[status-im.ui.components.typography :as typography]))
(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)})

View File

@ -7,8 +7,8 @@
(def ^:private reply-symbol "↪ ")
(defn format-author
([contact] (format-author contact nil))
(defn format-author-old
([contact] (format-author-old contact nil))
([{:keys [names] :as contact} {:keys [modal profile? you?]}]
(let [{:keys [nickname ens-name]} names
[first-name second-name] (multiaccounts/contact-two-names contact false)]
@ -31,6 +31,32 @@
:font-weight "400"}}
first-name]))))
(defn format-author
([contact] (format-author contact nil))
([{:keys [names] :as contact} {:keys [modal profile? you?]}]
(let [{:keys [nickname ens-name]} names
[first-name second-name] (multiaccounts/contact-two-names contact false)]
(if (or nickname ens-name)
[react/nested-text {:number-of-lines 2
:style {:color (if modal colors/white-persist colors/black)
:font-size (if profile? 15 13)
:line-height (if profile? 22 18)
:letter-spacing -0.2
:font-weight "600"}}
(subs first-name 0 81)
(when you?
[{:style {:color colors/black-light :font-weight "500" :font-size 13}}
(str " " (i18n/label :t/You))])
(when nickname
[{:style {:color colors/black-light :font-weight "500"}}
(str " " (subs second-name 0 81))])]
[react/text {:style {:color (if modal colors/white-persist colors/black)
:font-size (if profile? 15 13)
:line-height (if profile? 22 18)
:font-weight "600"
:letter-spacing -0.2}}
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)

View File

@ -16,6 +16,7 @@
[quo.react-native :as rn]
[status-im.ui.screens.chat.audio-message.views :as audio-message]
[quo.react :as quo.react]
[status-im.ui.screens.chat.message.message-old :as message-old]
[status-im.ui.screens.chat.message.message :as message]
[status-im.ui.screens.chat.stickers.views :as stickers]
[status-im.ui.screens.chat.styles.main :as style]
@ -27,6 +28,7 @@
[status-im.ui.screens.chat.message.gap :as gap]
[status-im.ui.screens.chat.components.accessory :as accessory]
[status-im.ui.screens.chat.components.input :as components]
[status-im.ui.screens.chat.message.datemark-old :as message-datemark-old]
[status-im.ui.screens.chat.message.datemark :as message-datemark]
[status-im.ui.components.toolbar :as toolbar]
[quo.core :as quo]
@ -37,7 +39,10 @@
[status-im.ui.screens.chat.sheets :as sheets]
[status-im.utils.debounce :as debounce]
[status-im.navigation.state :as navigation.state]
[status-im.react-native.resources :as resources]))
[status-im.react-native.resources :as resources]
[status-im.ui.components.topbar :as topbar]
[quo2.foundations.colors :as quo2.colors]
[quo2.components.button :as quo2.button]))
(defn invitation-requests [chat-id admins]
(let [current-pk @(re-frame/subscribe [:multiaccount/public-key])
@ -53,6 +58,18 @@
(i18n/label :t/group-membership-request)]]])))))
(defn add-contact-bar [public-key]
(when-not (or @(re-frame/subscribe [:contacts/contact-added? public-key])
@(re-frame/subscribe [:contacts/contact-blocked? public-key]))
[react/touchable-highlight
{:on-press
#(re-frame/dispatch [:contact.ui/add-to-contact-pressed public-key])
:accessibility-label :add-to-contacts-button}
[react/view {:style (merge (style/add-contact) {:background-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/divider-dark)})}
[icons/icon :main-icons/add
{:color colors/blue}]
[react/i18n-text {:style style/add-contact-text :key :add-to-contacts}]]]))
(defn add-contact-bar-old [public-key]
(when-not (or @(re-frame/subscribe [:contacts/contact-added? public-key])
@(re-frame/subscribe [:contacts/contact-blocked? public-key]))
[react/touchable-highlight
@ -286,6 +303,29 @@
[react/view {:style (when platform/android? {:scaleY -1})}
[chat.group/group-chat-footer chat-id invitation-admin]]))
(defn render-fn-old [{: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-old/chat-datemark (:value message)]
(if (= type :gap)
[gap/gap message idx messages-list-ref false chat-id]
; message content
[message-old/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]))])
(defn render-fn [{:keys [outgoing type] :as message}
idx
_
@ -342,6 +382,57 @@
:edit-enabled edit-enabled
:in-pinned-view? in-pinned-view?}))
(defn messages-view-old [{:keys [chat
bottom-space
pan-responder
mutual-contact-requests-enabled?
space-keeper
show-input?]}]
(let [{:keys [group-chat chat-type chat-id public? community-id admins]} chat
messages @(re-frame/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? @(re-frame/subscribe [:contacts/contact-added? chat-id]))
should-send-contact-request?
(and
mutual-contact-requests-enabled?
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-old
: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 messages-view [{:keys [chat
bottom-space
pan-responder
@ -393,13 +484,29 @@
:inverted (when platform/ios? true)
:style (when platform/android? {:scaleY -1})})]))
(defn back-button []
[quo2.button/button {:type :grey
:size 32
:width 32
:accessibility-label "back-button"
:on-press #(re-frame/dispatch [:navigate-back])}
[icons/icon :main-icons/arrow-left {:color (quo2.colors/theme-colors quo2.colors/black quo2.colors/white)}]])
(defn search-button []
[quo2.button/button {:type :grey
:size 32
:width 32
:accessibility-label "search-button"}
[icons/icon :main-icons/search {:color (quo2.colors/theme-colors quo2.colors/black quo2.colors/white)}]])
(defn topbar-content []
(let [window-width @(re-frame/subscribe [:dimensions/window-width])
{:keys [group-chat chat-id] :as chat-info} @(re-frame/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]]))
[react/view {:flex-direction :row :align-items :center :height 56}
[react/touchable-highlight {:on-press #(when-not group-chat
(debounce/dispatch-and-chill [:chat.ui/show-profile chat-id] 1000))
:style {:flex 1 :margin-left 12 :width (- window-width 120)}}
[toolbar-content/toolbar-content-view-inner chat-info]]]))
(defn navigate-back-handler []
(when (and (not @navigation.state/curr-modal) (= (get @re-frame.db/app-db :view-id) :chat))
@ -407,7 +514,15 @@
(re-frame/dispatch [:close-chat])
(re-frame/dispatch [:navigate-back])))
(defn topbar []
(defn topbar-content-old []
(let [window-width @(re-frame/subscribe [:dimensions/window-width])
{:keys [group-chat chat-id] :as chat-info} @(re-frame/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-old []
;;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
@ -416,7 +531,7 @@
: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]]
[topbar-content-old]]
[react/touchable-highlight {:on-press-in #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[sheets/current-chat-actions])
@ -427,6 +542,64 @@
:padding-right 16}}
[icons/icon :main-icons/more {:color colors/black}]]])
(defn chat-render-old []
(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}
;;we want to react only on these fields, do not use full chat map here
@(re-frame/subscribe [:chats/current-chat-chat-view])
mutual-contact-requests-enabled? @(re-frame/subscribe [:mutual-contact-requests/enabled?])
max-bottom-space (max @bottom-space @panel-space)]
[:<>
[topbar-old]
[connectivity/loading-indicator]
(when chat-id
(if group-chat
[invitation-requests chat-id admins]
(when-not mutual-contact-requests-enabled? [add-contact-bar-old chat-id])))
;;MESSAGES LIST
[messages-view-old {:chat chat
:bottom-space max-bottom-space
:pan-responder pan-responder
:mutual-contact-requests-enabled? mutual-contact-requests-enabled?
: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-render []
(let [bottom-space (reagent/atom 0)
panel-space (reagent/atom 52)
@ -446,7 +619,15 @@
mutual-contact-requests-enabled? @(re-frame/subscribe [:mutual-contact-requests/enabled?])
max-bottom-space (max @bottom-space @panel-space)]
[:<>
[topbar]
;; It is better to not use topbar component because of performance
[topbar/topbar {:navigation :none
:left-component [react/view {:flex-direction :row :margin-left 16}
[back-button]]
:title-component [topbar-content]
:right-component [react/view {:flex-direction :row :margin-right 16}
[search-button]]
:border-bottom false
:new-ui? true}]
[connectivity/loading-indicator]
(when chat-id
(if group-chat
@ -485,6 +666,14 @@
[contact-request/contact-request-message-auto-focus-wrapper text-input-ref]]
[bottom-sheet @active-panel]])]))))
(defn chat-old []
(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-old}))
(defn chat []
(reagent/create-class
{:component-did-mount (fn []

View File

@ -148,7 +148,7 @@
text]])
(defn community-chat-item [{:keys [chat-id] :as home-item} _ _ _]
[inner-item/home-list-item
[inner-item/home-list-item-old
;; We want communities to behave as public chats when it comes to
;; unread indicator
(assoc home-item :public? true)
@ -271,7 +271,7 @@
[community-chat-list id categories false from-chat]
[community-channel-preview-list id chats])
(when admin
[components.plus-button/plus-button
[components.plus-button/plus-button-old
{:on-press #(>evt [:bottom-sheet/show-sheet
{:content (fn []
[community-plus-actions community])}])

View File

@ -27,7 +27,7 @@
[quo/checkbox {:value selected
:on-change on-change}]]
[react/view {:flex 1}
[inner-item/home-list-item
[inner-item/home-list-item-old
(assoc home-item :public? true)
{:on-press on-change}]]]))

View File

@ -51,7 +51,7 @@
{:title first-name
:subtitle second-name
:accessibility-label :member-item
:icon [chat-icon/profile-photo-plus-dot-view
:icon [chat-icon/profile-photo-plus-dot-view-old
{:public-key public-key
:photo-path (multiaccounts/displayed-photo member)}]
:accessory (when (not= public-key my-public-key)

View File

@ -54,7 +54,7 @@
:on-press #(show-delete-chat-confirmation community-id chat-id)}
[icons/icon :main-icons/delete-circle {:no-color true}]]
[rn/view {:flex 1}
[inner-item/home-list-item (assoc home-item :edit? true) {:active-opacity 1}]]
[inner-item/home-list-item-old (assoc home-item :edit? true) {:active-opacity 1}]]
[rn/touchable-opacity {:on-long-press drag
:delay-long-press 100
:accessibility-label :chat-drag-handle

View File

@ -15,7 +15,7 @@
[quo/list-item
{:title first-name
:subtitle second-name
:icon [chat-icon.screen/profile-photo-plus-dot-view
:icon [chat-icon.screen/profile-photo-plus-dot-view-old
{:public-key public-key
:photo-path (multiaccounts/displayed-photo contact)}]
:chevron true

View File

@ -31,7 +31,7 @@
[react/view {:flex 1}
[react/view {:padding-horizontal 16
:padding-vertical 10}
[search-input/search-input
[search-input/search-input-old
{:search-active? search-active?
:search-filter search-filter
:on-cancel #(re-frame/dispatch [:search/currency-filter-changed nil])

View File

@ -17,7 +17,7 @@
[status-im.ui.components.topbar :as topbar]
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.ui.components.toolbar :as toolbar]
[status-im.ui.screens.chat.message.message :as message]
[status-im.ui.screens.chat.message.message-old :as message]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.profile.components.views :as profile.components]
[status-im.utils.debounce :as debounce]
@ -639,10 +639,10 @@
(views/defview my-name []
(views/letsubs [contact-name [:multiaccount/preferred-name]]
(when-not (string/blank? contact-name)
(chat.utils/format-author {:names {:ens-name
(str "@"
(or (stateofus/username contact-name)
contact-name))}}))))
(chat.utils/format-author-old {:names {:ens-name
(str "@"
(or (stateofus/username contact-name)
contact-name))}}))))
(views/defview registered [names {:keys [preferred-name] :as account} _ registrations]
[react/view {:style {:flex 1}}

View File

@ -149,8 +149,8 @@
(fn [{:keys [contacts no-contacts-label toggle-fn allow-new-users?]}]
[react/view {:style {:flex 1}}
[react/view {:style (styles/search-container)}
[search/search-input {:on-cancel #(reset! search-value nil)
:on-change #(reset! search-value %)}]]
[search/search-input-old {:on-cancel #(reset! search-value nil)
:on-change #(reset! search-value %)}]]
[react/view {:style {:flex 1
:padding-vertical 8}}
(if (seq contacts)

View File

@ -9,11 +9,10 @@
(def public-unread
{:background-color colors/blue
:border-radius 6
:margin-right 5
:margin-bottom 5
:width 12
:height 12})
:border-radius 5
:margin-right 16
:width 10
:height 10})
(def datetime-text
{:color colors/text-gray

View File

@ -18,13 +18,18 @@
[status-im.add-new.db :as db]
[status-im.utils.debounce :as debounce]
[status-im.utils.utils :as utils]
[quo.components.safe-area :as safe-area]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.components.plus-button :as components.plus-button]
[status-im.ui.screens.chat.sheets :as sheets]
[status-im.ui.components.tabbar.core :as tabbar]
[status-im.ui.components.invite.views :as invite]
[status-im.utils.config :as config])
[status-im.utils.config :as config]
[quo2.components.text :as quo2.text]
[status-im.qr-scanner.core :as qr-scanner]
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
[status-im.ui.components.chat-icon.styles :as chat-icon.styles]
[quo2.foundations.colors :as quo2.colors]
[quo2.components.button :as quo2.button])
(:require-macros [status-im.utils.views :as views]))
(defn home-tooltip-view []
@ -71,6 +76,26 @@
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:new-chat/set-new-identity text] 300))}]])
(defn search-input-wrapper-old [search-filter chats-empty]
[react/view {:padding-horizontal 16
:padding-vertical 10}
[search-input/search-input-old
{:search-active? search-active?
:search-filter search-filter
:on-cancel #(re-frame/dispatch [:search/home-filter-changed nil])
:on-blur (fn []
(when chats-empty
(re-frame/dispatch [:search/home-filter-changed nil]))
(re-frame/dispatch [::new-chat/clear-new-identity]))
:on-focus (fn [search-filter]
(when-not search-filter
(re-frame/dispatch [:search/home-filter-changed ""])
(re-frame/dispatch [::new-chat/clear-new-identity])))
:on-change (fn [text]
(re-frame/dispatch [:search/home-filter-changed text])
(re-frame/dispatch [:set-in [:contacts/new-identity :state] :searching])
(debounce/debounce-and-dispatch [:new-chat/set-new-identity text] 300))}]])
(defn start-suggestion [search-value]
(let [{:keys [state ens-name public-key]}
@(re-frame/subscribe [:contacts/new-identity])
@ -114,6 +139,23 @@
[sheets/actions home-item])}])}]
[communities.views/community-home-list-item home-item]))
(defn render-fn-old [{:keys [chat-id] :as home-item}]
;; We use `chat-id` to distinguish communities from chats
(if chat-id
[inner-item/home-list-item-old
home-item
{:on-press (fn []
(re-frame/dispatch [:dismiss-keyboard])
(if (and @config/new-ui-enabled? platform/android?)
(re-frame/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id])
(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id]))
(re-frame/dispatch [:search/home-filter-changed nil])
(re-frame/dispatch [:accept-all-activity-center-notifications-from-chat chat-id]))
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
{:content (fn []
[sheets/actions home-item])}])}]
[communities.views/community-home-list-item home-item]))
(defn chat-list-key-fn [item]
(or (:chat-id item) (:id item)))
@ -145,6 +187,31 @@
[home-tooltip-view]
[react/view {:height 68}])}])))
(views/defview communities-and-chats-old []
(views/letsubs [{:keys [items search-filter]} [:home-items]
hide-home-tooltip? [:hide-home-tooltip?]]
(if (and (empty? items)
(empty? search-filter)
hide-home-tooltip?
(not @search-active?))
[welcome-blank-page]
[list/flat-list
{:key-fn chat-list-key-fn
:getItemLayout get-item-layout
:on-end-reached #(re-frame/dispatch [:chat.ui/show-more-chats])
:keyboard-should-persist-taps :always
:data items
:render-fn render-fn-old
:header [:<>
(when (or (seq items) @search-active? (seq search-filter))
[search-input-wrapper-old search-filter (empty? items)])
(when (and (empty? items)
(or @search-active? (seq search-filter)))
[start-suggestion search-filter])]
:footer (if (and (not hide-home-tooltip?) (not @search-active?))
[home-tooltip-view]
[react/view {:height 68}])}])))
(views/defview chats-list []
(views/letsubs [loading? [:chats/loading?]]
[:<>
@ -154,6 +221,15 @@
[react/activity-indicator {:animating true}]]
[communities-and-chats])]))
(views/defview chats-list-old []
(views/letsubs [loading? [:chats/loading?]]
[:<>
[connectivity/loading-indicator]
(if loading?
[react/view {:flex 1 :align-items :center :justify-content :center}
[react/activity-indicator {:animating true}]]
[communities-and-chats-old])]))
(views/defview plus-button []
(views/letsubs [logging-in? [:multiaccounts/login]]
[components.plus-button/plus-button
@ -162,7 +238,33 @@
:loading logging-in?
:accessibility-label :new-chat-button}]))
(views/defview plus-button-old []
(views/letsubs [logging-in? [:multiaccounts/login]]
[components.plus-button/plus-button-old
{:on-press (when-not logging-in?
#(re-frame/dispatch [:bottom-sheet/show-sheet :add-new {}]))
:loading logging-in?
:accessibility-label :new-chat-button}]))
(views/defview notifications-button []
(views/letsubs [notif-count [:activity.center/notifications-count]]
[react/view
[quo2.button/button {:type :grey
:size 32
:width 32
:style {:margin-left 12}
:accessibility-label :notifications-button
:on-press #(do
(re-frame/dispatch [:mark-all-activity-center-notifications-as-read])
(re-frame/dispatch [:navigate-to :notifications-center]))}
[icons/icon :main-icons/notification2 {:color (quo2.colors/theme-colors quo2.colors/black quo2.colors/white)}]]
(when (pos? notif-count)
[react/view {:style (merge (styles/counter-public-container) {:top 5 :right 5})
:pointer-events :none}
[react/view {:style styles/counter-public
:accessibility-label :notifications-unread-badge}]])]))
(views/defview notifications-button-old []
(views/letsubs [notif-count [:activity.center/notifications-count]]
[react/view
[quo/button {:type :icon
@ -179,19 +281,57 @@
[react/view {:style styles/counter-public
:accessibility-label :notifications-unread-badge}]])]))
(defn qr-button []
[quo2.button/button {:type :grey
:accessibility-label "qr-button"
:size 32
:width 32
:style {:margin-left 12}
:on-press #(do
(re-frame/dispatch [::qr-scanner/scan-code
{:handler ::qr-scanner/on-scan-success}]))}
[icons/icon :main-icons/qr2 {:color (quo2.colors/theme-colors quo2.colors/black quo2.colors/white)}]])
(defn scan-button []
[quo2.button/button {:type :grey
:size 32
:width 32
:accessibility-label "scan-button"
:on-press #(do
(re-frame/dispatch [::qr-scanner/scan-code
{:handler ::qr-scanner/on-scan-success}]))}
[icons/icon :main-icons/scan2 {:color (quo2.colors/theme-colors quo2.colors/black quo2.colors/white)}]])
(views/defview profile-button []
(views/letsubs [{:keys [public-key preferred-name emoji]} [:multiaccount]]
[react/view
[chat-icon.screen/emoji-chat-icon-view public-key false preferred-name emoji
{:size 28
:chat-icon chat-icon.styles/chat-icon-chat-list}]]))
(defn home []
[safe-area/consumer
(fn [insets]
[react/keyboard-avoiding-view {:style {:flex 1 :padding-top (:top insets)}
:ignore-offset true}
[topbar/topbar {:title (i18n/label :t/chat)
:navigation :none
:right-component [react/view {:flex-direction :row :margin-right 16}
[connectivity/connectivity-button]
[notifications-button]]}]
[chats-list]
[plus-button]
[tabbar/tabs-counts-subscriptions]])])
[react/keyboard-avoiding-view {:style {:flex 1 :background-color (quo2.colors/theme-colors quo2.colors/neutral-5 quo2.colors/switcher-background)}
:ignore-offset true}
[topbar/topbar {:navigation :none
:use-insets true
:background (quo2.colors/theme-colors quo2.colors/neutral-5 quo2.colors/switcher-background)
:left-component [react/view {:flex-direction :row :margin-left 16}
[profile-button]]
:right-component [react/view {:flex-direction :row :margin-right 16}
[scan-button]
[qr-button]
[notifications-button]]
:border-bottom false}]
[react/view {:flex-direction :row
:justify-content :space-between
:align-items :center
:margin-horizontal 16
:margin-top 15
:margin-bottom 8}
[quo2.text/text {:size :heading-1 :weight :semi-bold} (i18n/label :t/messages)]
[plus-button]]
[chats-list]
[tabbar/tabs-counts-subscriptions]])
(defn home-old []
[react/keyboard-avoiding-view {:style {:flex 1}
@ -200,7 +340,7 @@
:navigation :none
:right-component [react/view {:flex-direction :row :margin-right 16}
[connectivity/connectivity-button]
[notifications-button]]}]
[chats-list]
[plus-button]
[tabbar/tabs-counts-subscriptions]])
[notifications-button-old]]}]
[chats-list-old]
[plus-button-old]
[tabbar/tabs-counts-subscriptions]])

View File

@ -12,7 +12,10 @@
[status-im.ui.components.icons.icons :as icons]
[status-im.utils.core :as utils]
[status-im.utils.datetime :as time]
[status-im.ui.components.chat-icon.styles :as chat-icon.styles]))
[status-im.ui.components.chat-icon.styles :as chat-icon.styles]
[quo2.components.text :as quo2.text]
[status-im.utils.utils :as utils.utils]
[quo2.foundations.colors :as quo2.colors]))
(defn preview-label [label-key label-fn]
[react/text {:style styles/last-message-text
@ -116,6 +119,22 @@
(defn unviewed-indicator [{:keys [unviewed-mentions-count
unviewed-messages-count
public?]}]
(when (pos? unviewed-messages-count)
[react/view {:position :absolute :right 16}
(cond
(and public? (not (pos? unviewed-mentions-count)))
[react/view {:style styles/public-unread
:accessibility-label :unviewed-messages-public}]
(and public? (pos? unviewed-mentions-count))
[badge/message-counter unviewed-mentions-count]
:else
[badge/message-counter unviewed-messages-count])]))
(defn unviewed-indicator-old [{:keys [unviewed-mentions-count
unviewed-messages-count
public?]}]
(when (pos? unviewed-messages-count)
[react/view {:position :absolute :right 16 :bottom 12}
(cond
@ -151,6 +170,23 @@
[icons/icon :main-icons/tiny-new-contact (icon-style)]))
(defn chat-item-title [chat-id muted group-chat chat-name edit?]
[quo2.text/text {:weight :semi-bold
:color (when muted :secondary)
:accessibility-label :chat-name-text
:ellipsize-mode :tail
:number-of-lines 1
:style {:position :absolute
:left 72
:top 10
:right (if edit? 50 90)}}
(if group-chat
(utils/truncate-str chat-name 30)
;; This looks a bit odd, but I would like only to subscribe
;; if it's a one-to-one. If wrapped in a component styling
;; won't be applied correctly.
(first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))])
(defn chat-item-title-old [chat-id muted group-chat chat-name edit?]
[quo/text {:weight :medium
:color (when muted :secondary)
:accessibility-label :chat-name-text
@ -168,12 +204,62 @@
(first @(re-frame/subscribe [:contacts/contact-two-names-by-identity chat-id])))])
(defn home-list-item [home-item opts]
(let [{:keys [chat-id chat-name color group-chat muted emoji highlight edit? public? unviewed-messages-count contacts]} home-item
background-color (when highlight (colors/get-color :interactive-02))]
[react/touchable-opacity (merge {:style {:height 64 :background-color background-color}} opts)
[:<>
(when (pos? unviewed-messages-count)
[react/view {:position :absolute :top 2 :left 8 :right 8 :bottom 2 :border-radius 16 :background-color quo2.colors/primary-50-opa-5}])
[chat-icon.screen/emoji-chat-icon-view chat-id group-chat chat-name emoji
{:container (assoc chat-icon.styles/container-chat-list
:top 12 :left 20 :position :absolute)
:size 32
:chat-icon chat-icon.styles/chat-icon-chat-list
:default-chat-icon (chat-icon.styles/default-chat-icon-chat-list color)
:default-chat-icon-text (if (string/blank? emoji)
(chat-icon.styles/default-chat-icon-text 40)
(chat-icon.styles/emoji-chat-icon-text 40))}]
[chat-item-title chat-id muted group-chat chat-name edit?]
(when-not edit?
[react/view {:height "100%" :justify-content :center}
[unviewed-indicator home-item]])
[react/view {:position :absolute :left 72 :top 32 :right 80}
(if public?
[quo2.text/text {:color :secondary
:number-of-lines 1
:ellipsize-mode :middle
:weight :medium
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}}
(i18n/label :t/public)]
(if group-chat
[react/view {:flex-direction :row
:flex 1
:padding-right 16
:align-items :center}
[icons/icon :main-icons/tiny-group2
{:width 16
:height 16
:no-color true
:container-style {:width 16
:height 16
:margin-right 4}}]
[quo2.text/text {:weight :medium
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}}
(i18n/label :t/members-count {:count (count contacts)})]]
[quo2.text/text {:monospace true
:weight :medium
:style {:color (quo2.colors/theme-colors quo2.colors/neutral-50 quo2.colors/neutral-40)}
:number-of-lines 1
:ellipsize-mode :middle}
(utils.utils/get-shortened-address chat-id)]))]]]))
(defn home-list-item-old [home-item opts]
(let [{:keys [chat-id chat-name color group-chat public? timestamp last-message muted emoji highlight edit?]} home-item
background-color (when highlight (colors/get-color :interactive-02))]
[react/touchable-opacity (merge {:style {:height 64 :background-color background-color}} opts)
[:<>
[chat-item-icon muted (and group-chat (not public?)) (and group-chat public?)]
[chat-icon.screen/emoji-chat-icon-view chat-id group-chat chat-name emoji
[chat-icon.screen/emoji-chat-icon-view-old chat-id group-chat chat-name emoji
{:container (assoc chat-icon.styles/container-chat-list
:top 12 :left 16 :position :absolute)
:size 40
@ -182,7 +268,7 @@
:default-chat-icon-text (if (string/blank? emoji)
(chat-icon.styles/default-chat-icon-text 40)
(chat-icon.styles/emoji-chat-icon-text 40))}]
[chat-item-title chat-id muted group-chat chat-name edit?]
[chat-item-title-old chat-id muted group-chat chat-name edit?]
(when-not edit?
[:<>
[react/text {:style styles/datetime-text
@ -192,5 +278,5 @@
(memo-timestamp (if (pos? (:whisper-timestamp last-message))
(:whisper-timestamp last-message)
timestamp))]
[unviewed-indicator home-item]])
[message-content-text (select-keys last-message [:content :content-type :community-id]) true]]]))
[unviewed-indicator-old home-item]])
[message-content-text (select-keys last-message [:content :content-type :community-id]) true]]]))

View File

@ -13,7 +13,7 @@
[status-im.ui.screens.profile.components.styles :as profile.components.styles]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.components.common.common :as components.common]
[status-im.ui.screens.chat.message.message :as message]
[status-im.ui.screens.chat.message.message-old :as message]
[status-im.ui.screens.chat.photos :as photos]
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.utils.debounce :as debounce])
@ -109,7 +109,7 @@
:content-type constants/content-type-text}]
[react/view {:margin-bottom 8 :margin-right 16}
[react/view {:padding-left 72}
(chat.utils/format-author contact)]
(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}]]

View File

@ -1,5 +1,6 @@
(ns status-im.ui.screens.profile.visibility-status.styles
(:require [quo.design-system.colors :as colors]))
(:require [quo.design-system.colors :as colors]
[quo2.foundations.colors :as quo2.colors]))
(defn visibility-status-button-container []
{:background-color (:interactive-02 @colors/theme)
@ -14,6 +15,14 @@
:padding-right 12})
(defn visibility-status-dot [dot-color size]
{:background-color dot-color
:width size
:height size
:border-radius (/ size 2)
:border-width 3.5
:border-color (quo2.colors/theme-colors quo2.colors/white quo2.colors/neutral-90)})
(defn visibility-status-dot-old [dot-color size]
{:background-color dot-color
:width size
:height size
@ -21,8 +30,8 @@
:border-width 1
:border-color colors/white})
(defn visibility-status-profile-dot [color size border-width margin-left]
(merge (visibility-status-dot color size)
(defn visibility-status-profile-dot-old [color size border-width margin-left]
(merge (visibility-status-dot-old color size)
{:margin-right 6
:margin-left margin-left
:border-width border-width}))

View File

@ -5,7 +5,8 @@
[status-im.utils.handlers :refer [<sub]]
[status-im.utils.datetime :as datetime]
[quo.design-system.colors :as colors]
[clojure.string :as string]))
[clojure.string :as string]
[quo2.foundations.colors :as quo2.colors]))
;; Specs:
;; :visibility-status-automatic
@ -19,6 +20,26 @@
;; Display - Offline forever
;; Note: Only send pings if the user interacted with the app in the last x minutes.
(def visibility-status-type-data
{constants/visibility-status-unknown
{:color colors/red
:title (i18n/label :t/error)}
constants/visibility-status-automatic
{:color quo2.colors/color-online
:title (i18n/label :t/status-automatic)
:subtitle (i18n/label :t/status-automatic-subtitle)}
constants/visibility-status-dnd
{:color colors/color-dnd
:title (i18n/label :t/status-dnd)
:subtitle (i18n/label :t/status-dnd-subtitle)}
constants/visibility-status-always-online
{:color quo2.colors/color-online
:title (i18n/label :t/status-always-online)}
constants/visibility-status-inactive
{:color colors/color-inactive
:title (i18n/label :t/status-inactive)
:subtitle (i18n/label :t/status-inactive-subtitle)}})
(def visibility-status-type-data-old
{constants/visibility-status-unknown
{:color colors/red
:title (i18n/label :t/error)}
@ -63,11 +84,20 @@
[{:keys [status-type] :as visibility-status-update} my-icon?]
(if my-icon?
(if (= status-type constants/visibility-status-inactive)
colors/color-inactive colors/color-online)
colors/color-inactive quo2.colors/color-online)
(let [{:keys [real-status-type]}
(calculate-real-status-type-and-time-left visibility-status-update)]
(:color (get visibility-status-type-data real-status-type)))))
(defn dot-color-old
[{:keys [status-type] :as visibility-status-update} my-icon?]
(if my-icon?
(if (= status-type constants/visibility-status-inactive)
colors/color-inactive colors/color-online)
(let [{:keys [real-status-type]}
(calculate-real-status-type-and-time-left visibility-status-update)]
(:color (get visibility-status-type-data-old real-status-type)))))
(defn my-icon? [public-key]
(or (string/blank? public-key)
(= public-key (<sub [:multiaccount/public-key]))))
@ -77,16 +107,31 @@
(<sub [:multiaccount/current-user-visibility-status])
(<sub [:visibility-status-updates/visibility-status-update public-key])))
(defn icon-visibility-status-dot [public-key container-size identicon?]
(defn icon-visibility-status-dot [public-key container-size _]
(let [my-icon? (my-icon? public-key)
visibility-status-update (visibility-status-update public-key my-icon?)
size (/ container-size 2.4)
margin -2
dot-color (dot-color visibility-status-update my-icon?)
accessibility-label (if (= dot-color quo2.colors/color-online)
:online-profile-photo-dot
:offline-profile-photo-dot)]
(merge (styles/visibility-status-dot dot-color size)
{:bottom margin
:right margin
:position :absolute
:accessibility-label accessibility-label})))
(defn icon-visibility-status-dot-old [public-key container-size identicon?]
(let [my-icon? (my-icon? public-key)
visibility-status-update (visibility-status-update public-key my-icon?)
size (/ container-size 4)
margin (if identicon? (/ size 6) (/ size 7))
dot-color (dot-color visibility-status-update my-icon?)
dot-color (dot-color-old visibility-status-update my-icon?)
accessibility-label (if (= dot-color colors/color-online)
:online-profile-photo-dot
:offline-profile-photo-dot)]
(merge (styles/visibility-status-dot dot-color size)
(merge (styles/visibility-status-dot-old dot-color size)
{:bottom margin
:right margin
:position :absolute

View File

@ -36,9 +36,9 @@
[border-width margin-left size] (if automatic? [1 -10 12] [0 6 10])]
[:<>
(when automatic?
[rn/view {:style (styles/visibility-status-profile-dot
[rn/view {:style (styles/visibility-status-profile-dot-old
colors/color-inactive size border-width 6)}])
[rn/view {:style (styles/visibility-status-profile-dot
[rn/view {:style (styles/visibility-status-profile-dot-old
color size border-width margin-left)}]]))
(defn visibility-status-button [on-press props]
@ -50,7 +50,7 @@
constants/visibility-status-automatic)
constants/visibility-status-automatic)
status-type)
{:keys [color title]} (get utils/visibility-status-type-data status-type)]
{:keys [color title]} (get utils/visibility-status-type-data-old status-type)]
[rn/touchable-opacity
(merge
{:on-press on-press
@ -97,7 +97,7 @@
(defn status-option [{:keys [request-close status-type]}]
(let [{:keys [color title subtitle]}
(get utils/visibility-status-type-data status-type)]
(get utils/visibility-status-type-data-old status-type)]
[rn/touchable-opacity {:style {:padding 6}
:accessibility-label :visibility-status-option
:on-press #(status-option-pressed

View File

@ -224,7 +224,7 @@
:hardwareBackButton {:dismissModalOnPress false
:popStackOnPress false}
:topBar {:visible false}}
:component chat/chat}
:component chat/chat-old}
;Pinned messages
{:name :chat-pinned-messages

View File

@ -1,5 +1,5 @@
(ns status-im.ui.screens.status.views
(:require [status-im.ui.screens.chat.message.message :as message]
(:require [status-im.ui.screens.chat.message.message-old :as message]
[status-im.ui.components.react :as react]
[quo.design-system.colors :as colors]
[status-im.utils.datetime :as datetime]
@ -210,5 +210,5 @@
:on-scroll-to-index-failed #()
:header [react/view {:height 8}]
:footer [react/view {:height 68}]}]))
[components.plus-button/plus-button
[components.plus-button/plus-button-old
{:on-press #(re-frame/dispatch [:open-modal :my-status])}]]))

View File

@ -43,7 +43,7 @@
(let [search-filter @(re-frame/subscribe [:search/recipient-filter])]
[react/view {:padding-horizontal 16
:padding-vertical 10}
[search-input/search-input
[search-input/search-input-old
{:search-active? search-active?
:search-filter search-filter
:on-cancel #(re-frame/dispatch [:search/recipient-filter-changed nil])

View File

@ -80,7 +80,7 @@
[react/view {:flex 1}
[react/view {:padding-horizontal 16
:padding-vertical 10}
[search-input/search-input
[search-input/search-input-old
{:search-active? search-active?
:search-filter search-filter
:on-cancel #(re-frame/dispatch [:search/token-filter-changed nil])

View File

@ -55,7 +55,7 @@
(i18n/label :t/select-token-to-receive))
:modal? true}]
[search-input/search-input
[search-input/search-input-old
{:search-active? true}]
[react/scroll-view

View File

@ -1756,5 +1756,6 @@
"mutual-contact-requests": "Mutual contact requests",
"pending": "Pending",
"negative": "Negative",
"positive": "Positive"
"positive": "Positive",
"public": "Public"
}