diff --git a/js/app/app.config.ts b/js/app/app.config.ts index 870522d9..8738bd7d 100644 --- a/js/app/app.config.ts +++ b/js/app/app.config.ts @@ -232,6 +232,15 @@ export default function () { }, ], [withConsistentVersionNumber, { version: pkg.version }], + [ + "react-native-edge-to-edge", + { + android: { + parentTheme: "Default", + enforceNavigationBarContrast: false, + }, + }, + ], ...(isProd ? [ "@react-native-firebase/app", diff --git a/js/app/package.json b/js/app/package.json index f63ca2c0..7d6471fa 100644 --- a/js/app/package.json +++ b/js/app/package.json @@ -65,7 +65,6 @@ "expo-notifications": "~0.31.3", "expo-splash-screen": "~0.30.9", "expo-sqlite": "~15.2.12", - "expo-status-bar": "~2.2.3", "expo-system-ui": "~5.0.8", "expo-updates": "~0.28.14", "expo-video": "~2.2.1", @@ -78,6 +77,7 @@ "react": "19.0.0", "react-dom": "19.0.0", "react-native": "0.79.3", + "react-native-edge-to-edge": "^1.6.2", "react-native-gesture-handler": "~2.26.0", "react-native-markdown-display": "^7.0.2", "react-native-quick-crypto": "^0.7.14", diff --git a/js/app/src/router.tsx b/js/app/src/router.tsx index eb5cb296..e81ce36c 100644 --- a/js/app/src/router.tsx +++ b/js/app/src/router.tsx @@ -57,7 +57,6 @@ import { Linking, Platform, Pressable, - StatusBar, } from "react-native"; import { useAppDispatch, useAppSelector } from "store/hooks"; import { H3, Text, useTheme, View } from "tamagui"; @@ -80,6 +79,7 @@ import { store } from "store/store"; import HomeScreen from "./screens/home"; import { useUrl } from "@streamplace/components"; +import { SystemBars } from "react-native-edge-to-edge"; import { configureReanimatedLogger, ReanimatedLogLevel, @@ -305,6 +305,8 @@ export function StreamplaceDrawer() { const sidebar = useSidebarControl(); + SystemBars.setStyle("dark"); + // Top-level stuff to handle push notification registration useEffect(() => { dispatch(hydrate()); @@ -357,7 +359,6 @@ export function StreamplaceDrawer() { } return ( <> - { /> { if (fullscreen) { - StatusBar.setHidden(true); + SystemBars.setHidden(true); console.log("setting sidebar hidden"); // Hide the navigation header @@ -73,7 +68,7 @@ export function Fullscreen(props: { src: string }) { backHandler.remove(); }; } else { - StatusBar.setHidden(false); + SystemBars.setHidden(false); // Restore the navigation header navigation.setOptions({ @@ -82,7 +77,7 @@ export function Fullscreen(props: { src: string }) { } return () => { - StatusBar.setHidden(false); + SystemBars.setHidden(false); // Ensure header is restored if component unmounts navigation.setOptions({ headerShown: true, diff --git a/js/components/src/components/mobile-player/video.native.tsx b/js/components/src/components/mobile-player/video.native.tsx index 4ff992d2..0e8c7bcd 100644 --- a/js/components/src/components/mobile-player/video.native.tsx +++ b/js/components/src/components/mobile-player/video.native.tsx @@ -224,6 +224,12 @@ export function NativeWHEP() { objectFit={"contain"} streamURL={mediaStream.toURL()} onLayout={handleLayout} + pictureInPictureEnabled={true} + autoStartPictureInPicture={true} + pictureInPicturePreferredSize={{ + width: 160, + height: 90, + }} style={{ minWidth: "100%", minHeight: "100%", diff --git a/js/components/src/components/ui/resizeable.tsx b/js/components/src/components/ui/resizeable.tsx index 4c053cb2..d5ee2ecf 100644 --- a/js/components/src/components/ui/resizeable.tsx +++ b/js/components/src/components/ui/resizeable.tsx @@ -36,15 +36,14 @@ export function Resizable({ children, }: ResizableChatSheetProps) { const { slideKeyboard } = useKeyboardSlide(); - const MAX_HEIGHT = SCREEN_HEIGHT * 0.5; - const MIN_HEIGHT = -SCREEN_HEIGHT * 0.2; - const COLLAPSE_HEIGHT = SCREEN_HEIGHT * 0.1; + const { bottom: safeBottom } = useSafeAreaInsets(); + const MAX_HEIGHT = (SCREEN_HEIGHT - safeBottom) * 0.5; + const MIN_HEIGHT = -(SCREEN_HEIGHT - safeBottom) * 0.2; + const COLLAPSE_HEIGHT = (SCREEN_HEIGHT - safeBottom) * 0.1; const sheetHeight = useSharedValue(MIN_HEIGHT); const startHeight = useSharedValue(MIN_HEIGHT); - const { bottom: safeBottom } = useSafeAreaInsets(); - const panGesture = Gesture.Pan() .onStart(() => { startHeight.value = sheetHeight.value; @@ -95,6 +94,7 @@ export function Resizable({ w.percent[100], layout.flex.center, zIndex[1], + { marginBottom: safeBottom }, ]} > 0) { + if (keyboardHeight > 0) { slideKeyboard = -keyboardHeight + (outerHeight - innerHeight); } return { keyboardHeight, slideKeyboard }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c36a9383..56ba40e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,9 +171,6 @@ importers: expo-sqlite: specifier: ~15.2.12 version: 15.2.12(expo@53.0.11(@babel/core@7.26.0)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-native-webview@13.15.0(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0))(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(utf-8-validate@5.0.10))(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) - expo-status-bar: - specifier: ~2.2.3 - version: 2.2.3(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) expo-system-ui: specifier: ~5.0.8 version: 5.0.8(expo@53.0.11(@babel/core@7.26.0)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-native-webview@13.15.0(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0))(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(utf-8-validate@5.0.10))(react-native-web@0.20.0(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10)) @@ -210,6 +207,9 @@ importers: react-native: specifier: 0.79.3 version: 0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10) + react-native-edge-to-edge: + specifier: ^1.6.2 + version: 1.6.2(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) react-native-gesture-handler: specifier: ~2.26.0 version: 2.26.0(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) @@ -6759,12 +6759,6 @@ packages: react: '*' react-native: '*' - expo-status-bar@2.2.3: - resolution: {integrity: sha512-+c8R3AESBoduunxTJ8353SqKAKpxL6DvcD8VKBuh81zzJyUUbfB4CVjr1GufSJEKsMzNPXZU+HJwXx7Xh7lx8Q==} - peerDependencies: - react: '*' - react-native: '*' - expo-structured-headers@4.1.0: resolution: {integrity: sha512-2X+aUNzC/qaw7/WyUhrVHNDB0uQ5rE12XA2H/rJXaAiYQSuOeU90ladaN0IJYV9I2XlhYrjXLktLXWbO7zgbag==} @@ -10056,6 +10050,12 @@ packages: react: '*' react-native: '*' + react-native-edge-to-edge@1.6.2: + resolution: {integrity: sha512-koEF6WRAfdGNelXlP7NtHrQhFGtplwciYNWLHOCTCk0Thc7dlxtqxHRYSA5vPJgWOEkVBFqxcoOqKwAtqOmLNw==} + peerDependencies: + react: '*' + react-native: '*' + react-native-fit-image@1.5.5: resolution: {integrity: sha512-Wl3Vq2DQzxgsWKuW4USfck9zS7YzhvLNPpkwUUCF90bL32e1a0zOVQ3WsJILJOwzmPdHfzZmWasiiAUNBkhNkg==} @@ -21077,13 +21077,6 @@ snapshots: react: 19.0.0 react-native: 0.79.3(@babel/core@7.26.0)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10) - expo-status-bar@2.2.3(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0): - dependencies: - react: 19.0.0 - react-native: 0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10) - react-native-edge-to-edge: 1.6.0(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) - react-native-is-edge-to-edge: 1.1.7(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0) - expo-structured-headers@4.1.0: {} expo-system-ui@5.0.8(expo@53.0.11(@babel/core@7.26.0)(@expo/metro-runtime@5.0.4(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(react-native-webview@13.15.0(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0))(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0)(utf-8-validate@5.0.10))(react-native-web@0.20.0(encoding@0.1.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10)): @@ -25467,6 +25460,11 @@ snapshots: react: 19.0.0 react-native: 0.79.3(@babel/core@7.26.0)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10) + react-native-edge-to-edge@1.6.2(react-native@0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10))(react@19.0.0): + dependencies: + react: 19.0.0 + react-native: 0.79.3(@babel/core@7.26.0)(@types/react@18.3.12)(bufferutil@4.0.8)(react@19.0.0)(utf-8-validate@5.0.10) + react-native-fit-image@1.5.5: dependencies: prop-types: 15.8.1