Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add loading and error indicators to sticker images #12999

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/status_im/ui/components/image_with_loader.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
(ns status-im.ui.components.image-with-loader
(:require [reagent.core :as reagent]
[quo.design-system.colors :as colors]
[status-im.ui.components.react :as react]
[status-im.ui.components.icons.icons :as icons]
[status-im.utils.contenthash :as contenthash]
[taoensso.timbre :as log]))

(defn- placeholder [props child]
(let [{:keys [accessibility-label style]} props]
[react/view {:accessibility-label accessibility-label
:style (merge style
{:align-items :center
:justify-content :center
:background-color colors/gray-lighter})}
child]))

(defn source [props]
(let [{:keys [source style accessibility-labels]} props
loaded? (reagent/atom false)
error? (reagent/atom false)
current-source (reagent/atom (if (seq? source)
source
[source]))]
(fn []
[react/view
(when @error?
[placeholder {:accessibility-label (:error accessibility-labels)
:style style}
[icons/icon :main-icons/cancel]])
(when-not (or @loaded? @error?)
[placeholder {:accessibility-label (:loading accessibility-labels)
:style style}
[react/activity-indicator {:animating true}]])
(when (not @error?)
(log/info "loaded" @loaded?)
(log/info "style" style)
[react/fast-image {:accessibility-label (:success accessibility-labels)
:onError #(if (empty? (rest @current-source))
(reset! error? true)
(reset! current-source
(rest @current-source)))
:onLoad #(reset! loaded? true)
:style (if @loaded? style {})
:source (first @current-source)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if all sources failed ?

Copy link
Contributor Author

@msuess msuess Mar 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error icon will be displayed if all sources fail

:resize-mode :contain}])])))

(defn ipfs [props]
(let [{:keys [hash]} props]
(source (merge (dissoc props :hash)
msuess marked this conversation as resolved.
Show resolved Hide resolved
{:source (map (fn [u] {:uri u})
(contenthash/alternatives hash))}))))
10 changes: 5 additions & 5 deletions src/status_im/ui/screens/chat/message/message.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im.ui.screens.chat.styles.message.message :as style]
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.utils.contenthash :as contenthash]
[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]
Expand All @@ -25,7 +24,8 @@
[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.pin-message :as models.pin-message])
[status-im.chat.models.pin-message :as models.pin-message]
[status-im.ui.components.image-with-loader :as image-with-loader])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))

(defn message-timestamp-anim
Expand Down Expand Up @@ -567,9 +567,9 @@
[{: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}
;;TODO (perf) move to event
:source {:uri (contenthash/url (-> content :sticker :hash))}}]]
[image-with-loader/ipfs {:style {:margin 10 :width 140 :height 140 :border-radius 16}
;;TODO (perf) move to event
:hash (-> content :sticker :hash)}]]
reaction-picker]))

(defmethod ->message constants/content-type-image [{:keys [content in-popover?] :as message} {:keys [on-long-press modal]
Expand Down
16 changes: 9 additions & 7 deletions src/status_im/ui/screens/chat/stickers/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
[status-im.i18n.i18n :as i18n]
[quo.core :as quo]
[status-im.ui.screens.chat.stickers.styles :as styles]
[status-im.utils.contenthash :as contenthash]
[status-im.utils.debounce :as debounce]))
[status-im.utils.debounce :as debounce]
[status-im.ui.components.image-with-loader :as image-with-loader]))

(def icon-size 28)
(def icon-horizontal-margin 8)
Expand Down Expand Up @@ -39,9 +39,11 @@
^{:key (str hash)}
[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 (contenthash/url (str "0x" hash))}}]])]]])
[image-with-loader/ipfs {:style {:width "100%" :height "100%" :border-radius 8}
:accessibility-labels {:success :sticker-icon
:loading :sticker-icon-loading
:error :sticker-icon-error}
:hash (str "0x" hash)}]])]]])

(defview recent-stickers-panel [window-width]
(letsubs [stickers [:stickers/recent]]
Expand Down Expand Up @@ -143,6 +145,6 @@
^{:key 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 (contenthash/url thumbnail)}}]])]
[image-with-loader/ipfs {:style {:width icon-size :height icon-size :border-radius (/ icon-size 2)}
:hash thumbnail}]])]
[scroll-indicator]]]]]))
2 changes: 1 addition & 1 deletion src/status_im/ui/screens/stickers/styles.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@
:border-radius 14
:background-color colors/green
:align-items :center
:justify-content :center})
:justify-content :center})
20 changes: 10 additions & 10 deletions src/status_im/ui/screens/stickers/views.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
[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.image-with-loader :as image-with-loader]
[status-im.ui.screens.stickers.styles :as styles]
[status-im.utils.contenthash :as contenthash]
[status-im.utils.money :as money])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))

(defn- thumbnail-icon [uri size]
[react/fast-image {:style {:width size :height size :border-radius (/ size 2)}
:source {:uri uri}}])
(defn- thumbnail-icon [hash size]
[image-with-loader/ipfs {:style {:width size :height size :border-radius (/ size 2)}
:hash hash}])

(defn- installed-icon []
[react/view styles/installed-icon
Expand Down Expand Up @@ -43,9 +43,9 @@
(defn pack-badge [{:keys [name author price thumbnail preview id installed owned pending]}]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:navigate-to :stickers-pack {:id id}])}
[react/view {:margin-bottom 27}
[react/fast-image {:style {:height 200 :border-radius 20} :source {:uri (contenthash/url preview)}}]
[image-with-loader/ipfs {:style {:height 200 :border-radius 20} :hash preview}]
[react/view {:height 64 :align-items :center :flex-direction :row}
[thumbnail-icon (contenthash/url thumbnail) 40]
[thumbnail-icon thumbnail 40]
[react/view {:padding-horizontal 16 :flex 1}
[react/text {:accessibility-label :sticker-pack-name} name]
[react/text {:style {:color colors/gray :margin-top 6}
Expand Down Expand Up @@ -74,11 +74,11 @@
stickers installed owned pending]
:as pack}
[:stickers/get-current-pack]]
[react/keyboard-avoiding-view {:flex 1}
[react/keyboard-avoiding-view {:flex 1 :margin-top 18}
(if pack
[react/view {:flex 1}
[react/view {:height 74 :align-items :center :flex-direction :row :padding-horizontal 16}
[thumbnail-icon (contenthash/url thumbnail) 64]
[thumbnail-icon thumbnail 64]
[react/view {:padding-horizontal 16 :flex 1}
[react/text {:style {:typography :header}} name]
[react/text {:style {:color colors/gray :margin-top 6}} author]]
Expand All @@ -90,8 +90,8 @@
[react/view {:flex-direction :row :flex-wrap :wrap}
(for [{:keys [hash]} stickers]
^{:key hash}
[react/fast-image {:style (styles/sticker-image sticker-icon-size)
:source {:uri (contenthash/url hash)}}])]]]]
[image-with-loader/ipfs {:style (styles/sticker-image sticker-icon-size)
:hash hash}])]]]]
[react/view {:flex 1 :align-items :center :justify-content :center}
[react/activity-indicator {:animating true}]])]))

Expand Down
13 changes: 13 additions & 0 deletions src/status_im/utils/contenthash.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@
"")))

(def url (memoize url-fn))

(defn ipfs-alternatives [hash]
[(str "https://" hash ".ipfs.cf-ipfs.com")
(str "https://" hash ".ipfs.dweb.link")
(str "https://ipfs.io/ipfs/" hash)])

(defn alternatives-fn [hex]
(let [{:keys [namespace hash]} (decode (ethereum/normalized-hex hex))]
(case namespace
:ipfs (ipfs-alternatives hash)
"")))

(def alternatives (memoize alternatives-fn))