Skip to content

Commit e89b297

Browse files
committed
Fix expo-video
1 parent b5b29a6 commit e89b297

File tree

3 files changed

+143
-15
lines changed

3 files changed

+143
-15
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/adapters/ExpoVideoAdapter.tsx

Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,148 @@ export class ExpoVideoAdapter implements VideoPlayerAdapter {
1313

1414
private loadExpoVideo(): void {
1515
try {
16+
console.log('ExpoVideoAdapter - Attempting to load expo-video...');
1617
this.expoVideoModule = require('expo-video');
18+
console.log('ExpoVideoAdapter - expo-video loaded successfully:', {
19+
hasVideoView: !!this.expoVideoModule?.VideoView,
20+
hasCreateVideoPlayer: !!this.expoVideoModule?.createVideoPlayer,
21+
exports: Object.keys(this.expoVideoModule || {})
22+
});
1723
} catch (error) {
24+
console.log('ExpoVideoAdapter - Failed to load expo-video:', error);
1825
this.expoVideoModule = null;
1926
}
2027
}
2128

2229
isAvailable(): boolean {
23-
// TODO: expo-video support requires architectural changes to support hooks
24-
// The current class-based adapter system is incompatible with expo-video's hook-based API
25-
// For now, return false to allow clean fallback to expo-av
26-
// This maintains the correct priority: try expo-video first, fall back to expo-av
27-
return false;
30+
// Check if expo-video module loaded successfully and has Video component
31+
const available = !!(this.expoVideoModule && this.expoVideoModule.VideoView);
32+
console.log('ExpoVideoAdapter - isAvailable():', {
33+
hasModule: !!this.expoVideoModule,
34+
hasVideoView: !!this.expoVideoModule?.VideoView,
35+
result: available
36+
});
37+
return available;
2838
}
2939

3040
getAdapterName(): string {
3141
return VideoPlayerType.EXPO_VIDEO;
3242
}
3343

34-
renderVideo(_props: VideoPlayerProps, _ref: RefObject<VideoPlayerRef | null>): ReactElement {
35-
// This method should never be called since isAvailable() returns false
36-
// expo-video support requires architectural changes for hooks compatibility
37-
throw new Error('expo-video is not available - requires architectural redesign for hooks support');
44+
renderVideo(props: VideoPlayerProps, ref: RefObject<VideoPlayerRef | null>): ReactElement {
45+
console.log('ExpoVideoAdapter - renderVideo() called with:', {
46+
videoUri: props.videoUri,
47+
hasStyle: !!props.style,
48+
useNativeControls: props.useNativeControls
49+
});
50+
51+
if (!this.isAvailable()) {
52+
console.log('ExpoVideoAdapter - renderVideo() failed: not available');
53+
throw new Error('expo-video is not available');
54+
}
55+
56+
const { VideoView, createVideoPlayer } = this.expoVideoModule;
57+
console.log('ExpoVideoAdapter - Using expo-video components:', {
58+
hasVideoView: !!VideoView,
59+
hasCreateVideoPlayer: !!createVideoPlayer
60+
});
61+
62+
// Create VideoPlayer instance for expo-video
63+
const player = createVideoPlayer({ uri: props.videoUri });
64+
65+
// Configure player properties
66+
player.loop = false;
67+
player.muted = false;
68+
69+
// Set up event listeners for status updates
70+
if (props.onPlaybackStatusUpdate) {
71+
// Listen to various player events and map them to status updates
72+
player.addListener('playingChange', (isPlaying: boolean) => {
73+
const status = {
74+
uri: props.videoUri,
75+
isLoaded: true,
76+
shouldPlay: isPlaying,
77+
isPlaying: isPlaying,
78+
positionMillis: player.currentTime * 1000,
79+
durationMillis: player.duration * 1000,
80+
isMuted: player.muted,
81+
rate: 1.0,
82+
volume: player.muted ? 0 : 1.0
83+
};
84+
props.onPlaybackStatusUpdate!(status);
85+
});
86+
87+
player.addListener('timeUpdate', () => {
88+
const status = {
89+
uri: props.videoUri,
90+
isLoaded: true,
91+
shouldPlay: player.playing,
92+
isPlaying: player.playing,
93+
positionMillis: player.currentTime * 1000,
94+
durationMillis: player.duration * 1000,
95+
isMuted: player.muted,
96+
rate: 1.0,
97+
volume: player.muted ? 0 : 1.0
98+
};
99+
props.onPlaybackStatusUpdate!(status);
100+
});
101+
}
102+
103+
// Handle errors
104+
if (props.onError) {
105+
player.addListener('error', (error: any) => {
106+
props.onError!(error);
107+
});
108+
}
109+
110+
return React.createElement(VideoView, {
111+
ref: (videoInstance: any) => {
112+
if (ref && typeof ref === 'object' && 'current' in ref) {
113+
// Store the player reference for compatibility with existing code
114+
ref.current = {
115+
...videoInstance,
116+
// Add expo-av compatible methods for backward compatibility
117+
setStatusAsync: async (status: any) => {
118+
if (status.shouldPlay !== undefined) {
119+
if (status.shouldPlay) {
120+
player.play();
121+
} else {
122+
player.pause();
123+
}
124+
}
125+
if (status.positionMillis !== undefined) {
126+
player.currentTime = status.positionMillis / 1000;
127+
}
128+
if (status.isMuted !== undefined) {
129+
player.muted = status.isMuted;
130+
}
131+
},
132+
_currentStatus: {
133+
uri: props.videoUri,
134+
isLoaded: true,
135+
shouldPlay: player.playing,
136+
positionMillis: player.currentTime * 1000,
137+
durationMillis: player.duration * 1000,
138+
isMuted: player.muted
139+
}
140+
};
141+
}
142+
},
143+
player: player,
144+
style: props.style,
145+
nativeControls: props.useNativeControls || false,
146+
contentFit: 'contain',
147+
onLoad: (data: any) => {
148+
if (props.onLoad) {
149+
props.onLoad(data);
150+
}
151+
},
152+
onLoadStart: (data: any) => {
153+
if (props.onLoadStart) {
154+
props.onLoadStart(data);
155+
}
156+
},
157+
});
38158
}
39159

40160
private processExpoVideoEvents(videoRef: VideoPlayerRef | null, eventType: string, data: any): void {

src/adapters/VideoPlayerFactory.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,24 @@ export class VideoPlayerFactory {
2727
static getAvailableAdapter(): VideoPlayerAdapter {
2828
this.initializeAdapters();
2929

30+
console.log('VideoPlayerFactory - Finding available adapter...');
31+
3032
// Find the first available adapter
3133
for (const adapter of this.adapters) {
3234
const isAvailable = adapter.isAvailable();
35+
console.log('VideoPlayerFactory - Checking adapter:', {
36+
name: adapter.getAdapterName(),
37+
isAvailable: isAvailable
38+
});
3339

3440
if (isAvailable) {
41+
console.log('VideoPlayerFactory - Selected adapter:', adapter.getAdapterName());
3542
return adapter;
3643
}
3744
}
3845

3946
// If no adapter is available, return fallback
47+
console.log('VideoPlayerFactory - No adapters available, using fallback');
4048
return new FallbackVideoAdapter('No video player library found. Install expo-video or expo-av.');
4149
}
4250

0 commit comments

Comments
 (0)