diff --git a/src/adapters/VideoPlayerFactory.ts b/src/adapters/VideoPlayerFactory.ts index 8dad75e..d5a587d 100644 --- a/src/adapters/VideoPlayerFactory.ts +++ b/src/adapters/VideoPlayerFactory.ts @@ -26,18 +26,34 @@ export class VideoPlayerFactory { */ static getAvailableAdapter(): VideoPlayerAdapter { this.initializeAdapters(); + // Find the first available adapter and collect availability info + const availabilityInfos: { name: string; info: { isAvailable: boolean; error?: string; installCommand?: string; packageName?: string } }[] = []; - // Find the first available adapter for (const adapter of this.adapters) { - const isAvailable = adapter.isAvailable(); - - if (isAvailable) { + const info = typeof (adapter as any).getAvailabilityInfo === 'function' + ? (adapter as any).getAvailabilityInfo() + : { isAvailable: adapter.isAvailable() }; + + availabilityInfos.push({ name: adapter.getAdapterName(), info }); + + if (info.isAvailable) { return adapter; } } - // If no adapter is available, return fallback - return new FallbackVideoAdapter('No video player library found. Install expo-video or expo-av.'); + // Build a helpful, actionable error message listing why adapters are unavailable + const details = availabilityInfos.map(ai => { + if (ai.info.isAvailable) return `${ai.name}: available`; + const parts: string[] = []; + if (ai.info.error) parts.push(ai.info.error); + if (ai.info.installCommand) parts.push(`To install: ${ai.info.installCommand}`); + if (ai.info.packageName && !ai.info.installCommand) parts.push(`Package: ${ai.info.packageName}`); + return `${ai.name}: ${parts.join(' ').trim()}`.trim(); + }).join('\n\n'); + + const message = `No video player library found. Please install one of the supported players:\n\n${details}`; + + return new FallbackVideoAdapter(message); } /** @@ -45,10 +61,19 @@ export class VideoPlayerFactory { */ static getAdapterByType(type: VideoPlayerType): VideoPlayerAdapter { this.initializeAdapters(); - const adapter = this.adapters.find(adapter => adapter.getAdapterName() === type); - if (adapter && adapter.isAvailable()) { - return adapter; + if (adapter) { + const info = typeof (adapter as any).getAvailabilityInfo === 'function' + ? (adapter as any).getAvailabilityInfo() + : { isAvailable: adapter.isAvailable() }; + + if (info.isAvailable) { + return adapter; + } + + const installHint = info.installCommand ? `\nTo fix: ${info.installCommand}` : ''; + const errorMsg = info.error ? `${info.error}${installHint}` : `Adapter for ${type} is not available.${installHint}`; + throw new Error(errorMsg); } throw new Error(`Adapter for ${type} is not available`); @@ -66,6 +91,20 @@ export class VideoPlayerFactory { })); } + /** + * Return detailed availability info (including install commands) for each adapter. + */ + static getAdaptersAvailabilityInfo(): { name: string; info: { isAvailable: boolean; error?: string; installCommand?: string; packageName?: string } }[] { + this.initializeAdapters(); + + return this.adapters.map(adapter => ({ + name: adapter.getAdapterName(), + info: typeof (adapter as any).getAvailabilityInfo === 'function' + ? (adapter as any).getAvailabilityInfo() + : { isAvailable: adapter.isAvailable() } + })); + } + /** * Check if a specific video player type is available */