Disable multiple button presses (#18478)

This commit is contained in:
Parvesh Monu 2024-02-05 15:26:14 +05:30 committed by GitHub
parent a6565b52ce
commit b6ce60eccf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 194 additions and 129 deletions

View File

@ -63,6 +63,6 @@
[quo/button
{:theme :positive
:style {:margin-horizontal 8}
:on-press #(debounce/dispatch-and-chill [::network/connect-network-pressed target-network-id]
1000)}
:on-press #(debounce/throttle-and-dispatch [::network/connect-network-pressed target-network-id]
1000)}
(i18n/label :t/allow)]]]]))

View File

@ -84,7 +84,7 @@
(zero? (count selected)))
:accessibility-label :share-community-link
:type :secondary
:on-press #(debounce/dispatch-and-chill
:on-press #(debounce/throttle-and-dispatch
[(if can-invite?
::communities/invite-people-confirmation-pressed
::communities/share-community-confirmation-pressed) @user-pk

View File

@ -111,7 +111,7 @@
(:available :connected :connected-with-different-key :owned)
[react/touchable-highlight
{:on-press #(debounce/dispatch-and-chill [::ens/input-submitted] 3000)}
{:on-press #(debounce/throttle-and-dispatch [::ens/input-submitted] 3000)}
[icon-wrapper colors/blue
[icons/icon :main-icons/arrow-right {:color colors/white-persist}]]]
@ -365,8 +365,9 @@
:right [react/view {:padding-horizontal 8}
[quo/button
{:disabled (or (not @checked?) (not sufficient-funds?))
:on-press #(debounce/dispatch-and-chill [::ens/register-name-pressed address]
2000)}
:on-press #(debounce/throttle-and-dispatch [::ens/register-name-pressed
address]
2000)}
(if sufficient-funds?
(i18n/label :t/ens-register)
(i18n/label :t/not-enough-snt))]]}]]))))

View File

@ -139,9 +139,9 @@
{:type :secondary
:accessibility-label :create-group-chat-button
:disabled group-name-empty?
:on-press #(debounce/dispatch-and-chill [:group-chats.ui/create-pressed
group-name]
300)}
:on-press #(debounce/throttle-and-dispatch [:group-chats.ui/create-pressed
group-name]
300)}
(i18n/label :t/create-group-chat)]}]]])))
(defn searchable-contact-list

View File

@ -6,7 +6,7 @@
[legacy.status-im.ui.screens.network.styles :as st]
[legacy.status-im.ui.screens.network.views :as network-settings]
[re-frame.core :as re-frame]
[utils.debounce :refer [dispatch-and-chill]]
[utils.debounce :refer [throttle-and-dispatch]]
[utils.i18n :as i18n])
(:require-macros [legacy.status-im.utils.views :as views]))
@ -25,7 +25,7 @@
:connected? connected?}]
(when-not connected?
[react/touchable-highlight
{:on-press #(dispatch-and-chill [::network/connect-network-pressed id] 1000)}
{:on-press #(throttle-and-dispatch [::network/connect-network-pressed id] 1000)}
[react/view st/connect-button-container
[react/view
{:style st/connect-button

View File

@ -109,7 +109,7 @@
(defn hide-sheet-and-dispatch-old
[event]
(re-frame/dispatch [:bottom-sheet/hide-old])
(debounce/dispatch-and-chill event 2000))
(debounce/throttle-and-dispatch event 2000))
(defn invitation-sheet
[{:keys [id]} contact]

View File

@ -34,7 +34,7 @@
(fn
[{:keys [on-press on-long-press disabled? type background size icon-left icon-right icon-top
customization-color theme accessibility-label icon-only? container-style inner-style
pressed? on-press-in on-press-out]
pressed? on-press-in on-press-out allow-multiple-presses?]
:or {type :primary
size 40
customization-color (cond (= type :primary) :blue
@ -52,16 +52,17 @@
:icon-only? icon-only?})
icon-size (when (= 24 size) 12)]
[rn/touchable-without-feedback
{:disabled disabled?
:accessibility-label accessibility-label
:on-press-in (fn []
(reset! pressed-state? true)
(when on-press-in (on-press-in)))
:on-press-out (fn []
(reset! pressed-state? nil)
(when on-press-out (on-press-out)))
:on-press on-press
:on-long-press on-long-press}
{:disabled disabled?
:accessibility-label accessibility-label
:on-press-in (fn []
(reset! pressed-state? true)
(when on-press-in (on-press-in)))
:on-press-out (fn []
(reset! pressed-state? nil)
(when on-press-out (on-press-out)))
:on-press on-press
:allow-multiple-presses? allow-multiple-presses?
:on-long-press on-long-press}
[rn/view
{:style (merge
(style/shape-style-container size border-radius)

View File

@ -15,11 +15,12 @@
[rn/view
{:style style/container}
[button/button
{:icon true
:type :outline
:accessibility-label :previous-month-button
:size 24
:on-press #(on-change (utils/previous-month year month))}
{:icon true
:type :outline
:accessibility-label :previous-month-button
:allow-multiple-presses? true
:size 24
:on-press #(on-change (utils/previous-month year month))}
:i/chevron-left]
[text/text
{:weight :semi-bold
@ -27,11 +28,12 @@
:style (style/text theme)}
(utils/format-month-year year month)]
[button/button
{:icon true
:accessibility-label :next-month-button
:size 24
:type :outline
:on-press #(on-change (utils/next-month year month))}
{:icon true
:accessibility-label :next-month-button
:allow-multiple-presses? true
:size 24
:type :outline
:on-press #(on-change (utils/next-month year month))}
:i/chevron-right]]))
(def view (theme/with-theme view-internal))

View File

@ -31,9 +31,10 @@
theme))]
[rn/pressable
{:style (style/color-button hex-color selected? idx window-width)
:accessibility-label :color-picker-item
:on-press #(on-press color)}
{:style (style/color-button hex-color selected? idx window-width)
:accessibility-label :color-picker-item
:allow-multiple-presses? true
:on-press #(on-press color)}
(if (and (= :feng-shui color) (not selected?))
[feng-shui
(assoc props

View File

@ -39,13 +39,15 @@
(defn user
[{:keys [short-chat-key primary-name secondary-name photo-path online? contact? verified?
untrustworthy? on-press on-long-press accessory customization-color theme]}]
untrustworthy? on-press on-long-press accessory customization-color theme
allow-multiple-presses?]}]
[rn/touchable-highlight
{:style container-style
:underlay-color (colors/resolve-color customization-color theme 5)
:accessibility-label :user-list
:on-press (when on-press on-press)
:on-long-press (when on-long-press on-long-press)}
{:style container-style
:underlay-color (colors/resolve-color customization-color theme 5)
:allow-multiple-presses? allow-multiple-presses?
:accessibility-label :user-list
:on-press (when on-press on-press)
:on-long-press (when on-long-press on-long-press)}
[:<>
[user-avatar/user-avatar
{:full-name primary-name

View File

@ -47,12 +47,13 @@
:height 40
:border-radius 10})]
[rn/touchable-without-feedback
{:test-ID test-ID
:on-long-press on-long-press ;;NOTE - this is temporary while supporting old wallet
:on-press on-press
:on-press-in #(toggle-background-color background-color false pass-through?)
:on-press-out #(toggle-background-color background-color true pass-through?)
:accessibility-label accessibility-label}
{:test-ID test-ID
:on-long-press on-long-press ;;NOTE - this is temporary while supporting old wallet
:allow-multiple-presses? true
:on-press on-press
:on-press-in #(toggle-background-color background-color false pass-through?)
:on-press-out #(toggle-background-color background-color true pass-through?)
:accessibility-label accessibility-label}
[reanimated/view {:style background-animated-style}
;; In android animations are not working for the animated components which are nested by
;; hole-view,

View File

@ -19,15 +19,16 @@
(let [label-color (style/get-label-color disabled? theme blur?)
background-color (style/toggle-background-color @pressed? blur? theme)]
[rn/pressable
{:accessibility-label (label->accessibility-label label)
:disabled (or disabled? (not label))
:on-press (fn []
(when on-press
(on-press label)))
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)
:hit-slop {:top 8 :bottom 8 :left 25 :right 25}
:style (style/container background-color)}
{:accessibility-label (label->accessibility-label label)
:disabled (or disabled? (not label))
:on-press (fn []
(when on-press
(on-press label)))
:allow-multiple-presses? true
:on-press-in #(reset! pressed? true)
:on-press-out #(reset! pressed? false)
:hit-slop {:top 8 :bottom 8 :left 25 :right 25}
:style (style/container background-color)}
(case type
:key [icons/icon
label

View File

@ -12,12 +12,13 @@
accessibility-label]
:or {accessibility-label :reaction}}]
[rn/pressable
{:accessibility-label accessibility-label
:style (merge (style/container @pressed?)
container-style)
:on-press (fn [e]
(swap! pressed? not)
(when on-press
(on-press e)))}
{:accessibility-label accessibility-label
:allow-multiple-presses? true
:style (merge (style/container @pressed?)
container-style)
:on-press (fn [e]
(swap! pressed? not)
(when on-press
(on-press e)))}
[rn/text
(reactions.resource/system-emojis emoji)]])))

View File

@ -30,7 +30,8 @@
:theme theme})]
[rn/pressable
(when-not disabled?
{:on-press #(handle-press on-change internal-checked? actual-checked?)})
{:on-press #(handle-press on-change internal-checked? actual-checked?)
:allow-multiple-presses? true})
[rn/view
{:style outer-styles
:needs-offscreen-alpha-compositing true

View File

@ -7,6 +7,7 @@
[react-native.flat-list :as flat-list]
[react-native.platform :as platform]
[react-native.section-list :as section-list]
[react-native.utils :as utils]
[reagent.core :as reagent]))
(def app-state ^js (.-AppState ^js react-native))
@ -33,12 +34,28 @@
(def text (reagent/adapt-react-class (.-Text ^js react-native)))
(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native)))
(def pressable (reagent/adapt-react-class (.-Pressable ^js react-native)))
(def touchable-opacity (reagent/adapt-react-class (.-TouchableOpacity ^js react-native)))
(def touchable-highlight (reagent/adapt-react-class (.-TouchableHighlight ^js react-native)))
(def touchable-without-feedback
(def pressable-class (reagent/adapt-react-class (.-Pressable ^js react-native)))
(def touchable-opacity-class (reagent/adapt-react-class (.-TouchableOpacity ^js react-native)))
(def touchable-highlight-class (reagent/adapt-react-class (.-TouchableHighlight ^js react-native)))
(def touchable-without-feedback-class
(reagent/adapt-react-class (.-TouchableWithoutFeedback ^js react-native)))
(defn pressable
[props & children]
(into [pressable-class (utils/custom-pressable-props props)] children))
(defn touchable-opacity
[props & children]
(into [touchable-opacity-class (utils/custom-pressable-props props)] children))
(defn touchable-highlight
[props & children]
(into [touchable-highlight-class (utils/custom-pressable-props props)] children))
(defn touchable-without-feedback
[props & children]
(into [touchable-without-feedback-class (utils/custom-pressable-props props)] children))
(def flat-list flat-list/flat-list)
(def section-list section-list/section-list)

View File

@ -0,0 +1,32 @@
(ns react-native.utils)
(defonce ^:private throttle (atom {}))
(defn- wrapped-ref
[{:keys [ref]} throttle-id]
(fn [ref-value]
(when ref-value
(when ref
(ref ref-value))
(reset! throttle-id ref-value))))
(defn- throttled-on-press
[{:keys [on-press allow-multiple-presses? throttle-duration]} throttle-id]
(if allow-multiple-presses?
on-press
(fn []
(let [id @throttle-id]
(when (and id (not (get @throttle id)))
(swap! throttle assoc id true)
(on-press)
(js/setTimeout
#(swap! throttle dissoc id)
(or throttle-duration 500)))))))
(defn custom-pressable-props
[{:keys [on-press] :as props}]
(let [throttle-id (atom nil)]
(cond-> props
on-press
(assoc :on-press (throttled-on-press props throttle-id)
:ref (wrapped-ref props throttle-id)))))

View File

@ -5,22 +5,23 @@
[utils.re-frame :as rf]))
(defn contact-list-item
[{:keys [on-press on-long-press accessory]}
[{:keys [on-press on-long-press accessory allow-multiple-presses?]}
{:keys [primary-name secondary-name public-key compressed-key ens-verified added?]}
theme]
(let [photo-path (rf/sub [:chats/photo-path public-key])
online? (rf/sub [:visibility-status-updates/online? public-key])
customization-color (rf/sub [:profile/customization-color])]
[quo/user
{:customization-color customization-color
:theme theme
:short-chat-key (address/get-shortened-compressed-key (or compressed-key public-key))
:primary-name primary-name
:secondary-name secondary-name
:photo-path photo-path
:online? online?
:verified? ens-verified
:contact? added?
:on-press on-press
:on-long-press on-long-press
:accessory accessory}]))
{:customization-color customization-color
:allow-multiple-presses? allow-multiple-presses?
:theme theme
:short-chat-key (address/get-shortened-compressed-key (or compressed-key public-key))
:primary-name primary-name
:secondary-name secondary-name
:photo-path photo-path
:online? online?
:verified? ens-verified
:contact? added?
:on-press on-press
:on-long-press on-long-press
:accessory accessory}]))

View File

@ -4,7 +4,6 @@
[status-im.common.home.top-nav.style :as style]
[status-im.constants :as constants]
[status-im.contexts.profile.utils :as profile.utils]
[utils.debounce :refer [dispatch-and-chill]]
[utils.re-frame :as rf]))
(defn view
@ -36,7 +35,7 @@
{:avatar-on-press #(rf/dispatch [:open-modal :settings])
:scan-on-press #(js/alert "to be implemented")
:activity-center-on-press #(rf/dispatch [:activity-center/open])
:qr-code-on-press #(dispatch-and-chill [:open-modal :share-shell] 1000)
:qr-code-on-press #(rf/dispatch [:open-modal :share-shell])
:container-style (merge style/top-nav-container container-style)
:blur? blur?
:jump-to? jump-to?

View File

@ -23,7 +23,7 @@
:label (i18n/label :t/new-chat)
:on-press (fn []
(rf/dispatch [:group-chat/clear-contacts])
(debounce/dispatch-and-chill
(debounce/throttle-and-dispatch
[:open-modal :start-a-new-chat]
1000))}
{:icon :i/add-user
@ -31,6 +31,6 @@
:label (i18n/label :t/add-a-contact)
:sub-label (i18n/label :t/enter-chat-key)
:add-divider? true
:on-press #(debounce/dispatch-and-chill
:on-press #(debounce/throttle-and-dispatch
[:open-modal :new-contact]
1000)}]]])

View File

@ -79,10 +79,11 @@
(let [on-toggle #(group-chat-member-toggle member? (swap! checked? not) public-key)]
[contact-list-item/contact-list-item
(when (not= current-pk public-key)
{:on-press on-toggle
:accessory {:type :checkbox
:checked? @checked?
:on-check on-toggle}})
{:on-press on-toggle
:allow-multiple-presses? true
:accessory {:type :checkbox
:checked? @checked?
:on-check on-toggle}})
item]))))
(defn add-manage-members
@ -135,10 +136,11 @@
extra-data])}])]
[contact-list-item/contact-list-item
(when (not= public-key current-pk)
{:on-press #(rf/dispatch [:chat.ui/show-profile public-key])
:on-long-press show-profile-actions
:accessory {:type :options
:on-press show-profile-actions}})
{:on-press #(rf/dispatch [:chat.ui/show-profile public-key])
:allow-multiple-presses? true
:on-long-press show-profile-actions
:accessory {:type :options
:on-press show-profile-actions}})
item]))
(defn group-details

View File

@ -18,7 +18,7 @@
[chat-id]
(fn []
(rf/dispatch [:dismiss-keyboard])
(debounce/dispatch-and-chill [:chat/navigate-to-chat chat-id] 500)))
(debounce/throttle-and-dispatch [:chat/navigate-to-chat chat-id] 500)))
(defn parsed-text-to-one-line
[parsed-text]

View File

@ -57,10 +57,11 @@
(re-frame/dispatch [:deselect-contact public-key])
(re-frame/dispatch [:select-contact public-key]))]
[contact-list-item/contact-list-item
{:on-press on-toggle
:accessory {:type :checkbox
:checked? user-selected?
:on-check on-toggle}}
{:on-press on-toggle
:allow-multiple-presses? true
:accessory {:type :checkbox
:checked? user-selected?
:on-check on-toggle}}
item])))
(defn- view-internal

View File

@ -190,16 +190,17 @@
{:accessibility-label :audio-message-container
:style (style/container)}
[rn/touchable-opacity
{:accessibility-label :play-pause-audio-message-button
:on-press #(play-pause-player {:player-key player-key
:player-state player-state
:progress progress
:message-id message-id
:audio-duration-ms duration
:seeking-audio? seeking-audio?
:user-interaction? true
:mediaserver-port mediaserver-port})
:style (style/play-pause-container)}
{:accessibility-label :play-pause-audio-message-button
:allow-multiple-presses? true
:on-press #(play-pause-player {:player-key player-key
:player-state player-state
:progress progress
:message-id message-id
:audio-duration-ms duration
:seeking-audio? seeking-audio?
:user-interaction? true
:mediaserver-port mediaserver-port})
:style (style/play-pause-container)}
[quo/icon
(cond
(= @player-state :preparing)

View File

@ -26,8 +26,9 @@
[quo/communities-membership-list-item
{:customization-color customization-color
:style {:padding-horizontal 20}
:on-press #(debounce/dispatch-and-chill [:communities/navigate-to-community-overview id]
500)
:on-press #(debounce/throttle-and-dispatch [:communities/navigate-to-community-overview
id]
500)
:on-long-press #(rf/dispatch
[:show-bottom-sheet
{:content (fn []

View File

@ -199,7 +199,7 @@
(assoc :on-press (when joined-or-spectated
(fn []
(rf/dispatch [:dismiss-keyboard])
(debounce/dispatch-and-chill
(debounce/throttle-and-dispatch
[:communities/navigate-to-community-chat (str community-id id)]
1000)))
:on-long-press #(rf/dispatch

View File

@ -19,16 +19,16 @@
(reset! scan-sync-code/dismiss-animations reset-top-animation-fn))
:animations-duration constants/onboarding-modal-animation-duration
:animations-delay constants/onboarding-modal-animation-delay
:top-card {:on-press #(debounce/dispatch-and-chill [:open-modal
:sign-in-intro]
2000)
:top-card {:on-press #(debounce/throttle-and-dispatch [:open-modal
:sign-in-intro]
2000)
:heading (i18n/label :t/sign-in)
:animated-heading (i18n/label :t/sign-in-by-syncing)
:accessibility-label :already-use-status-button}
:bottom-card {:on-press (fn []
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
(blur-show-fn))
(debounce/dispatch-and-chill
(debounce/throttle-and-dispatch
[:open-modal :new-to-status]
1000))
:heading (i18n/label :t/new-to-status)
@ -45,7 +45,7 @@
:style style/plain-text}
(i18n/label :t/by-continuing-you-accept)]
[quo/text
{:on-press #(debounce/dispatch-and-chill [:open-modal :privacy-policy] 1000)
{:on-press #(debounce/throttle-and-dispatch [:open-modal :privacy-policy] 1000)
:size :paragraph-2
:weight :regular
:style style/highlighted-text}

View File

@ -31,7 +31,7 @@
(* 2 56) ;; two other list items
(* 2 16) ;; spacing between items
220) ;; extra spacing (top bar)
:on-press #(debounce/dispatch-and-chill
:on-press #(debounce/throttle-and-dispatch
[:onboarding/navigate-to-create-profile]
1000)}]
[rn/view {:style style/subtitle-container}

View File

@ -35,8 +35,8 @@
in-onboarding? (rf/dispatch [:navigate-back-to :sign-in-intro])
:else (do
(rf/dispatch [:navigate-back])
(debounce/dispatch-and-chill [:open-modal :sign-in]
1000))))
(debounce/throttle-and-dispatch [:open-modal :sign-in]
1000))))
:accessibility-label :try-again-later-button
:customization-color profile-color
:container-style style/try-again-button}

View File

@ -50,13 +50,13 @@
:on-press (fn []
(when @push-animation-fn-atom
(@push-animation-fn-atom))
(debounce/dispatch-and-chill
(debounce/throttle-and-dispatch
[:open-modal :new-to-status]
1000))
:accessibility-label :create-new-profile}
{:icon :i/multi-profile
:label (i18n/label :t/add-existing-status-profile)
:on-press #(debounce/dispatch-and-chill
:on-press #(debounce/throttle-and-dispatch
[:open-modal :sign-in]
1000)
:accessibility-label :multi-profile}]]])

View File

@ -56,7 +56,7 @@
:on-press #(rf/dispatch [:navigate-back])
:right-side [{:icon-name :i/multi-profile :on-press #(rf/dispatch [:open-modal :sign-in])}
{:icon-name :i/qr-code
:on-press #(debounce/dispatch-and-chill [:open-modal :share-shell] 1000)}
:on-press #(debounce/throttle-and-dispatch [:open-modal :share-shell] 1000)}
{:icon-name :i/share :on-press not-implemented/alert}]}]]
[rn/flat-list
{:key :list
@ -74,7 +74,7 @@
:jump-to
{:on-press (fn []
(rf/dispatch [:navigate-back])
(debounce/dispatch-and-chill [:shell/navigate-to-jump-to] 500))
(debounce/throttle-and-dispatch [:shell/navigate-to-jump-to] 500))
:customization-color customization-color
:label (i18n/label :t/jump-to)}}
{:position :absolute

View File

@ -22,15 +22,15 @@
(clear event-key)
(swap! timeout assoc event-key (js/setTimeout #(re-frame/dispatch event) duration-ms))))
(def chill (atom {}))
(def throttle (atom {}))
(defn dispatch-and-chill
(defn throttle-and-dispatch
"Dispatches event and ignores subsequent calls for the duration of `duration-ms`."
[event duration-ms]
(let [event-key (first event)]
(when-not (get @chill event-key)
(swap! chill assoc event-key true)
(js/setTimeout #(swap! chill assoc event-key false) duration-ms)
(when-not (get @throttle event-key)
(swap! throttle assoc event-key true)
(js/setTimeout #(swap! throttle dissoc event-key) duration-ms)
(re-frame/dispatch event))))
(defn debounce