Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smart TV support #40

Merged
merged 49 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
1fc1a06
Add toggleAttribute helper
MattiasBuelens Apr 6, 2023
f006970
Add device-type attribute
MattiasBuelens Apr 6, 2023
23d3668
Add 'tv' device type
MattiasBuelens Apr 6, 2023
e5b2b04
Add device type to state receivers
MattiasBuelens Apr 6, 2023
f5fcfab
Simplify
MattiasBuelens Apr 6, 2023
80cdfca
Sort key codes
MattiasBuelens Apr 6, 2023
12e00ac
Add keyboard navigation for TVs
MattiasBuelens Apr 7, 2023
7241eaa
Snap to pixels before comparing client rectangles
MattiasBuelens Apr 7, 2023
beff653
Handle keyboard navigation in radio groups
MattiasBuelens Apr 7, 2023
04dbde4
Tiny fix
MattiasBuelens Apr 7, 2023
d8f88c6
Allow partial overlap when looking for a keyboard navigation target
MattiasBuelens Apr 7, 2023
f435306
Only allow left/right arrow keys to move the Range slider on TV devices
MattiasBuelens Apr 7, 2023
8dc562b
Fix preview time display no longer updating
MattiasBuelens Apr 7, 2023
c9e5f1f
Add dropdown to override device type in example
MattiasBuelens May 23, 2023
539c537
Hide unused elements on tv
Jeroen-Veltmans Sep 13, 2023
d84732e
TV play pause using seekbar
Jeroen-Veltmans Sep 14, 2023
21f738d
Stop event propagation when button is pressed
Jeroen-Veltmans Sep 21, 2023
4880623
Listen to keydown event on the window instead
Jeroen-Veltmans Sep 21, 2023
d5452c0
Only update if value is different
Jeroen-Veltmans Oct 3, 2023
36788f1
Handle TV back button
Jeroen-Veltmans Oct 3, 2023
b0627d1
Increase default tv idle timeout
Jeroen-Veltmans Oct 3, 2023
6a4918e
Only collect visible focusable children
Jeroen-Veltmans Oct 3, 2023
3812038
Improve getting active element during navigation
Jeroen-Veltmans Oct 3, 2023
ca0790e
Update menus TV layout
Jeroen-Veltmans Oct 4, 2023
47ddb64
Extract getFocusedChild
Jeroen-Veltmans Oct 5, 2023
e79b22a
Handle key inputs only when UI is visible
Jeroen-Veltmans Oct 10, 2023
5d3b79b
Check multiple BACK key codes
Jeroen-Veltmans Oct 5, 2023
0d72630
Close menu on back key press
Jeroen-Veltmans Oct 5, 2023
a5bfcce
Play from first OK press on tv
Jeroen-Veltmans Oct 10, 2023
d4fd5df
Add more back key codes
Jeroen-Veltmans Oct 11, 2023
cc1c24f
Return HTML element
Jeroen-Veltmans Oct 11, 2023
dfad370
Blur focused child when idle
Jeroen-Veltmans Oct 11, 2023
a6167e6
Do not focus when pressing back key
Jeroen-Veltmans Oct 11, 2023
252b96f
Fix possible TypeError
Jeroen-Veltmans Oct 12, 2023
c8ac8ce
Optimize getActiveElement slightly
MattiasBuelens Oct 17, 2023
5a242fc
Add keydown listener only on TVs
MattiasBuelens Oct 17, 2023
7df63e7
Remove check
MattiasBuelens Oct 17, 2023
111671c
Fix indentation
MattiasBuelens Oct 17, 2023
1902c9b
Extract variable
MattiasBuelens Oct 17, 2023
fffd993
Tweak check
MattiasBuelens Oct 17, 2023
af92e47
Remove non-null assertion
Jeroen-Veltmans Oct 19, 2023
71da703
Move setting focus outside getFocusedChild
Jeroen-Veltmans Oct 19, 2023
9e87261
Allow setting a default focused child for TV
Jeroen-Veltmans Oct 19, 2023
260a3e7
Optimize import
Jeroen-Veltmans Nov 2, 2023
fc0ee13
Expose DeviceType
MattiasBuelens Nov 3, 2023
e2fbdf7
Hide fullscreen button on TV
Jeroen-Veltmans Nov 3, 2023
0420f20
Set device type on default UI
MattiasBuelens Nov 3, 2023
5ea8d98
Add tv-only and tv-hidden attributes
MattiasBuelens Nov 3, 2023
5041068
Update changelog
MattiasBuelens Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions docs/examples/custom-ui.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,6 @@
<script>
var ui = document.querySelector('theoplayer-ui');
document.querySelector('#mobile-toggle').addEventListener('change', function (ev) {
if (ev.target.checked) {
ui.setAttribute('mobile', '');
} else {
ui.removeAttribute('mobile');
}
ui.setAttribute('device-type', ev.target.checked ? 'mobile' : 'desktop');
});
</script>
19 changes: 13 additions & 6 deletions docs/examples/default-ui.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,22 @@
<span slot="title">Elephant's Dream</span>
</theoplayer-default-ui>
<p>
<label style="user-select: none"><input type="checkbox" id="mobile-toggle" /> Mobile</label>
<label style="user-select: none">
Override device type
<select id="device-type-select">
<option value=""></option>
<option value="desktop">Desktop</option>
<option value="mobile">Mobile</option>
<option value="tv">TV</option>
</select>
</label>
</p>
<script>
var ui = document.querySelector('theoplayer-default-ui');
document.querySelector('#mobile-toggle').addEventListener('change', function (ev) {
if (ev.target.checked) {
ui.setAttribute('mobile', '');
} else {
ui.removeAttribute('mobile');
document.querySelector('#device-type-select').addEventListener('change', function (ev) {
var selectedDeviceType = ev.target.value;
if (selectedDeviceType) {
ui.setAttribute('device-type', selectedDeviceType);
}
});
</script>
8 changes: 8 additions & 0 deletions src/DefaultUI.css
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ theoplayer-ad-skip-button:not([disabled]) {
display: none !important;
}

/*
* Tv-hidden elements
*/
theoplayer-ui[tv] [tv-hidden],
theoplayer-ui[tv] theoplayer-control-bar ::slotted([tv-hidden]) {
display: none !important;
}

/*
* Live-only and live-hidden elements
*/
Expand Down
8 changes: 4 additions & 4 deletions src/DefaultUI.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@
</theoplayer-control-bar>
<theoplayer-control-bar ad-hidden>
<theoplayer-play-button mobile-hidden></theoplayer-play-button>
<theoplayer-mute-button></theoplayer-mute-button>
<theoplayer-volume-range mobile-hidden></theoplayer-volume-range>
<theoplayer-mute-button tv-hidden></theoplayer-mute-button>
<theoplayer-volume-range mobile-hidden tv-hidden></theoplayer-volume-range>
<theoplayer-live-button live-only ad-hidden></theoplayer-live-button>
<theoplayer-time-display show-duration remaining-when-live></theoplayer-time-display>
<span class="theoplayer-spacer" style="pointer-events: auto"></span>
<theoplayer-language-menu-button menu="language-menu" mobile-hidden ad-hidden></theoplayer-language-menu-button>
<theoplayer-airplay-button mobile-hidden ad-hidden></theoplayer-airplay-button>
<theoplayer-chromecast-button mobile-hidden ad-hidden></theoplayer-chromecast-button>
<theoplayer-airplay-button tv-hidden mobile-hidden ad-hidden></theoplayer-airplay-button>
<theoplayer-chromecast-button tv-hidden mobile-hidden ad-hidden></theoplayer-chromecast-button>
<slot name="bottom-control-bar"></slot>
<theoplayer-fullscreen-button></theoplayer-fullscreen-button>
MattiasBuelens marked this conversation as resolved.
Show resolved Hide resolved
</theoplayer-control-bar>
Expand Down
41 changes: 16 additions & 25 deletions src/DefaultUI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import defaultUiCss from './DefaultUI.css';
import defaultUiHtml from './DefaultUI.html';
import { Attribute } from './util/Attribute';
import { applyExtensions } from './extensions/ExtensionRegistry';
import { isMobile } from './util/Environment';
import { isMobile, isTv } from './util/Environment';
import type { StreamType } from './util/StreamType';
import type { TimeRange } from './components/TimeRange';
import { STREAM_TYPE_CHANGE_EVENT } from './events/StreamTypeChangeEvent';
import { toggleAttribute } from './util/CommonUtils';

const template = document.createElement('template');
template.innerHTML = `<style>${defaultUiCss}</style>${defaultUiHtml}`;
Expand Down Expand Up @@ -40,8 +41,10 @@ shadyCss.prepareTemplate(template, 'theoplayer-default-ui');
* @attribute `fluid` - If set, the player automatically adjusts its height to fit the video's aspect ratio.
* @attribute `muted` - If set, the player starts out as muted. Reflects `ui.player.muted`.
* @attribute `autoplay` - If set, the player attempts to automatically start playing (if allowed).
* @attribute `mobile` - Whether to use a mobile-optimized UI layout instead.
* Can be used in CSS to show/hide certain desktop-specific or mobile-specific UI controls.
* @attribute `device-type` - The device type, either "desktop", "mobile" or "tv".
* Can be used in CSS to show/hide certain device-specific UI controls.
* @attribute `mobile` - Whether the user is on a mobile device. Equivalent to `device-type == "mobile"`.
* @attribute `tv` - Whether the user is on a TV device. Equivalent to `device-type == "tv"`.
* @attribute `stream-type` - The stream type, either "vod", "live" or "dvr".
* Can be used to show/hide certain UI controls specific for livestreams, such as
* a {@link LiveButton | `<theoplayer-live-button>`}.
Expand All @@ -65,7 +68,7 @@ export class DefaultUI extends HTMLElement {
Attribute.MUTED,
Attribute.AUTOPLAY,
Attribute.FLUID,
Attribute.MOBILE,
Attribute.DEVICE_TYPE,
Attribute.STREAM_TYPE,
Attribute.USER_IDLE_TIMEOUT,
Attribute.DVR_THRESHOLD,
Expand Down Expand Up @@ -229,6 +232,8 @@ export class DefaultUI extends HTMLElement {

if (!this.hasAttribute(Attribute.MOBILE) && isMobile()) {
this.setAttribute(Attribute.MOBILE, '');
} else if (!this.hasAttribute(Attribute.TV) && isTv()) {
this.setAttribute(Attribute.TV, '');
}

if (!this._appliedExtensions) {
Expand Down Expand Up @@ -258,17 +263,11 @@ export class DefaultUI extends HTMLElement {
} else if (attrName === Attribute.AUTOPLAY) {
this.autoplay = hasValue;
} else if (attrName === Attribute.FLUID) {
if (hasValue) {
this._ui.setAttribute(Attribute.FLUID, newValue);
} else {
this._ui.removeAttribute(Attribute.FLUID);
}
} else if (attrName === Attribute.MOBILE) {
if (hasValue) {
this._ui.setAttribute(Attribute.MOBILE, newValue);
} else {
this._ui.removeAttribute(Attribute.MOBILE);
}
toggleAttribute(this._ui, Attribute.FLUID, hasValue);
} else if (attrName === Attribute.DEVICE_TYPE) {
toggleAttribute(this, Attribute.MOBILE, newValue === 'mobile');
toggleAttribute(this, Attribute.TV, newValue === 'tv');
this._ui.setAttribute(Attribute.DEVICE_TYPE, newValue);
} else if (attrName === Attribute.STREAM_TYPE) {
this.streamType = newValue;
} else if (attrName === Attribute.USER_IDLE_TIMEOUT) {
Expand All @@ -284,19 +283,11 @@ export class DefaultUI extends HTMLElement {
private readonly _updateStreamType = () => {
this.setAttribute(Attribute.STREAM_TYPE, this.streamType);
// Hide seekbar when stream is live with no DVR
if (this.streamType === 'live') {
this._timeRange.setAttribute(Attribute.HIDDEN, '');
} else {
this._timeRange.removeAttribute(Attribute.HIDDEN);
}
toggleAttribute(this._timeRange, Attribute.HIDDEN, this.streamType === 'live');
};

private readonly _onTitleSlotChange = () => {
if (this._titleSlot.assignedNodes().length > 0) {
this.setAttribute(Attribute.HAS_TITLE, '');
} else {
this.removeAttribute(Attribute.HAS_TITLE);
}
toggleAttribute(this, Attribute.HAS_TITLE, this._titleSlot.assignedNodes().length > 0);
};
}

Expand Down
11 changes: 10 additions & 1 deletion src/UIContainer.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
pointer-events: none;
}

:host(:not([mobile])) [part~='menu-layer'] {
:host(:not([mobile]):not([tv])) [part~='menu-layer'] {
top: var(--theoplayer-menu-offset-top, 0);
bottom: var(--theoplayer-menu-offset-bottom, 0);
padding: var(--theoplayer-menu-layer-padding, 10px);
Expand Down Expand Up @@ -153,7 +153,16 @@
@mixin menu-fill-styles;
}

:host([tv]) [part~='menu-layer'] {
left: auto;
}

:host([tv]) [part='menu'] {
@mixin menu-fill-styles;
}

:host(:not([menu-opened])) [part~='menu-layer'],
:host([menu-opened][tv]) [part~='vertical-layer'],
:host([menu-opened][mobile]) [part~='vertical-layer'] {
display: none !important;
}
Expand Down
Loading