Skip to content

Commit

Permalink
feat(focus-screen): adding focus-screen component to overcome tabinde…
Browse files Browse the repository at this point in the history
…x issue when mainUI is hidden
  • Loading branch information
BrooklynKing committed Oct 11, 2023
1 parent 7ccaf82 commit 46cc374
Show file tree
Hide file tree
Showing 16 changed files with 538 additions and 214 deletions.
2 changes: 2 additions & 0 deletions src/core/default-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import KeyboardControls from '../modules/keyboard-control/keyboard-control';
import DebugPanel from '../modules/ui/debug-panel/debug-panel';

import Screen, { IScreenAPI } from '../modules/ui/screen/screen';
import FocusScreen from '../modules/ui/focus-screen/focus-screen';
import InteractionIndicator from '../modules/ui/interaction-indicator/interaction-indicator';

import Overlay, { IOverlayAPI } from '../modules/ui/overlay/overlay';
Expand Down Expand Up @@ -99,6 +100,7 @@ export const modules: { [id: string]: any } = {
DebugPanel,

Screen,
FocusScreen,
InteractionIndicator,

Overlay,
Expand Down
10 changes: 5 additions & 5 deletions src/modules/keyboard-control/keyboard-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import { IEventEmitter } from '../event-emitter/types';
import { IPlaybackEngine } from '../playback-engine/types';
import { IPlayerConfig } from '../../core/config';
import { IKeyboardControl } from './types';
import { IRootContainer } from '../root-container/types';
import { ListenerFn } from 'eventemitter3';
import { IFocusScreen } from '../ui/focus-screen/types';

export const AMOUNT_TO_SKIP_SECONDS = 5;
export const AMOUNT_TO_CHANGE_VOLUME = 10;

export default class KeyboardControl implements IKeyboardControl {
static moduleName = 'keyboardControl';
static dependencies = ['engine', 'eventEmitter', 'rootContainer', 'config'];
static dependencies = ['engine', 'eventEmitter', 'focusScreen', 'config'];

private _isEnabled: boolean;
private _eventEmitter: IEventEmitter;
Expand All @@ -32,12 +32,12 @@ export default class KeyboardControl implements IKeyboardControl {
constructor({
config,
eventEmitter,
rootContainer,
focusScreen,
engine,
}: {
config: IPlayerConfig;
eventEmitter: IEventEmitter;
rootContainer: IRootContainer;
focusScreen: IFocusScreen;
engine: IPlaybackEngine;
}) {
this._eventEmitter = eventEmitter;
Expand All @@ -49,7 +49,7 @@ export default class KeyboardControl implements IKeyboardControl {
this._isEnabled = config.disableControlWithKeyboard !== false;
}

this._initInterceptor(rootContainer.getElement());
this._initInterceptor(focusScreen.getElement());
}

private _initInterceptor(rootElement: HTMLElement) {
Expand Down
1 change: 0 additions & 1 deletion src/modules/root-container/templates/container.dot
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
data-playable-hook="player-container"
dir="ltr"
data-playable-dir="${props.direction}"
tabindex="0"
class="${props.styles.container}">
</div>
25 changes: 25 additions & 0 deletions src/modules/ui/focus-screen/focus-screen.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@import '../shared';

.focusScreen {
position: absolute;
z-index: 51;
top: 0;
right: 0;
bottom: 0;
left: 0;

display: flex;
flex-direction: column;

width: 100%;
height: 100%;

opacity: 1;

justify-content: center;
align-items: center;

&.hiddenCursor {
cursor: none;
}
}
118 changes: 118 additions & 0 deletions src/modules/ui/focus-screen/focus-screen.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import 'jsdom-global/register';
import { expect } from 'chai';
import * as sinon from 'sinon';

import { EngineState } from '../../../constants';

import createPlayerTestkit from '../../../testkit';

import FocusScreen from './focus-screen';
class FullScreenManagerMock {
enterFullScreen = (_: any) => _;
exitFullScreen = (_: any) => _;
isInFullScreen = false;
isEnabled = true;
_config = {};
}

describe('Loader', () => {
let testkit: any;
let screen: any;
let engine: any;
let fullScreenManager: any;

beforeEach(() => {
testkit = createPlayerTestkit();
testkit.registerModuleAsSingleton(
'fullScreenManager',
FullScreenManagerMock,
);
testkit.registerModule('focus-screen', FocusScreen);
engine = testkit.getModule('engine');
fullScreenManager = testkit.getModule('fullScreenManager');
screen = testkit.getModule('focus-screen');
});

describe('constructor', () => {
it('should create instance ', () => {
expect(screen).to.exist;
expect(screen.view).to.exist;
});
});

describe('instance callbacks', () => {
it('should trigger _toggleVideoPlayback on node click', () => {
const processClickSpy = sinon.spy(screen, '_processClick');
screen._bindCallbacks();
screen._initUI();

screen.view.getElement().dispatchEvent(new Event('click'));
expect(processClickSpy.called).to.be.true;
});

it('should remove timeout of delayed playback change on _processClick and call _toggleFullScreen on _processDblClick', () => {
const timeoutClearSpy = sinon.spy<Window, 'clearTimeout'>(
window,
'clearTimeout',
);
const toggleFullScreenSpy = sinon.spy(screen, '_toggleFullScreen');
const id = window.setTimeout(() => {}, 0);
screen._delayedToggleVideoPlaybackTimeout = id;

screen._processClick();
expect(timeoutClearSpy.calledWith(id)).to.be.true;
screen._processDblClick();
expect(toggleFullScreenSpy.called).to.be.true;

timeoutClearSpy.restore();
});

it('should add native controls if config passed', () => {
testkit.setConfig({
nativeBrowserControls: true,
});

const video: any = document.createElement('video');

video.setAttribute = sinon.spy();

engine.getElement = () => video;

screen = testkit.getModule('screen');

expect(video.setAttribute.calledWith('controls', 'true')).to.be.true;
});

it('should emit ui event on enter full screen', () => {
const spy = sinon.spy(fullScreenManager, 'enterFullScreen');
fullScreenManager.isInFullScreen = false;

screen._toggleFullScreen();

expect(spy.called).to.be.true;
fullScreenManager.enterFullScreen.restore();
});

it('should emit ui event on exit full screen', () => {
const spy = sinon.spy(fullScreenManager, 'exitFullScreen');
fullScreenManager.isInFullScreen = true;

screen._toggleFullScreen();

expect(spy.called).to.be.true;
fullScreenManager.exitFullScreen.restore();
});

it('should have method for toggling playback', () => {
const playSpy = sinon.spy();
const pauseSpy = sinon.spy();
screen._engine = {
getCurrentState: () => EngineState.PLAYING,
play: playSpy,
pause: pauseSpy,
};
screen._toggleVideoPlayback();
expect(pauseSpy.called).to.be.true;
});
});
});
Loading

0 comments on commit 46cc374

Please sign in to comment.