Skip to content

Commit

Permalink
fix(player): do not render layouts when ios controls are shown
Browse files Browse the repository at this point in the history
  • Loading branch information
mihar-22 committed Apr 3, 2024
1 parent 479df95 commit eeed0e4
Show file tree
Hide file tree
Showing 12 changed files with 52 additions and 64 deletions.
12 changes: 3 additions & 9 deletions packages/react/src/components/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,10 @@ interface MediaOutletProps extends React.HTMLAttributes<HTMLMediaElement> {
}

function MediaOutlet({ provider, ...props }: MediaOutletProps) {
const { controls, crossOrigin, poster, remotePlaybackInfo } = useStateContext(mediaState),
const { crossOrigin, poster, remotePlaybackInfo, nativeControls } = useStateContext(mediaState),
{ loader } = provider.$state,
{
$iosControls: $$iosControls,
$provider: $$provider,
$providerSetup: $$providerSetup,
} = useMediaContext(),
$controls = useSignal(controls),
$iosControls = useSignal($$iosControls),
$nativeControls = $controls || $iosControls,
{ $provider: $$provider, $providerSetup: $$providerSetup } = useMediaContext(),
$nativeControls = useSignal(nativeControls),
$crossOrigin = useSignal(crossOrigin),
$poster = useSignal(poster),
$loader = useSignal(loader),
Expand Down
13 changes: 1 addition & 12 deletions packages/vidstack/src/components/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ export class MediaPlayer
__DEV__ ? context.logger : undefined,
);
context.remote.setPlayer(this);
context.$iosControls = computed(this._isIOSControls.bind(this));
context.textTracks = new TextTrackList();
context.textTracks[TextTrackSymbol._crossOrigin] = this.$state.crossOrigin;
context.textRenderers = new TextRenderers(context);
Expand Down Expand Up @@ -309,7 +308,7 @@ export class MediaPlayer
return !!track && isTrackCaptionKind(track);
},
'data-ios-controls': function (this: MediaPlayer) {
return this._media.$iosControls();
return this.$state.iOSControls();
},
'data-controls': function (this: MediaPlayer) {
return this.controls.showing;
Expand Down Expand Up @@ -377,16 +376,6 @@ export class MediaPlayer
this._onResize();
}

private _isIOSControls() {
const { playsInline, fullscreen } = this.$state;
return (
IS_IPHONE &&
!canFullscreen() &&
this.$state.mediaType() === 'video' &&
(!playsInline() || fullscreen())
);
}

/**
* The current media provider.
*/
Expand Down
7 changes: 2 additions & 5 deletions packages/vidstack/src/components/ui/captions/captions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,10 @@ export class Captions extends Component<CaptionsProps> {
}

private _isHidden() {
const { textTrack, remotePlaybackState } = this._media.$state,
const { textTrack, remotePlaybackState, iOSControls } = this._media.$state,
track = textTrack();
return (
this._media.$iosControls() ||
remotePlaybackState() === 'connected' ||
!track ||
!isTrackCaptionKind(track)
iOSControls() || remotePlaybackState() === 'connected' || !track || !isTrackCaptionKind(track)
);
}

Expand Down
5 changes: 2 additions & 3 deletions packages/vidstack/src/components/ui/controls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ export class Controls extends Component<ControlsProps, {}, ControlsEvents> {
private _hideControls() {
if (!this.el) return;

const { $iosControls } = this._media,
{ controls } = this._media.$state,
isHidden = controls() || $iosControls();
const { nativeControls } = this._media.$state,
isHidden = nativeControls();

setAttribute(this.el, 'aria-hidden', isHidden ? 'true' : null);
setStyle(this.el, 'display', isHidden ? 'none' : null);
Expand Down
8 changes: 3 additions & 5 deletions packages/vidstack/src/components/ui/poster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,9 @@ export class Poster extends Component<PosterProps, PosterState> {

private _watchHidden() {
const { src } = this.$props,
{ $iosControls } = this._media,
{ poster } = this._media.$state;

this.el && setAttribute(this.el, 'display', $iosControls() ? 'none' : null);
this.$state.hidden.set(this._hasError() || !(src() || poster()) || $iosControls());
{ poster, nativeControls } = this._media.$state;
this.el && setAttribute(this.el, 'display', nativeControls() ? 'none' : null);
this.$state.hidden.set(this._hasError() || !(src() || poster()) || nativeControls());
}

private _isLoading() {
Expand Down
1 change: 0 additions & 1 deletion packages/vidstack/src/core/api/media-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export interface MediaContext {
logger?: Logger;
$provider: WriteSignal<MediaProviderAdapter | null>;
$providerSetup: WriteSignal<boolean>;
$iosControls: ReadSignal<boolean>;
$props: ReadSignalRecord<MediaPlayerProps>;
$state: PlayerStore;
activeMenu?: {
Expand Down
22 changes: 21 additions & 1 deletion packages/vidstack/src/core/api/player-state.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import fscreen from 'fscreen';
import { State, tick, type Store } from 'maverick.js';

import type { LogLevel } from '../../foundation/logger/log-level';
import type { MediaProviderLoader } from '../../providers/types';
import { canOrientScreen } from '../../utils/support';
import { canOrientScreen, IS_IPHONE } from '../../utils/support';
import type { VideoQuality } from '../quality/video-quality';
import { getTimeRangesEnd, getTimeRangesStart, TimeRange } from '../time-ranges';
import type { AudioTrack } from '../tracks/audio-tracks';
Expand Down Expand Up @@ -38,6 +39,16 @@ export const mediaState = new State<MediaState>({
clipStartTime: 0,
clipEndTime: 0,
controls: false,
get iOSControls() {
return (
IS_IPHONE &&
this.mediaType === 'video' &&
(!this.playsInline || (!fscreen.fullscreenEnabled && this.fullscreen))
);
},
get nativeControls() {
return this.controls || this.iOSControls;
},
controlsVisible: false,
get controlsHidden() {
return !this.controlsVisible;
Expand Down Expand Up @@ -410,6 +421,15 @@ export interface MediaState {
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/controls}
*/
controls: boolean;
/**
* Whether iOS Safari video controls are visible. This will be true if `playsinline` is not set
* or in fullscreen due to lack of a Fullscreen API.
*/
readonly iOSControls: boolean;
/**
* Whether native controls should be shown due to the `controls` state or `iOSControls` state.
*/
readonly nativeControls: boolean;
/**
* Defines how the media element handles cross-origin requests, thereby enabling the
* configuration of the CORS requests for the element's fetched data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export class TextRenderers {
}

private _watchControls() {
const { $state, $iosControls } = this._media;
this._nativeDisplay = $state.controls() || $iosControls();
const { nativeControls } = this._media.$state;
this._nativeDisplay = nativeControls();
this._update();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ export class MediaVideoLayoutElement

private _render() {
const { load } = this._media.$props,
{ canLoad, streamType } = this._media.$state;
{ canLoad, streamType, nativeControls } = this._media.$state;

return this.isMatch
return !nativeControls() && this.isMatch
? load() === 'play' && !canLoad()
? DefaultVideoLoadLayout()
: streamType() === 'unknown'
Expand Down
23 changes: 9 additions & 14 deletions packages/vidstack/src/elements/define/provider-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ export class MediaProviderElement extends Host(HTMLElement, MediaProvider) {

if (isEmbed && target) {
effect(() => {
const { $iosControls } = this._media,
{ controls } = this._media.$state,
showControls = controls() || $iosControls();
const { nativeControls } = this._media.$state,
showControls = nativeControls();

if (showControls) {
this._blocker?.remove();
Expand Down Expand Up @@ -111,13 +110,12 @@ export class MediaProviderElement extends Host(HTMLElement, MediaProvider) {
const video =
this._target instanceof HTMLVideoElement ? this._target : document.createElement('video');

const { controls, crossOrigin, poster } = this._media.$state,
{ $iosControls } = this._media,
$nativeControls = computed(() => (controls() || $iosControls() ? 'true' : null)),
$poster = computed(() => (poster() && (controls() || $iosControls()) ? poster() : null));
const { crossOrigin, poster, nativeControls } = this._media.$state,
$controls = computed(() => (nativeControls() ? 'true' : null)),
$poster = computed(() => (poster() && nativeControls() ? poster() : null));

effect(() => {
setAttribute(video, 'controls', $nativeControls());
setAttribute(video, 'controls', $controls());
setAttribute(video, 'crossorigin', crossOrigin());
setAttribute(video, 'poster', $poster());
});
Expand All @@ -127,13 +125,10 @@ export class MediaProviderElement extends Host(HTMLElement, MediaProvider) {

private _createIFrame() {
const iframe =
this._target instanceof HTMLIFrameElement ? this._target : document.createElement('iframe');
this._target instanceof HTMLIFrameElement ? this._target : document.createElement('iframe'),
{ nativeControls } = this._media.$state;

const { controls } = this._media.$state,
{ $iosControls } = this._media,
$nativeControls = computed(() => controls() || $iosControls());

effect(() => setAttribute(iframe, 'tabindex', !$nativeControls() ? -1 : null));
effect(() => setAttribute(iframe, 'tabindex', !nativeControls() ? -1 : null));

return iframe;
}
Expand Down
12 changes: 5 additions & 7 deletions packages/vidstack/src/providers/vimeo/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,9 @@ export class VimeoProvider
}

protected override _buildParams(): VimeoParams {
const { $iosControls } = this._ctx,
{ keyDisabled } = this._ctx.$props,
{ controls, playsInline } = this._ctx.$state,
showControls = controls() || $iosControls();
const { keyDisabled } = this._ctx.$props,
{ playsInline, nativeControls } = this._ctx.$state,
showControls = nativeControls();
return {
title: this.title,
byline: this.byline,
Expand Down Expand Up @@ -361,9 +360,8 @@ export class VimeoProvider
}

private _onReady(duration: number, trigger: Event) {
const { $iosControls } = this._ctx,
{ controls } = this._ctx.$state,
showEmbedControls = controls() || $iosControls();
const { nativeControls } = this._ctx.$state,
showEmbedControls = nativeControls();

this._seekableRange = new TimeRange(0, duration);

Expand Down
5 changes: 2 additions & 3 deletions packages/vidstack/src/providers/youtube/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,8 @@ export class YouTubeProvider

protected override _buildParams(): YouTubeParams {
const { keyDisabled } = this._ctx.$props,
{ $iosControls } = this._ctx,
{ controls, muted, playsInline } = this._ctx.$state,
showControls = controls() || $iosControls();
{ muted, playsInline, nativeControls } = this._ctx.$state,
showControls = nativeControls();
return {
autoplay: 0,
cc_lang_pref: this.language,
Expand Down

0 comments on commit eeed0e4

Please sign in to comment.