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