Skip to content

Commit

Permalink
fix(player): scroll and zoom gestures not working on iphone
Browse files Browse the repository at this point in the history
closes #987
  • Loading branch information
mihar-22 committed Nov 7, 2023
1 parent dbf7785 commit 671cdaf
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 22 deletions.
8 changes: 1 addition & 7 deletions packages/vidstack/src/components/provider/provider.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Component, method, onDispose, peek, signal, State, tick } from 'maverick.js';
import { animationFrameThrottle, listenEvent, setStyle } from 'maverick.js/std';
import { animationFrameThrottle, setStyle } from 'maverick.js/std';
import type { CaptionsFileFormat } from 'media-captions';

import type { MediaSrc, TextTrackInit } from '../../core';
import { useMediaContext, type MediaContext } from '../../core/api/media-context';
import type { MediaProviderLoader } from '../../providers';
import { IS_SAFARI } from '../../utils/support';
import { SourceSelection } from './source-select';
import { Tracks } from './tracks';

Expand Down Expand Up @@ -51,11 +50,6 @@ export class MediaProvider extends Component<MediaProviderProps, MediaProviderSt
const mutation = new MutationObserver(this._onMutation.bind(this));
mutation.observe(el, { attributes: true, childList: true });

if (IS_SAFARI) {
// Prevent delay on pointer/click events.
listenEvent(el, 'touchstart', (e) => e.preventDefault(), { passive: false });
}

this._onResize();
this._onMutation();

Expand Down
21 changes: 17 additions & 4 deletions packages/vidstack/src/components/ui/gesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from 'maverick.js/std';

import { useMediaContext, type MediaContext } from '../../core/api/media-context';
import { isTouchPinchEvent } from '../../utils/dom';

/**
* This component enables actions to be performed on the media based on user gestures.
Expand Down Expand Up @@ -54,10 +55,18 @@ export class Gesture extends Component<GestureProps, {}, GestureEvents> {
eventType = eventType.split(/^dbl/)[1] as keyof HTMLElementEventMap;
}

if (eventType === 'pointerup' || eventType === 'pointerdown') {
const pointer = this._media.$state.pointer();
if (pointer === 'coarse') {
eventType = eventType === 'pointerup' ? 'touchend' : 'touchstart';
}
}

listenEvent(
this._provider,
eventType as keyof HTMLElementEventMap,
this._acceptEvent.bind(this),
{ passive: false },
);
}

Expand All @@ -66,8 +75,10 @@ export class Gesture extends Component<GestureProps, {}, GestureEvents> {

private _acceptEvent(event: Event) {
if (
!this._inBounds(event) ||
(isPointerEvent(event) && (event.button !== 0 || this._media.activeMenu))
(isPointerEvent(event) && (event.button !== 0 || this._media.activeMenu)) ||
(isTouchEvent(event) && this._media.activeMenu) ||
isTouchPinchEvent(event) ||
!this._inBounds(event)
) {
return;
}
Expand All @@ -76,7 +87,9 @@ export class Gesture extends Component<GestureProps, {}, GestureEvents> {
event.MEDIA_GESTURE = true;
event.preventDefault();

const isDblEvent = peek(this.$props.event)?.startsWith('dbl');
const eventType = peek(this.$props.event),
isDblEvent = eventType?.startsWith('dbl');

if (!isDblEvent) {
if (this._presses === 0) {
setTimeout(() => {
Expand Down Expand Up @@ -116,7 +129,7 @@ export class Gesture extends Component<GestureProps, {}, GestureEvents> {
if (!this.el) return false;

if (isPointerEvent(event) || isMouseEvent(event) || isTouchEvent(event)) {
const touch = isTouchEvent(event) ? event.touches[0] : undefined;
const touch = isTouchEvent(event) ? event.changedTouches[0] ?? event.touches[0] : undefined;

const clientX = touch?.clientX ?? (event as MouseEvent).clientX;
const clientY = touch?.clientY ?? (event as MouseEvent).clientY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from 'maverick.js/std';

import type { MediaContext } from '../../../../core';
import { isTouchPinchEvent } from '../../../../utils/dom';
import { IS_SAFARI } from '../../../../utils/support';
import type {
SliderDragEndEvent,
Expand Down Expand Up @@ -88,7 +89,7 @@ export class SliderEventsController extends ViewController<
}

private _onTouchMove(event: TouchEvent) {
if (isNull(this._touch)) return;
if (isNull(this._touch) || isTouchPinchEvent(event)) return;

const touch = event.touches[0],
xDiff = touch.clientX - this._touch.clientX,
Expand All @@ -99,8 +100,6 @@ export class SliderEventsController extends ViewController<
return;
}

event.preventDefault();

if (isDragging) return;

if (Math.abs(xDiff) > 20) {
Expand Down
26 changes: 19 additions & 7 deletions packages/vidstack/src/core/controls.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { effect } from 'maverick.js';
import { isKeyboardEvent, listenEvent } from 'maverick.js/std';
import { isKeyboardEvent, isTouchEvent, listenEvent } from 'maverick.js/std';

import { isTouchPinchEvent } from '../utils/dom';
import { MediaPlayerController } from './api/player-controller';

export class MediaControls extends MediaPlayerController {
Expand Down Expand Up @@ -76,12 +77,17 @@ export class MediaControls extends MediaPlayerController {
if (paused() || (autoplayError() && !started())) return;

const onStopIdle = this._onStopIdle.bind(this);
for (const eventType of ['pointerup', 'keydown'] as const) {
listenEvent(this.el!, eventType, onStopIdle);
}

effect(() => {
if (this.$state.pointer() === 'fine') {
const pointer = this.$state.pointer(),
isTouch = pointer === 'coarse',
events = [isTouch ? 'touchend' : 'pointerup', 'keydown'] as const;

for (const eventType of events) {
listenEvent(this.el!, eventType, onStopIdle, { passive: false });
}

if (!isTouch) {
listenEvent(this.el!, 'pointermove', onStopIdle);
}
});
Expand All @@ -102,8 +108,14 @@ export class MediaControls extends MediaPlayerController {
}

private _onStopIdle(event: Event) {
// @ts-expect-error
if (event.MEDIA_GESTURE || this._pausedTracking) return;
if (
// @ts-expect-error
event.MEDIA_GESTURE ||
this._pausedTracking ||
isTouchPinchEvent(event)
) {
return;
}

if (isKeyboardEvent(event)) {
if (event.key === 'Escape') {
Expand Down
12 changes: 11 additions & 1 deletion packages/vidstack/src/utils/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import {
type Placement,
} from '@floating-ui/dom';
import { effect, getScope, onDispose, scoped } from 'maverick.js';
import { isKeyboardClick, listenEvent, setAttribute, setStyle } from 'maverick.js/std';
import {
isKeyboardClick,
isTouchEvent,
listenEvent,
setAttribute,
setStyle,
} from 'maverick.js/std';

export function setAttributeIfEmpty(target: Element, name: string, value: string) {
if (!target.hasAttribute(name)) target.setAttribute(name, value);
Expand Down Expand Up @@ -52,6 +58,10 @@ export function onPress(
});
}

export function isTouchPinchEvent(event: Event) {
return isTouchEvent(event) && (event.touches.length > 1 || event.changedTouches.length > 1);
}

export function requestScopedAnimationFrame(callback: () => void) {
if (__SERVER__) return callback();

Expand Down

0 comments on commit 671cdaf

Please sign in to comment.