[#17964] emoji screen performance (#18213)

* Fix `->` style in emoji-picker.data

* Make `temp-empty-symbol` component code safer to avoid app crashing

* fix `->` style in `emoji-picker.utils`

* Pass sheet-animating? ratom to bottom-sheet's content component

* Improve emoji picker performance
This commit is contained in:
Ulises Manuel 2023-12-21 15:44:33 -06:00 committed by GitHub
parent 4f9544d20c
commit 5fa9c0cab6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 100 deletions

View File

@ -46,7 +46,10 @@
:border-color :grey}
size)}
[quo/text {:style {:color :grey}}
(string/capitalize (first (name token)))]])
(some-> token
name
first
string/capitalize)]])
(defn view-internal
"Render a token image.

View File

@ -2,8 +2,15 @@
(:require
[quo.foundations.colors :as colors]
[quo.theme :as theme]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]))
(defn container
[{:keys [top] :as _insets}]
(let [padding-top (if platform/ios? top (+ top 10))]
{:flex 1
:padding-top padding-top}))
(defn background
[opacity]
(reanimated/apply-animations-to-style

View File

@ -15,29 +15,26 @@
(def ^:const drag-threshold 200)
(defn drag-gesture
[translate-y opacity scroll-enabled curr-scroll close]
(->
(gesture/gesture-pan)
(gesture/on-start (fn [e]
(when (< (oops/oget e "velocityY") 0)
(reset! scroll-enabled true))))
(gesture/on-update (fn [e]
(let [translation (oops/oget e "translationY")
progress (Math/abs (/ translation drag-threshold))]
(when (pos? translation)
(reanimated/set-shared-value translate-y translation)
(reanimated/set-shared-value opacity (- 1 (/ progress 5)))))))
(gesture/on-end (fn [e]
(if (> (oops/oget e "translationY") drag-threshold)
(close)
(do
(reanimated/animate translate-y 0 300)
(reanimated/animate opacity 1 300)
(reset! scroll-enabled true)))))
(gesture/on-finalize (fn [e]
(when (and (>= (oops/oget e "velocityY") 0)
(<= @curr-scroll (if platform/ios? -1 0)))
(reset! scroll-enabled false))))))
[{:keys [translate-y opacity scroll-enabled curr-scroll close reset-open-sheet set-animating-true]}]
(-> (gesture/gesture-pan)
(gesture/on-start (fn [e]
(set-animating-true)
(when (< (oops/oget e "velocityY") 0)
(reset! scroll-enabled true))))
(gesture/on-update (fn [e]
(let [translation (oops/oget e "translationY")
progress (Math/abs (/ translation drag-threshold))]
(when (pos? translation)
(reanimated/set-shared-value translate-y translation)
(reanimated/set-shared-value opacity (- 1 (/ progress 5)))))))
(gesture/on-end (fn [e]
(if (> (oops/oget e "translationY") drag-threshold)
(close)
(reset-open-sheet))))
(gesture/on-finalize (fn [e]
(when (and (>= (oops/oget e "velocityY") 0)
(<= @curr-scroll (if platform/ios? -1 0)))
(reset! scroll-enabled false))))))
(defn on-scroll
[e curr-scroll]
@ -46,40 +43,54 @@
(defn- f-view
[_]
(let [scroll-enabled (reagent/atom true)
curr-scroll (reagent/atom 0)]
(let [scroll-enabled (reagent/atom true)
curr-scroll (reagent/atom 0)
animating? (reagent/atom true)
set-animating-true #(reset! animating? true)
set-animating-false (fn [ms]
(js/setTimeout #(reset! animating? false) ms))]
(fn [{:keys [content skip-background? theme]}]
(let [insets (safe-area/get-insets)
{:keys [height]} (rn/get-window)
padding-top (:top insets)
padding-top (if platform/ios? padding-top (+ padding-top 10))
opacity (reanimated/use-shared-value 0)
translate-y (reanimated/use-shared-value height)
close (fn []
(set-animating-true)
(reanimated/animate translate-y height 300)
(reanimated/animate opacity 0 300)
(rf/dispatch [:navigate-back]))]
(rf/dispatch [:navigate-back]))
reset-open-sheet (fn []
(reanimated/animate translate-y 0 300)
(reanimated/animate opacity 1 300)
(set-animating-false 300)
(reset! scroll-enabled true))]
(rn/use-effect
(fn []
(reanimated/animate translate-y 0 300)
(reanimated/animate opacity 1 300)))
(reanimated/animate opacity 1 300)
(set-animating-false 300)))
(hooks/use-back-handler close)
[rn/view
{:style {:flex 1
:padding-top padding-top}}
[rn/view {:style (style/container insets)}
(when-not skip-background?
[reanimated/view {:style (style/background opacity)}])
[gesture/gesture-detector
{:gesture (drag-gesture translate-y opacity scroll-enabled curr-scroll close)}
{:gesture (drag-gesture {:translate-y translate-y
:opacity opacity
:scroll-enabled scroll-enabled
:curr-scroll curr-scroll
:close close
:reset-open-sheet reset-open-sheet
:set-animating-true set-animating-true})}
[reanimated/view {:style (style/main-view translate-y theme)}
[rn/view {:style style/handle-container}
[rn/view {:style (style/handle theme)}]]
[content
{:insets insets
:close close
:scroll-enabled scroll-enabled
:current-scroll curr-scroll
:on-scroll #(on-scroll % curr-scroll)}]]]]))))
{:insets insets
:close close
:scroll-enabled scroll-enabled
:current-scroll curr-scroll
:on-scroll #(on-scroll % curr-scroll)
:sheet-animating? animating?}]]]]))))
(defn- internal-view
[params]

View File

@ -85,7 +85,7 @@
(def ^:private categorized-and-partitioned
(->> emoji-data
(reduce (fn [acc {:keys [group] :as emoji}]
(update-in acc [(-> (emoji-group->category group) :index) :data] conj emoji))
(update-in acc [(-> group emoji-group->category :index) :data] conj emoji))
categories)
(reduce (fn [acc {:keys [data] :as item}]
(conj acc (assoc item :data (partition-all constants/emojis-per-row data))))

View File

@ -7,14 +7,14 @@
(defn search-emoji
[search-query]
(let [cleaned-query (string/lower-case (string/trim search-query))]
(->> (filter (fn [{:keys [label tags emoticon]}]
(->> emoji-data
(filter (fn [{:keys [label tags emoticon]}]
(or (string/includes? label cleaned-query)
(when emoticon
(if (vector? emoticon)
(some #(string/includes? (string/lower-case %) cleaned-query) emoticon)
(string/includes? (string/lower-case emoticon) cleaned-query)))
(some #(string/includes? % cleaned-query) tags)))
emoji-data)
(some #(string/includes? % cleaned-query) tags))))
(partition-all constants/emojis-per-row))))
(defn random-emoji

View File

@ -16,8 +16,7 @@
[status-im.contexts.emoji-picker.utils :as emoji-picker.utils]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]
[utils.transforms :as transforms]))
[utils.re-frame :as rf]))
(defn- on-press-category
[{:keys [id index active-category scroll-ref]}]
@ -30,16 +29,14 @@
(defn- handle-on-viewable-items-changed
[{:keys [event active-category should-update-active-category?]}]
(when should-update-active-category?
(let [viewable-item (-> (oops/oget event "viewableItems")
transforms/js->clj
first
:item)
(let [viewable-item (some-> event
(oops/oget "viewableItems")
(aget 0)
(oops/oget "item"))
header? (and (map? viewable-item) (:header? viewable-item))
section-key (if header?
(:id viewable-item)
(:id (emoji-picker.data/emoji-group->category (-> viewable-item
first
:group))))]
(-> viewable-item first :group emoji-picker.data/emoji-group->category :id))]
(when (and (some? section-key) (not= @active-category section-key))
(reset! active-category section-key)))))
@ -77,11 +74,10 @@
(defn- emoji-row
[row-data {:keys [on-select close]}]
(into [rn/view {:style style/emoji-row-container}]
(map-indexed
(fn [col-index {:keys [hexcode] :as emoji}]
^{:key hexcode}
[emoji-item emoji col-index on-select close])
row-data)))
(map-indexed (fn [col-index {:keys [hexcode] :as emoji}]
^{:key hexcode}
[emoji-item emoji col-index on-select close]))
row-data))
(defn- render-item
[item _ _ render-data]
@ -98,30 +94,30 @@
:container-style style/empty-results}])
(defn- render-list
[{:keys [theme filtered-data on-viewable-items-changed scroll-enabled on-scroll on-select
set-scroll-ref close]}]
(let [data (if filtered-data filtered-data emoji-picker.data/flatten-data)]
[gesture/flat-list
{:ref set-scroll-ref
:scroll-enabled @scroll-enabled
:data data
:initial-num-to-render 20
:max-to-render-per-batch 20
:render-fn render-item
:get-item-layout get-item-layout
:keyboard-dismiss-mode :on-drag
:keyboard-should-persist-taps :handled
:shows-vertical-scroll-indicator false
:on-scroll-to-index-failed identity
:empty-component [empty-result]
:on-scroll on-scroll
:render-data {:close close
:theme theme
:on-select on-select}
:content-container-style style/list-container
:viewability-config {:item-visible-percent-threshold 100
:minimum-view-time 200}
:on-viewable-items-changed on-viewable-items-changed}]))
[{:keys [theme filtered-data on-viewable-items-changed scroll-enabled on-scroll
on-select set-scroll-ref close sheet-animating?]}]
[gesture/flat-list
{:ref set-scroll-ref
:scroll-enabled @scroll-enabled
:data (or filtered-data emoji-picker.data/flatten-data)
:initial-num-to-render 14
:max-to-render-per-batch 10
:render-fn render-item
:get-item-layout get-item-layout
:keyboard-dismiss-mode :on-drag
:keyboard-should-persist-taps :handled
:shows-vertical-scroll-indicator false
:on-scroll-to-index-failed identity
:empty-component [empty-result]
:on-scroll on-scroll
:render-data {:close close
:theme theme
:on-select on-select}
:content-container-style style/list-container
:viewability-config {:item-visible-percent-threshold 100
:minimum-view-time 200}
:on-viewable-items-changed on-viewable-items-changed
:window-size (if @sheet-animating? 1 10)}])
(defn- footer
[{:keys [theme active-category scroll-ref]}]
@ -152,12 +148,9 @@
(reset! search-text ""))
(defn f-view
[{:keys [render-emojis? search-text on-change-text clear-states active-category scroll-ref theme]
[{:keys [search-text on-change-text clear-states active-category scroll-ref theme]
:as sheet-opts}]
(let [search-active? (pos? (count @search-text))]
;; rendering emojis is heavy on the UI thread, we need to delay rendering until the navigation
;; animation completes. 250 is based on the default 300ms navigation duration.
(rn/use-effect #(js/setTimeout (fn [] (reset! render-emojis? true)) 250))
[rn/keyboard-avoiding-view
{:style style/flex-spacer
:keyboard-vertical-offset 8}
@ -171,8 +164,7 @@
:on-change-text on-change-text
:clearable? search-active?
:on-clear clear-states}]]
(when @render-emojis?
[render-list sheet-opts])
[render-list sheet-opts]
(when-not search-active?
[footer
{:theme theme
@ -186,7 +178,6 @@
set-scroll-ref #(reset! scroll-ref %)
search-text (reagent/atom "")
filtered-data (reagent/atom nil)
render-emojis? (reagent/atom false)
active-category (reagent/atom constants/default-category)
clear-states #(clear {:active-category active-category
:filtered-data filtered-data
@ -210,17 +201,15 @@
:should-update-active-category? (nil? @filtered-data)}))]
(fn [sheet-opts]
[:f> f-view
(merge sheet-opts
{:render-emojis? render-emojis?
:search-text search-text
:on-change-text on-change-text
:clear-states clear-states
:filtered-data @filtered-data
:set-scroll-ref set-scroll-ref
:on-select on-select
:on-viewable-items-changed on-viewable-items-changed
:active-category active-category
:scroll-ref scroll-ref})])))
(assoc sheet-opts
:search-text search-text
:on-change-text on-change-text
:clear-states clear-states
:filtered-data @filtered-data
:set-scroll-ref set-scroll-ref
:on-select on-select
:on-viewable-items-changed on-viewable-items-changed
:active-category active-category
:scroll-ref scroll-ref)])))
(def view (quo.theme/with-theme view-internal))