From ca3c790900547151a47ed1f2f0298823b5e433e0 Mon Sep 17 00:00:00 2001 From: tapframe Date: Mon, 5 Jan 2026 00:46:47 +0530 Subject: [PATCH] added web linking --- App.tsx | 26 ++++++- src/components/player/AndroidVideoPlayer.tsx | 72 +++++++++++++++++++ .../player/controls/PlayerControls.tsx | 48 +++++++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) diff --git a/App.tsx b/App.tsx index 001c143..0398fe8 100644 --- a/App.tsx +++ b/App.tsx @@ -203,13 +203,37 @@ const ThemedApp = () => { const shouldShowApp = isAppReady && hasCompletedOnboarding !== null; const initialRouteName = hasCompletedOnboarding ? 'MainTabs' : 'Onboarding'; + // Linking configuration for web browser history integration + // Using 'enabled' with 'web' to enable basic web history navigation + const linking = Platform.OS === 'web' ? { + prefixes: [window?.location?.origin || '/'], + config: { + screens: { + MainTabs: '', + Onboarding: 'onboarding', + Metadata: 'metadata', + Streams: 'streams', + PlayerAndroid: 'player', + PlayerIOS: 'player', + Catalog: 'catalog', + Addons: 'addons', + CatalogSettings: 'catalog-settings', + TraktSettings: 'trakt-settings', + PlayerSettings: 'player-settings', + ThemeSettings: 'theme-settings', + ScraperSettings: 'scraper-settings', + AISettings: 'ai-settings', + } as const, + }, + } : undefined; + return ( diff --git a/src/components/player/AndroidVideoPlayer.tsx b/src/components/player/AndroidVideoPlayer.tsx index 4abb59e..715a8d8 100644 --- a/src/components/player/AndroidVideoPlayer.tsx +++ b/src/components/player/AndroidVideoPlayer.tsx @@ -359,6 +359,78 @@ const AndroidVideoPlayer: React.FC = () => { const firstFrameAtRef = useRef(null); const controlsTimeout = useRef(null); + // Web keyboard shortcuts + useEffect(() => { + if (Platform.OS !== 'web') return; + + const handleKeyDown = (e: KeyboardEvent) => { + // Prevent default for media keys + if (['Space', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.code)) { + e.preventDefault(); + } + + switch (e.code) { + case 'Space': + // Toggle play/pause + controlsHook.togglePlayback(); + playerState.setShowControls(true); + break; + case 'ArrowLeft': + // Skip backward 10 seconds + controlsHook.skip(-10); + playerState.setShowControls(true); + break; + case 'ArrowRight': + // Skip forward 10 seconds + controlsHook.skip(10); + playerState.setShowControls(true); + break; + case 'ArrowUp': + // Increase volume + setVolume(v => Math.min(1, v + 0.1)); + playerState.setShowControls(true); + break; + case 'ArrowDown': + // Decrease volume + setVolume(v => Math.max(0, v - 0.1)); + playerState.setShowControls(true); + break; + case 'KeyF': + // Toggle fullscreen (handled by PlayerControls) + break; + case 'Escape': + // Already handled by browser for fullscreen exit + break; + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [controlsHook, setVolume]); + + // Auto-hide controls after 3 seconds + useEffect(() => { + if (playerState.showControls && !playerState.paused) { + // Clear any existing timeout + if (controlsTimeout.current) { + clearTimeout(controlsTimeout.current); + } + + // Set new timeout to hide controls + controlsTimeout.current = setTimeout(() => { + if (!playerState.isDragging.current) { + playerState.setShowControls(false); + } + }, 3000); + } + + return () => { + if (controlsTimeout.current) { + clearTimeout(controlsTimeout.current); + } + }; + }, [playerState.showControls, playerState.paused]); + const handleClose = useCallback(() => { if (navigation.canGoBack()) navigation.goBack(); else navigation.reset({ index: 0, routes: [{ name: 'Home' }] } as any); diff --git a/src/components/player/controls/PlayerControls.tsx b/src/components/player/controls/PlayerControls.tsx index 786d148..fc3f322 100644 --- a/src/components/player/controls/PlayerControls.tsx +++ b/src/components/player/controls/PlayerControls.tsx @@ -177,6 +177,40 @@ export const PlayerControls: React.FC = ({ }) => { const { currentTheme } = useTheme(); + // Web fullscreen state + const [isFullscreen, setIsFullscreen] = React.useState(false); + + // Listen for fullscreen changes + React.useEffect(() => { + if (Platform.OS !== 'web') return; + + const handleFullscreenChange = () => { + setIsFullscreen(!!document.fullscreenElement); + }; + + document.addEventListener('fullscreenchange', handleFullscreenChange); + return () => { + document.removeEventListener('fullscreenchange', handleFullscreenChange); + }; + }, []); + + // Toggle fullscreen function for web + const toggleFullscreen = React.useCallback(() => { + if (Platform.OS !== 'web') return; + + if (!document.fullscreenElement) { + // Enter fullscreen + document.documentElement.requestFullscreen().catch(err => { + console.log('[PlayerControls] Fullscreen request failed:', err); + }); + } else { + // Exit fullscreen + document.exitFullscreen().catch(err => { + console.log('[PlayerControls] Exit fullscreen failed:', err); + }); + } + }, []); + /* Responsive Spacing */ const screenWidth = Dimensions.get('window').width; @@ -677,6 +711,20 @@ export const PlayerControls: React.FC = ({ )} + + {/* Web Fullscreen Button */} + {Platform.OS === 'web' && ( + + + + )}