import type WebView from 'react-native-webview'; import type { EventCallback } from '../types/vimeo'; class WebviewVimeoPlayerController { private webViewRef: React.RefObject; private commandId: number = 0; private pendingCommands: Map void> = new Map(); constructor(webViewRef: React.RefObject) { this.webViewRef = webViewRef; } static createInstance(webViewRef: React.RefObject): WebviewVimeoPlayerController { return new WebviewVimeoPlayerController(webViewRef); } getPendingCommands(): Map void> { return this.pendingCommands; } async play(): Promise { await this.executeCommand('play'); } async pause(): Promise { await this.executeCommand('pause'); } async unload(): Promise { await this.executeCommand('unload'); } async setCurrentTime(seconds: number): Promise { return this.executeCommand('setCurrentTime', [seconds]); } async getCurrentTime(): Promise { return this.executeCommand('getCurrentTime', [], true); } async setVolume(volume: number): Promise { return this.executeCommand('setVolume', [volume]); } async getVolume(): Promise { return this.executeCommand('getVolume', [], true); } async setMuted(muted: boolean): Promise { return this.executeCommand('setMuted', [muted]); } async getMuted(): Promise { return this.executeCommand('getMuted', [], true); } async getDuration(): Promise { return this.executeCommand('getDuration', [], true); } async getPlaybackRate(): Promise { return this.executeCommand('getPlaybackRate', [], true); } async setPlaybackRate(rate: number): Promise { return this.executeCommand('setPlaybackRate', [rate]); } async getVideoId(): Promise { return this.executeCommand('getVideoId', [], true); } async getVideoTitle(): Promise { return this.executeCommand('getVideoTitle', [], true); } async getVideoWidth(): Promise { return this.executeCommand('getVideoWidth', [], true); } async getVideoHeight(): Promise { return this.executeCommand('getVideoHeight', [], true); } async getVideoUrl(): Promise { return this.executeCommand('getVideoUrl', [], true); } async requestFullscreen(): Promise { await this.executeCommand('requestFullscreen'); } async exitFullscreen(): Promise { await this.executeCommand('exitFullscreen'); } async getFullscreen(): Promise { return this.executeCommand('getFullscreen', [], true); } async destroy(): Promise { await this.executeCommand('destroy'); } async off(event: string, _callback?: EventCallback): Promise { await this.executeCommand('off', [event]); } private executeCommand( command: string, args: (string | number | boolean | undefined)[] = [], needsResult = false, ): Promise { return new Promise((resolve) => { if (!this.webViewRef.current) { resolve(null); return; } const messageId = needsResult ? (++this.commandId).toString() : undefined; if (needsResult && messageId) { const timeout = setTimeout(() => { this.pendingCommands.delete(messageId); console.warn('Command timeout:', command, messageId); resolve(null); }, 5000); this.pendingCommands.set(messageId, (result) => { clearTimeout(timeout); resolve(result); }); } const commandData = { command, args, ...(messageId && { id: messageId }), }; const injectScript = /* js */ ` window.__execCommand && window.__execCommand(${JSON.stringify(commandData)}); true; `; this.webViewRef.current.injectJavaScript(injectScript); if (!needsResult) { resolve(null); } }); } dispose(): void { this.pendingCommands.clear(); this.destroy(); } } export default WebviewVimeoPlayerController;