diff --git a/src/status_im/ui/components/fast_image.cljs b/src/status_im/ui/components/fast_image.cljs new file mode 100644 index 0000000000..1dda2d92a6 --- /dev/null +++ b/src/status_im/ui/components/fast_image.cljs @@ -0,0 +1,29 @@ +(ns status-im.ui.components.fast-image + (:require [reagent.core :as reagent] + [status-im.ui.components.icons.icons :as icons] + [status-im.ui.components.react :as react])) + +(defn placeholder [style child] + [react/view {:style (merge style {:flex 1 :justify-content :center :align-items :center})} + child]) + +(defn fast-image [_] + (let [loaded? (reagent/atom false) + error? (reagent/atom false)] + (fn [props] + [react/fast-image-class (merge + props + {:on-error (fn [e] + (when-let [on-error (:on-error props)] + (on-error e)) + (reset! error? true)) + :on-load (fn [e] + (when-let [on-load (:on-load props)] + (on-load e)) + (reset! loaded? true))}) + (when (or @error? (not @loaded?)) + [placeholder (:style props) + (if @error? + [icons/icon :main-icons/cancel] + (when-not @loaded? + [react/activity-indicator {:animating true}]))])]))) \ No newline at end of file diff --git a/src/status_im/ui/components/react.cljs b/src/status_im/ui/components/react.cljs index 6995c52a02..0ee37e9c0e 100644 --- a/src/status_im/ui/components/react.cljs +++ b/src/status_im/ui/components/react.cljs @@ -33,7 +33,7 @@ (def image-class (reagent/adapt-react-class (reactjs/memo (.-Image react-native)))) -(def fast-image (reagent/adapt-react-class FastImage)) +(def fast-image-class (reagent/adapt-react-class FastImage)) (defn image-get-size [uri callback] (.getSize (.-Image react-native) uri callback)) (defn resolve-asset-source [uri] (js->clj (.resolveAssetSource (.-Image react-native) uri) :keywordize-keys true)) diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index 5aab7e7fbb..7fdd4d4aca 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -25,7 +25,8 @@ [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.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 @@ -99,11 +100,11 @@ (if (and image ;; Disabling images for public-chats (not public?)) - [react/fast-image {:style {:width 56 - :height 56 - :background-color :black - :border-radius 4} - :source {:uri image}}] + [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)])])) @@ -374,9 +375,17 @@ :disabled in-popover?} [react/view {:style (style/image-message style-opts) :accessibility-label :image-message} - [react/fast-image {:style (dissoc style-opts :outgoing) - :on-load (image-set-size dimensions) - :source {:uri uri}}] + (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) @@ -567,8 +576,8 @@ [{:on-press #(when pack (re-frame/dispatch [:chat.ui/show-profile from])) :label (i18n/label :t/view-details)}])))}) - [react/fast-image {:style {:margin 10 :width 140 :height 140} - :source {:uri (str (-> content :sticker :url) "&download=true")}}]] + [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 diff --git a/src/status_im/ui/screens/chat/photos.cljs b/src/status_im/ui/screens/chat/photos.cljs index 97a5aed020..9b613329ed 100644 --- a/src/status_im/ui/screens/chat/photos.cljs +++ b/src/status_im/ui/screens/chat/photos.cljs @@ -5,16 +5,17 @@ [status-im.profile.db :as profile.db] [status-im.multiaccounts.core :as multiaccounts] [status-im.utils.image :as utils.image] - [quo.design-system.colors :as colors])) + [quo.design-system.colors :as colors] + [status-im.ui.components.fast-image :as fast-image])) (def memo-photo-rend (memoize (fn [photo-path size accessibility-label _] (let [identicon? (when photo-path (profile.db/base64-png? photo-path))] [react/view {:style (style/photo-container size)} - [react/fast-image {:source (utils.image/source photo-path) - :style (style/photo size) - :accessibility-label (or accessibility-label :chat-icon)}] + [fast-image/fast-image {:source (utils.image/source photo-path) + :style (style/photo size) + :accessibility-label (or accessibility-label :chat-icon)}] (when identicon? [react/view {:style (style/photo-border size)}])])))) @@ -36,7 +37,7 @@ (defn member-identicon [identicon] (let [size style/default-size] [react/view {:style (style/photo-container size)} - [react/fast-image {:source {:uri identicon} - :style (style/photo size) - :accessibility-label :member-photo}] + [fast-image/fast-image {:source {:uri identicon} + :style (style/photo size) + :accessibility-label :member-photo}] [react/view {:style (style/photo-border size)}]])) diff --git a/src/status_im/ui/screens/chat/stickers/views.cljs b/src/status_im/ui/screens/chat/stickers/views.cljs index c522525f89..3a6715b69d 100644 --- a/src/status_im/ui/screens/chat/stickers/views.cljs +++ b/src/status_im/ui/screens/chat/stickers/views.cljs @@ -8,7 +8,8 @@ [status-im.i18n.i18n :as i18n] [quo.core :as quo] [status-im.ui.screens.chat.stickers.styles :as styles] - [status-im.utils.debounce :as debounce])) + [status-im.utils.debounce :as debounce] + [status-im.ui.components.fast-image :as fast-image])) (def icon-size 28) (def icon-horizontal-margin 8) @@ -35,9 +36,9 @@ ^{:key (str url)} [react/touchable-highlight {:style {:height 75 :width 75 :margin 5} :on-press #(debounce/dispatch-and-chill [:chat/send-sticker sticker] 1000)} - [react/fast-image {:style {:width "100%" :height "100%"} - :accessibility-label :sticker-icon - :source {:uri (str url "&download=true")}}]])]]]) + [fast-image/fast-image {:style {:width "100%" :height "100%"} + :accessibility-label :sticker-icon + :source {:uri (str url "&download=true")}}]])]]]) (defview recent-stickers-panel [window-width] (letsubs [stickers [:stickers/recent-stickers]] @@ -137,6 +138,6 @@ ^{:key (str "pack-icon" id)} [pack-icon {:id id :background-color colors/white} - [react/fast-image {:style {:width icon-size :height icon-size :border-radius (/ icon-size 2)} - :source {:uri (str thumbnail "&download=true")}}]])] + [fast-image/fast-image {:style {:width icon-size :height icon-size :border-radius (/ icon-size 2)} + :source {:uri (str thumbnail "&download=true")}}]])] [scroll-indicator]]]]])) diff --git a/src/status_im/ui/screens/chat/styles/message/message.cljs b/src/status_im/ui/screens/chat/styles/message/message.cljs index 841434e593..77c5cd1ba2 100644 --- a/src/status_im/ui/screens/chat/styles/message/message.cljs +++ b/src/status_im/ui/screens/chat/styles/message/message.cljs @@ -400,7 +400,8 @@ (defn image-message-border [opts] (merge (image-message opts) - {:border-width 1 + {:opacity (:opacity opts) + :border-width 1 :top 0 :left 0 :position :absolute diff --git a/src/status_im/ui/screens/status/views.cljs b/src/status_im/ui/screens/status/views.cljs index 498f2e5555..daddba0f17 100644 --- a/src/status_im/ui/screens/status/views.cljs +++ b/src/status_im/ui/screens/status/views.cljs @@ -19,7 +19,8 @@ [status-im.chat.models.reactions :as models.reactions] [status-im.ui.screens.chat.components.reply :as components.reply] [status-im.ui.screens.chat.message.link-preview :as link-preview] - [status-im.chat.models :as chat])) + [status-im.chat.models :as chat] + [status-im.ui.components.fast-image :as fast-image])) (defonce messages-list-ref (atom nil)) (def image-max-dimension 192) @@ -40,10 +41,10 @@ :border-radius 16 :margin-top 8} :accessibility-label :image-message} - [react/fast-image {:style {:width @width - :height image-max-dimension} - :on-load (image-set-size width) - :source {:uri uri}}] + [fast-image/fast-image {:style {:width @width + :height image-max-dimension} + :on-load (image-set-size width) + :source {:uri uri}}] [react/view {:border-width 1 :top 0 :left 0 @@ -188,10 +189,10 @@ (if no-messages? [react/view {:padding-horizontal 32 :margin-top 64} - [react/fast-image {:style {:width 140 - :height 140 - :align-self :center} - :source {:uri "https://bafybeieayj76s4vjlw5uwdvnakosy46rqyioqsp2ygl6sedivemhkxrbwi.ipfs.cf-ipfs.com"}}] + [fast-image/fast-image {:style {:width 140 + :height 140 + :align-self :center} + :source {:uri "https://bafybeieayj76s4vjlw5uwdvnakosy46rqyioqsp2ygl6sedivemhkxrbwi.ipfs.cf-ipfs.com"}}] [react/view (styles/descr-container) [react/text {:style {:color colors/gray :line-height 22}} diff --git a/src/status_im/ui/screens/stickers/views.cljs b/src/status_im/ui/screens/stickers/views.cljs index fd70c385a8..172d461ff0 100644 --- a/src/status_im/ui/screens/stickers/views.cljs +++ b/src/status_im/ui/screens/stickers/views.cljs @@ -6,15 +6,16 @@ [status-im.ui.components.react :as react] [status-im.ui.screens.stickers.styles :as styles] [status-im.utils.money :as money] - [status-im.utils.handlers :refer [