From aa96fd27cc73c7ec11282f86b6dfc8bb15b42a0b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 8 Apr 2019 10:53:09 -0600 Subject: [PATCH] Add some tolerances to breadcrumb scrolling See https://github.com/vector-im/riot-web/issues/9400 See https://github.com/vector-im/riot-web/issues/9394 Tolerances are defined as a device-only setting to give advanced users an option to override the values. No UI is exposed for this. The default values are picked for assumptions on comfort, however as people change the tolerances themselves the defaults may need to change. --- .../structures/IndicatorScrollbar.js | 21 ++++++++++++++++++- src/components/views/rooms/RoomBreadcrumbs.js | 11 ++++++++-- src/settings/Settings.js | 7 +++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js index 76e6dfa96a..2470f9fa11 100644 --- a/src/components/structures/IndicatorScrollbar.js +++ b/src/components/structures/IndicatorScrollbar.js @@ -29,6 +29,13 @@ export default class IndicatorScrollbar extends React.Component { // scroll horizontally rather than vertically. This should only be used on components // with no vertical scroll opportunity. verticalScrollsHorizontally: PropTypes.bool, + + // An object containing 2 numbers: xyThreshold and yReduction. xyThreshold is the amount + // of horizontal movement required in order to ignore any vertical changes in scroll, and + // only applies when verticalScrollsHorizontally is true. yReduction is the factor to + // multiply the vertical delta by when verticalScrollsHorizontally is true. The default + // behaviour is to have an xyThreshold of infinity and a yReduction of 0.8 + scrollTolerances: PropTypes.object, }; constructor(props) { @@ -120,8 +127,20 @@ export default class IndicatorScrollbar extends React.Component { onMouseWheel = (e) => { if (this.props.verticalScrollsHorizontally && this._scrollElement) { + const xyThreshold = this.props.scrollTolerances + ? this.props.scrollTolerances.xyThreshold + : Number.MAX_SAFE_INTEGER; + + const yReduction = this.props.scrollTolerances + ? this.props.scrollTolerances.yReduction + : 0.8; + + // Don't apply vertical motion to horizontal scrolls. This is meant to eliminate + // trackpads causing excessive scroll motion. + if (e.deltaX >= xyThreshold) return; + // noinspection JSSuspiciousNameCombination - this._scrollElement.scrollLeft += e.deltaY / 2; // divide by 2 to reduce harshness + this._scrollElement.scrollLeft += e.deltaY * yReduction; } }; diff --git a/src/components/views/rooms/RoomBreadcrumbs.js b/src/components/views/rooms/RoomBreadcrumbs.js index a45b8f257f..2f2df42a1b 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.js +++ b/src/components/views/rooms/RoomBreadcrumbs.js @@ -33,7 +33,13 @@ const MAX_ROOMS = 20; export default class RoomBreadcrumbs extends React.Component { constructor(props) { super(props); - this.state = {rooms: []}; + + const tolerances = SettingsStore.getValue("breadcrumb_scroll_tolerances"); + this.state = {rooms: [], scrollTolerances: tolerances}; + + // Record this for debugging purposes + console.log("Breadcrumbs scroll tolerances:", tolerances); + this.onAction = this.onAction.bind(this); this._dispatcherRef = null; } @@ -334,7 +340,8 @@ export default class RoomBreadcrumbs extends React.Component { }); return ( + trackHorizontalOverflow={true} verticalScrollsHorizontally={true} + scrollTolerances={this.state.scrollTolerances}> { avatars } ); diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 35baa718b9..dcd6f91aef 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -262,6 +262,13 @@ export const SETTINGS = { supportedLevels: ['account'], default: [], }, + "breadcrumb_scroll_tolerances": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + default: { + xyThreshold: 10, + yReduction: 0.8, + }, + }, "analyticsOptIn": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, displayName: _td('Send analytics data'),