diff --git a/src/lib/viewers/controls/media/TimeControlsV2.tsx b/src/lib/viewers/controls/media/TimeControlsV2.tsx index 0541532ca..cb28b8245 100644 --- a/src/lib/viewers/controls/media/TimeControlsV2.tsx +++ b/src/lib/viewers/controls/media/TimeControlsV2.tsx @@ -1,7 +1,7 @@ import React from 'react'; import isFinite from 'lodash/isFinite'; import noop from 'lodash/noop'; -import { bdlGray65, white } from 'box-ui-elements/es/styles/variables'; +import { white } from 'box-ui-elements/es/styles/variables'; import buildClusters from './buildClusters'; import FilmstripV2 from './FilmstripV2'; import MarkerCluster from './MarkerCluster'; @@ -11,8 +11,12 @@ import { CommentMarker } from './types'; import { percent } from './utils'; import './TimeControlsV2.scss'; +const TRACK_COLOR_BUFFERED = 'rgb(127, 127, 127)'; +const TRACK_COLOR_UNPLAYED = 'rgb(85, 85, 85)'; + export type Props = { aspectRatio?: number; + bufferedRange?: TimeRanges; commentMarkers?: CommentMarker[]; currentTime?: number; durationTime?: number; @@ -25,6 +29,7 @@ export type Props = { export default function TimeControlsV2({ aspectRatio, + bufferedRange, commentMarkers = [], currentTime = 0, durationTime = 0, @@ -43,6 +48,8 @@ export default function TimeControlsV2({ const currentValue = isFinite(currentTime) ? currentTime : 0; const durationValue = isFinite(durationTime) ? durationTime : 0; const currentPercentage = percent(currentValue, durationValue); + const bufferedAmount = bufferedRange && bufferedRange.length ? bufferedRange.end(bufferedRange.length - 1) : 0; + const bufferedPercentage = percent(bufferedAmount, durationValue); React.useLayoutEffect(() => { const el = scrubberRef.current; @@ -124,7 +131,7 @@ export default function TimeControlsV2({ onUpdate={onTimeChange} step={fps ? 1 / fps : 5} title={__('media_time_slider')} - track={`linear-gradient(to right, ${white} calc(${currentPercentage}% - 2.5px), transparent calc(${currentPercentage}% - 2.5px), transparent calc(${currentPercentage}% + 2.5px), ${bdlGray65} calc(${currentPercentage}% + 2.5px), ${bdlGray65} 100%)`} + track={`linear-gradient(to right, ${white} calc(${currentPercentage}% - 2.5px), transparent calc(${currentPercentage}% - 2.5px), transparent calc(${currentPercentage}% + 2.5px), ${TRACK_COLOR_BUFFERED} calc(${currentPercentage}% + 2.5px), ${TRACK_COLOR_BUFFERED} ${bufferedPercentage}%, ${TRACK_COLOR_UNPLAYED} ${bufferedPercentage}%, ${TRACK_COLOR_UNPLAYED} 100%)`} value={currentValue} /> {durationValue > 0 && diff --git a/src/lib/viewers/controls/media/__tests__/TimeControlsV2-test.tsx b/src/lib/viewers/controls/media/__tests__/TimeControlsV2-test.tsx index fff8ff24e..bca69e2d1 100644 --- a/src/lib/viewers/controls/media/__tests__/TimeControlsV2-test.tsx +++ b/src/lib/viewers/controls/media/__tests__/TimeControlsV2-test.tsx @@ -2,8 +2,21 @@ import React from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import { userEvent } from '@testing-library/user-event'; import TimeControlsV2 from '../TimeControlsV2'; +import SliderControl from '../../slider/SliderControl'; import { CommentMarker } from '../types'; +jest.mock('../../slider/SliderControl', () => { + return jest.fn(props => ( +
+
+
+ )); +}); + const mockResizeObserver = jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), @@ -148,6 +161,36 @@ describe('TimeControlsV2', () => { }); }); + describe('buffered range', () => { + const createMockBufferedRange = (end: number): TimeRanges => ({ + length: 1, + start: () => 0, + end: () => end, + }); + + test('should render buffered and unplayed colors in track gradient', () => { + render( + , + ); + const trackProp = (SliderControl as jest.Mock).mock.calls.at(-1)[0].track as string; + expect(trackProp).toContain('rgb(127, 127, 127)'); + expect(trackProp).toContain('rgb(85, 85, 85)'); + expect(trackProp).toContain('50%'); + }); + + test('should default to 0% buffered when bufferedRange is undefined', () => { + render(); + const trackProp = (SliderControl as jest.Mock).mock.calls.at(-1)[0].track as string; + expect(trackProp).toContain('rgb(127, 127, 127)'); + expect(trackProp).toContain('rgb(85, 85, 85)'); + }); + }); + describe('track mask', () => { test('should not set --bp-track-mask when there are no markers', () => { const { container } = render(); diff --git a/src/lib/viewers/media/DashViewer.js b/src/lib/viewers/media/DashViewer.js index 9eb600fc2..2d1f4feb4 100644 --- a/src/lib/viewers/media/DashViewer.js +++ b/src/lib/viewers/media/DashViewer.js @@ -1279,6 +1279,7 @@ class DashViewer extends VideoBaseViewer { audioTrack: this.selectedAudioTrack, audioTracks: this.audioTracks, autoplay: this.isAutoplayEnabled(), + bufferedRange: this.mediaEl.buffered, currentTime: this.mediaEl.currentTime, durationTime: this.mediaEl.duration, experiences: this.experiences, @@ -1333,14 +1334,7 @@ class DashViewer extends VideoBaseViewer { return; } - this.controls.render( - , - ); + this.controls.render(); } } diff --git a/src/lib/viewers/media/VideoControlsV2.scss b/src/lib/viewers/media/VideoControlsV2.scss index cd5361ce4..24f0b738e 100644 --- a/src/lib/viewers/media/VideoControlsV2.scss +++ b/src/lib/viewers/media/VideoControlsV2.scss @@ -23,6 +23,7 @@ @include bp-VideoControls; padding: 30px 48px 20px 48px; + background: linear-gradient(to top, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); pointer-events: auto; } diff --git a/src/lib/viewers/media/VideoControlsV2.tsx b/src/lib/viewers/media/VideoControlsV2.tsx index db1c6f6c0..2738b1c73 100644 --- a/src/lib/viewers/media/VideoControlsV2.tsx +++ b/src/lib/viewers/media/VideoControlsV2.tsx @@ -49,6 +49,7 @@ export default function VideoControlsV2({ audioTrack, audioTracks, autoplay, + bufferedRange, commentMarkers, currentTime = 0, durationTime = 0, @@ -108,6 +109,7 @@ export default function VideoControlsV2({