diff --git a/src/components/Slider/Slider.js b/src/components/Slider/Slider.js index 9425ab6083..918dbc79ca 100644 --- a/src/components/Slider/Slider.js +++ b/src/components/Slider/Slider.js @@ -8,7 +8,7 @@ const useAnimationFrame = require('stremio/common/useAnimationFrame'); const useLiveRef = require('stremio/common/useLiveRef'); const styles = require('./styles'); -const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabled, onSlide, onComplete, audioBoost }) => { +const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabled, onSlide, onComplete, audioBoost, stepValue }) => { const minimumValueRef = useLiveRef(minimumValue !== null && !isNaN(minimumValue) ? minimumValue : 0); const maximumValueRef = useLiveRef(maximumValue !== null && !isNaN(maximumValue) ? maximumValue : 100); const valueRef = useLiveRef(value !== null && !isNaN(value) ? Math.min(maximumValueRef.current, Math.max(minimumValueRef.current, value)) : 0); @@ -26,7 +26,8 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl const { x: sliderX, width: sliderWidth } = sliderContainerRef.current.getBoundingClientRect(); const thumbStart = Math.min(Math.max(mouseX - sliderX, 0), sliderWidth); const value = (thumbStart / sliderWidth) * (maximumValueRef.current - minimumValueRef.current) + minimumValueRef.current; - return value; + const noramlizedValue = stepValue ? parseFloat((Math.round(value / stepValue) * stepValue).toFixed(2)) : value; + return noramlizedValue; }, []); const retainThumb = React.useCallback(() => { window.addEventListener('blur', onBlur); @@ -158,6 +159,7 @@ Slider.propTypes = { buffered: PropTypes.number, minimumValue: PropTypes.number, maximumValue: PropTypes.number, + stepValue: PropTypes.number, disabled: PropTypes.bool, onSlide: PropTypes.func, onComplete: PropTypes.func, diff --git a/src/routes/Player/SpeedMenu/SpeedMenu.js b/src/routes/Player/SpeedMenu/SpeedMenu.js index 501020e362..b1d927205e 100644 --- a/src/routes/Player/SpeedMenu/SpeedMenu.js +++ b/src/routes/Player/SpeedMenu/SpeedMenu.js @@ -4,38 +4,55 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); -const Option = require('./Option'); -const styles = require('./styles'); +const Button = require('stremio/components/Button').default; +const Slider = require('stremio/components/Slider'); -const RATES = Array.from(Array(8).keys(), (n) => n * 0.25 + 0.25).reverse(); +const styles = require('./styles'); +const RATES = Array.from(Array(8).keys(), (n) => n * 0.25 + 0.25); const SpeedMenu = React.memo(React.forwardRef(({ className, playbackSpeed, onPlaybackSpeedChanged }, ref) => { const { t } = useTranslation(); const onMouseDown = React.useCallback((event) => { event.nativeEvent.speedMenuClosePrevented = true; }, []); - const onOptionSelect = React.useCallback((value) => { + const onSpeedChanged = React.useCallback((value) => { if (typeof onPlaybackSpeedChanged === 'function') { onPlaybackSpeedChanged(value); } - }, [onPlaybackSpeedChanged]); + }, [onPlaybackSpeedChanged, playbackSpeed]); + return (
{ t('PLAYBACK_SPEED') }
-
- { - RATES.map((rate) => ( -
); diff --git a/src/routes/Player/SpeedMenu/styles.less b/src/routes/Player/SpeedMenu/styles.less index c2a694629d..243ae7cf5f 100644 --- a/src/routes/Player/SpeedMenu/styles.less +++ b/src/routes/Player/SpeedMenu/styles.less @@ -2,24 +2,99 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; +:import('~stremio/components/Slider/styles.less') { + slider-track-after: track-after; + slider-thumb: thumb; +} + .speed-menu-container { - width: 14rem; + width: 30rem; + max-width: 100%; + display: flex; + flex-direction: column; .title { flex: none; align-self: stretch; font-weight: 700; color: var(--primary-foreground-color); - padding: 1.5rem 2rem; + padding: 1rem; + text-align: center; } - .options-container { - flex: 0 1 auto; - max-height: calc(3.2rem * 10); - padding: 0 1rem 0.5rem; - - .option { - height: 3.2rem; + .main-container { + display: flex; + flex-direction: column; + flex: 1; + padding-bottom: 1rem; + + .options-container { + display: flex; + justify-content: center; + flex-wrap: wrap; + + .speed-button { + color: var(--primary-foreground-color); + padding: 0.2rem 0.75rem; + border-radius: var(--border-radius); + transition: background-color 150ms ease, color 150ms ease; + + &:hover, &:focus { + background-color: var(--overlay-color); + } + + &.active { + background-color: var(--overlay-color); + color: @color-secondaryvariant1-light4; + font-weight: 700; + } + } + } + + .top-container { + display: flex; + flex-direction: column; + flex: none; + min-height: 3rem; + gap: 0.5rem; + padding: 0.5rem 0; + + .speed-title { + font-weight: 700; + color: var(--primary-foreground-color); + text-align: center; + } + } + + .slider { + --track-size: 0.35rem; + --thumb-size: 1rem; + + flex: none; + min-height: calc(var(--thumb-size) * 2); + align-self: stretch; + margin: 0.5rem var(--thumb-size) 0; + position: relative; + + .slider-thumb { + background-color: @color-secondaryvariant1-light4; + transition: transform 150ms ease; + + &:after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + border-radius: 100%; + box-shadow: 0 0 0 0.25rem white inset; + } + } + + &:hover .slider-thumb { + transform: translateX(-50%) scale(1.2); + } } } } \ No newline at end of file