Skip to content

Commit

Permalink
feat: add an option to handle smooth seeking
Browse files Browse the repository at this point in the history
Adds a player option called enableSmoothSeeking, which is false by default,
to provide a smoother seeking experience on mobile and desktop devices.

Usage:
```javascript
// Enables the smooth seeking
const player = videojs('player', {enableSmoothSeeking: true});

// Disable the smooth seeking
player.options({enableSmoothSeeking: false});
```

- **player.js** add an `option` called `enableSmoothSeeking`
- **time-display.js** add a listener to the `seeking` event if `enableSmoothSeeking` is `true` allowing to update the `CurrentTimeDisplay` and `RemainingTimeDisplay` in real time
- **seek-bar.js** `update` the seek bar on `mousemove` event  if `enableSmoothSeeking` is `true`
- add test cases
  • Loading branch information
amtins committed Nov 29, 2023
1 parent 9c6225b commit 5b8b883
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/js/control-bar/progress-control/seek-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ class SeekBar extends Slider {

// Set new time (tell player to seek to new time)
this.userSeek_(newTime);

if (this.player_.options_.enableSmoothSeeking) {
this.update();
}
}

enable() {
Expand Down
16 changes: 15 additions & 1 deletion src/js/control-bar/time-controls/time-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class TimeDisplay extends Component {
constructor(player, options) {
super(player, options);

this.on(player, ['timeupdate', 'ended'], (e) => this.updateContent(e));
this.on(player, ['timeupdate', 'ended', 'seeking'], (e) => this.update(e));
this.updateTextNode_();
}

Expand Down Expand Up @@ -71,6 +71,20 @@ class TimeDisplay extends Component {
super.dispose();
}

/**
* Updates the displayed time according to the `updateContent` function which is defined in the child class.
*
* @param {Event} [event]
* The `timeupdate`, `ended` or `seeking` (if enableSmoothSeeking is true) event that caused this function to be called.
*/
update(event) {
if (!this.player_.options_.enableSmoothSeeking && event.type === 'seeking') {
return;
}

this.updateContent(event);
}

/**
* Updates the time display text node with a new time
*
Expand Down
4 changes: 3 additions & 1 deletion src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -5316,7 +5316,9 @@ Player.prototype.options_ = {
breakpoints: {},
responsive: false,
audioOnlyMode: false,
audioPosterMode: false
audioPosterMode: false,
// Default smooth seeking to false
enableSmoothSeeking: false
};

[
Expand Down
63 changes: 63 additions & 0 deletions test/unit/player.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3419,3 +3419,66 @@ QUnit.test('should not reset the error when the tech triggers an error that is n
errorStub.restore();
log.error.restore();
});

QUnit.test('smooth seeking set to false should not update the display time components or the seek bar', function(assert) {
const player = TestHelpers.makePlayer({});
const {
currentTimeDisplay,
remainingTimeDisplay,
progressControl: {
seekBar
}
} = player.controlBar;
const currentTimeDisplayUpdateContent = sinon.spy(currentTimeDisplay, 'updateContent');
const remainingTimeDisplayUpdateContent = sinon.spy(remainingTimeDisplay, 'updateContent');
const seekBarUpdate = sinon.spy(seekBar, 'update');

assert.false(player.options().enableSmoothSeeking, 'enableSmoothSeeking is false by default');

player.trigger('seeking');

assert.ok(currentTimeDisplayUpdateContent.notCalled, 'currentTimeDisplay updateContent was not called');
assert.ok(remainingTimeDisplayUpdateContent.notCalled, 'remainingTimeDisplay updateContent was not called');

seekBar.trigger('mousedown');
seekBar.trigger('mousemove');

assert.ok(seekBarUpdate.notCalled, 'seekBar update was not called');

currentTimeDisplayUpdateContent.restore();
remainingTimeDisplayUpdateContent.restore();
seekBarUpdate.restore();
player.dispose();
});

QUnit.test('smooth seeking set to true should update the display time components and the seek bar', function(assert) {
const player = TestHelpers.makePlayer({enableSmoothSeeking: true});
const {
currentTimeDisplay,
remainingTimeDisplay,
progressControl: {
seekBar
}
} = player.controlBar;
const currentTimeDisplayUpdateContent = sinon.spy(currentTimeDisplay, 'updateContent');
const remainingTimeDisplayUpdateContent = sinon.spy(remainingTimeDisplay, 'updateContent');
const seekBarUpdate = sinon.spy(seekBar, 'update');

assert.true(player.options().enableSmoothSeeking, 'enableSmoothSeeking is true');

player.duration(1);
player.trigger('seeking');

assert.ok(currentTimeDisplayUpdateContent.called, 'currentTimeDisplay updateContent was called');
assert.ok(remainingTimeDisplayUpdateContent.called, 'remainingTimeDisplay updateContent was called');

seekBar.trigger('mousedown');
seekBar.trigger('mousemove');

assert.ok(seekBarUpdate.called, 'seekBar update was called');

currentTimeDisplayUpdateContent.restore();
remainingTimeDisplayUpdateContent.restore();
seekBarUpdate.restore();
player.dispose();
});

0 comments on commit 5b8b883

Please sign in to comment.