mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 23:59:08 +00:00
fix: update versions and use native-edge-to-edge
This commit is contained in:
3
app.json
3
app.json
@@ -100,7 +100,8 @@
|
||||
"motionPermission": "Allow Streamyfin to access your device motion for landscape video watching."
|
||||
}
|
||||
],
|
||||
"./plugins/withNativeStyles.js"
|
||||
["react-native-edge-to-edge"],
|
||||
["react-native-bottom-tabs", { "theme": "material2" }]
|
||||
],
|
||||
"experiments": {
|
||||
"typedRoutes": true
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import * as NavigationBar from "expo-navigation-bar";
|
||||
import React, { useEffect } from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
|
||||
@@ -19,6 +18,7 @@ import type {
|
||||
} from "@react-navigation/native";
|
||||
import {} from "@expo/vector-icons/Ionicons";
|
||||
import { Colors } from "@/constants/Colors";
|
||||
import { SystemBars } from "react-native-edge-to-edge";
|
||||
|
||||
export const NativeTabs = withLayoutContext<
|
||||
BottomTabNavigationOptions,
|
||||
@@ -28,58 +28,54 @@ export const NativeTabs = withLayoutContext<
|
||||
>(Navigator);
|
||||
|
||||
export default function TabLayout() {
|
||||
useEffect(() => {
|
||||
if (Platform.OS === "android") {
|
||||
NavigationBar.setBackgroundColorAsync("#121212");
|
||||
NavigationBar.setBorderColorAsync("#121212");
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<NativeTabs
|
||||
sidebarAdaptable
|
||||
ignoresTopSafeArea
|
||||
barTintColor={"#121212"}
|
||||
tabBarActiveTintColor={Colors.primary}
|
||||
scrollEdgeAppearance="default"
|
||||
screenOptions={{
|
||||
lazy: false,
|
||||
}}
|
||||
>
|
||||
<NativeTabs.Screen redirect name="index" />
|
||||
<NativeTabs.Screen
|
||||
name="(home)"
|
||||
options={{
|
||||
title: "Home",
|
||||
tabBarIcon:
|
||||
Platform.OS == "android"
|
||||
? ({ color, focused, size }) =>
|
||||
require("@/assets/icons/house.fill.png")
|
||||
: () => ({ sfSymbol: "house" }),
|
||||
<>
|
||||
<SystemBars hidden={false} style="light" />
|
||||
<NativeTabs
|
||||
sidebarAdaptable
|
||||
ignoresTopSafeArea
|
||||
barTintColor={"#121212"}
|
||||
tabBarActiveTintColor={Colors.primary}
|
||||
scrollEdgeAppearance="default"
|
||||
screenOptions={{
|
||||
lazy: false,
|
||||
}}
|
||||
/>
|
||||
<NativeTabs.Screen
|
||||
name="(search)"
|
||||
options={{
|
||||
title: "Search",
|
||||
tabBarIcon:
|
||||
Platform.OS == "android"
|
||||
? ({ color, focused, size }) =>
|
||||
require("@/assets/icons/magnifyingglass.png")
|
||||
: () => ({ sfSymbol: "magnifyingglass" }),
|
||||
}}
|
||||
/>
|
||||
<NativeTabs.Screen
|
||||
name="(libraries)"
|
||||
options={{
|
||||
title: "Library",
|
||||
tabBarIcon:
|
||||
Platform.OS == "android"
|
||||
? ({ color, focused, size }) =>
|
||||
require("@/assets/icons/server.rack.png")
|
||||
: () => ({ sfSymbol: "rectangle.stack" }),
|
||||
}}
|
||||
/>
|
||||
</NativeTabs>
|
||||
>
|
||||
<NativeTabs.Screen redirect name="index" />
|
||||
<NativeTabs.Screen
|
||||
name="(home)"
|
||||
options={{
|
||||
title: "Home",
|
||||
tabBarIcon:
|
||||
Platform.OS == "android"
|
||||
? ({ color, focused, size }) =>
|
||||
require("@/assets/icons/house.fill.png")
|
||||
: () => ({ sfSymbol: "house" }),
|
||||
}}
|
||||
/>
|
||||
<NativeTabs.Screen
|
||||
name="(search)"
|
||||
options={{
|
||||
title: "Search",
|
||||
tabBarIcon:
|
||||
Platform.OS == "android"
|
||||
? ({ color, focused, size }) =>
|
||||
require("@/assets/icons/magnifyingglass.png")
|
||||
: () => ({ sfSymbol: "magnifyingglass" }),
|
||||
}}
|
||||
/>
|
||||
<NativeTabs.Screen
|
||||
name="(libraries)"
|
||||
options={{
|
||||
title: "Library",
|
||||
tabBarIcon:
|
||||
Platform.OS == "android"
|
||||
? ({ color, focused, size }) =>
|
||||
require("@/assets/icons/server.rack.png")
|
||||
: () => ({ sfSymbol: "rectangle.stack" }),
|
||||
}}
|
||||
/>
|
||||
</NativeTabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { Text } from "@/components/common/Text";
|
||||
import AlbumCover from "@/components/posters/AlbumCover";
|
||||
import { Controls } from "@/components/video-player/Controls";
|
||||
import { useAndroidNavigationBar } from "@/hooks/useAndroidNavigationBar";
|
||||
import { useOrientation } from "@/hooks/useOrientation";
|
||||
import { useOrientationSettings } from "@/hooks/useOrientationSettings";
|
||||
import { useWebSocket } from "@/hooks/useWebsockets";
|
||||
@@ -20,9 +17,9 @@ import * as Haptics from "expo-haptics";
|
||||
import { Image } from "expo-image";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { debounce } from "lodash";
|
||||
import React, { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { Dimensions, Pressable, StatusBar, View } from "react-native";
|
||||
import { Dimensions, Pressable, View } from "react-native";
|
||||
import { SystemBars } from "react-native-edge-to-edge";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import Video, { OnProgressData, VideoRef } from "react-native-video";
|
||||
|
||||
@@ -176,7 +173,6 @@ export default function page() {
|
||||
|
||||
const { orientation } = useOrientation();
|
||||
useOrientationSettings();
|
||||
useAndroidNavigationBar();
|
||||
|
||||
useWebSocket({
|
||||
isPlaying: isPlaying,
|
||||
@@ -194,7 +190,7 @@ export default function page() {
|
||||
}}
|
||||
className="flex flex-col items-center justify-center"
|
||||
>
|
||||
<StatusBar hidden />
|
||||
<SystemBars hidden />
|
||||
|
||||
<View className="h-screen w-screen top-0 left-0 flex flex-col items-center justify-center p-4 absolute z-0">
|
||||
<Image
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Controls } from "@/components/video-player/Controls";
|
||||
import { useAndroidNavigationBar } from "@/hooks/useAndroidNavigationBar";
|
||||
import { useOrientation } from "@/hooks/useOrientation";
|
||||
import { useOrientationSettings } from "@/hooks/useOrientationSettings";
|
||||
import { apiAtom } from "@/providers/JellyfinProvider";
|
||||
@@ -13,7 +12,8 @@ import * as Haptics from "expo-haptics";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
import React, { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { Pressable, StatusBar, useWindowDimensions, View } from "react-native";
|
||||
import { Pressable, useWindowDimensions, View } from "react-native";
|
||||
import { SystemBars } from "react-native-edge-to-edge";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import Video, { OnProgressData, VideoRef } from "react-native-video";
|
||||
|
||||
@@ -28,7 +28,6 @@ export default function page() {
|
||||
const dimensions = useWindowDimensions();
|
||||
useOrientation();
|
||||
useOrientationSettings();
|
||||
useAndroidNavigationBar();
|
||||
|
||||
const [showControls, setShowControls] = useState(true);
|
||||
const [ignoreSafeAreas, setIgnoreSafeAreas] = useState(false);
|
||||
@@ -87,7 +86,7 @@ export default function page() {
|
||||
}}
|
||||
className="flex flex-col items-center justify-center"
|
||||
>
|
||||
<StatusBar hidden />
|
||||
<SystemBars hidden />
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setShowControls(!showControls);
|
||||
@@ -119,7 +118,6 @@ export default function page() {
|
||||
}}
|
||||
/>
|
||||
</Pressable>
|
||||
|
||||
<Controls
|
||||
item={playSettings.item}
|
||||
videoRef={videoRef}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Controls } from "@/components/video-player/Controls";
|
||||
import { useAndroidNavigationBar } from "@/hooks/useAndroidNavigationBar";
|
||||
import { useOrientation } from "@/hooks/useOrientation";
|
||||
import { useOrientationSettings } from "@/hooks/useOrientationSettings";
|
||||
import { useWebSocket } from "@/hooks/useWebsockets";
|
||||
@@ -18,7 +17,8 @@ import * as Haptics from "expo-haptics";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useAtomValue } from "jotai";
|
||||
import React, { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { Pressable, StatusBar, useWindowDimensions, View } from "react-native";
|
||||
import { Pressable, useWindowDimensions, View } from "react-native";
|
||||
import { SystemBars } from "react-native-edge-to-edge";
|
||||
import { useSharedValue } from "react-native-reanimated";
|
||||
import Video, {
|
||||
OnProgressData,
|
||||
@@ -171,7 +171,6 @@ export default function page() {
|
||||
|
||||
useOrientation();
|
||||
useOrientationSettings();
|
||||
useAndroidNavigationBar();
|
||||
|
||||
useWebSocket({
|
||||
isPlaying: isPlaying,
|
||||
@@ -222,7 +221,7 @@ export default function page() {
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<StatusBar hidden />
|
||||
<SystemBars hidden />
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setShowControls(!showControls);
|
||||
|
||||
@@ -31,7 +31,6 @@ import * as Notifications from "expo-notifications";
|
||||
import { router, Stack } from "expo-router";
|
||||
import * as ScreenOrientation from "expo-screen-orientation";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import * as TaskManager from "expo-task-manager";
|
||||
import { Provider as JotaiProvider, useAtom } from "jotai";
|
||||
import { useEffect, useRef } from "react";
|
||||
@@ -39,6 +38,7 @@ import { AppState } from "react-native";
|
||||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||||
import "react-native-reanimated";
|
||||
import { Toaster } from "sonner-native";
|
||||
import { SystemBars } from "react-native-edge-to-edge";
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
@@ -326,7 +326,7 @@ function Layout() {
|
||||
<PlaySettingsProvider>
|
||||
<DownloadProvider>
|
||||
<BottomSheetModalProvider>
|
||||
<StatusBar style="light" backgroundColor="#000" />
|
||||
<SystemBars style="light" hidden={false} />
|
||||
<ThemeProvider value={DarkTheme}>
|
||||
<Stack initialRouteName="/home">
|
||||
<Stack.Screen
|
||||
@@ -335,7 +335,6 @@ function Layout() {
|
||||
headerShown: false,
|
||||
title: "",
|
||||
header: () => null,
|
||||
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
|
||||
@@ -63,7 +63,7 @@ export const DownloadItem: React.FC<DownloadProps> = ({ item, ...props }) => {
|
||||
getDefaultPlaySettings(item, settings);
|
||||
|
||||
// 4. Set states
|
||||
setSelectedMediaSource(mediaSource);
|
||||
setSelectedMediaSource(mediaSource ?? undefined);
|
||||
setSelectedAudioStream(audioIndex ?? 0);
|
||||
setSelectedSubtitleStream(subtitleIndex ?? -1);
|
||||
setMaxBitrate(bitrate);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import * as NavigationBar from "expo-navigation-bar";
|
||||
import { useEffect } from "react";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
export const useAndroidNavigationBar = () => {
|
||||
useEffect(() => {
|
||||
if (Platform.OS === "android") {
|
||||
NavigationBar.setVisibilityAsync("hidden");
|
||||
NavigationBar.setBehaviorAsync("overlay-swipe");
|
||||
|
||||
return () => {
|
||||
NavigationBar.setVisibilityAsync("visible");
|
||||
NavigationBar.setBehaviorAsync("inset-swipe");
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
// hooks/useNavigationBarVisibility.ts
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import * as NavigationBar from "expo-navigation-bar";
|
||||
|
||||
export const useNavigationBarVisibility = (isPlaying: boolean | null) => {
|
||||
useEffect(() => {
|
||||
const handleVisibility = async () => {
|
||||
if (Platform.OS === "android") {
|
||||
if (isPlaying) {
|
||||
await NavigationBar.setVisibilityAsync("hidden");
|
||||
} else {
|
||||
await NavigationBar.setVisibilityAsync("visible");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleVisibility();
|
||||
|
||||
return () => {
|
||||
if (Platform.OS === "android") {
|
||||
NavigationBar.setVisibilityAsync("visible");
|
||||
}
|
||||
};
|
||||
}, [isPlaying]);
|
||||
};
|
||||
@@ -47,7 +47,6 @@
|
||||
"expo-keep-awake": "~13.0.2",
|
||||
"expo-linear-gradient": "~13.0.2",
|
||||
"expo-linking": "~6.3.1",
|
||||
"expo-navigation-bar": "~3.0.7",
|
||||
"expo-network": "~6.0.1",
|
||||
"expo-notifications": "~0.28.19",
|
||||
"expo-router": "~3.5.23",
|
||||
@@ -68,9 +67,10 @@
|
||||
"react-dom": "18.2.0",
|
||||
"react-native": "0.74.5",
|
||||
"react-native-awesome-slider": "^2.5.3",
|
||||
"react-native-bottom-tabs": "^0.0.13",
|
||||
"react-native-bottom-tabs": "^0.3.1",
|
||||
"react-native-circular-progress": "^1.4.0",
|
||||
"react-native-compressor": "^1.8.25",
|
||||
"react-native-edge-to-edge": "^1.0.1",
|
||||
"react-native-gesture-handler": "~2.16.1",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-google-cast": "^4.8.3",
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
const { withAndroidStyles, withDangerousMod } = require("@expo/config-plugins");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
function withNativeTabBarStyles(config) {
|
||||
// First, apply the styles modifications
|
||||
config = withAndroidStyles(config, async (config) => {
|
||||
const styleContents = config.modResults;
|
||||
|
||||
// Find or create the AppTheme style
|
||||
let appTheme = styleContents.resources.style.find(
|
||||
(style) => style.$.name === "AppTheme"
|
||||
);
|
||||
|
||||
if (!appTheme) {
|
||||
appTheme = {
|
||||
$: {
|
||||
name: "AppTheme",
|
||||
parent: "Theme.Material3.DayNight.NoActionBar",
|
||||
},
|
||||
item: [],
|
||||
};
|
||||
styleContents.resources.style.push(appTheme);
|
||||
} else {
|
||||
appTheme.$.parent = "Theme.Material3.DayNight.NoActionBar";
|
||||
}
|
||||
|
||||
// Update or add items in the AppTheme style
|
||||
const itemsToAdd = [
|
||||
{
|
||||
name: "android:editTextBackground",
|
||||
value: "@drawable/rn_edit_text_material",
|
||||
},
|
||||
{
|
||||
name: "bottomNavigationStyle",
|
||||
value: "@style/Widget.Material3.BottomNavigationView",
|
||||
},
|
||||
{
|
||||
name: "android:navigationBarColor",
|
||||
value: "@android:color/transparent",
|
||||
},
|
||||
{ name: "android:statusBarColor", value: "@android:color/transparent" },
|
||||
];
|
||||
|
||||
itemsToAdd.forEach(({ name, value }) => {
|
||||
const existingItem = appTheme.item.find((item) => item.$.name === name);
|
||||
if (existingItem) {
|
||||
existingItem._ = value;
|
||||
} else {
|
||||
appTheme.item.push({
|
||||
$: { name },
|
||||
_: value,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add custom bottom navigation style
|
||||
styleContents.resources.style.push({
|
||||
$: {
|
||||
name: "CustomBottomNavigationView",
|
||||
parent: "@style/Widget.Material3.BottomNavigationView",
|
||||
},
|
||||
item: [
|
||||
{
|
||||
$: { name: "android:layout_margin" },
|
||||
_: "16dp",
|
||||
},
|
||||
{
|
||||
$: { name: "android:background" },
|
||||
_: "@drawable/bottom_nav_background",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const bottomNavigationStyleItem = appTheme.item.find(
|
||||
(item) => item.$.name === "bottomNavigationStyle"
|
||||
);
|
||||
if (bottomNavigationStyleItem) {
|
||||
bottomNavigationStyleItem._ = "@style/CustomBottomNavigationView";
|
||||
} else {
|
||||
appTheme.item.push({
|
||||
$: { name: "bottomNavigationStyle" },
|
||||
_: "@style/CustomBottomNavigationView",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
modResults: styleContents,
|
||||
};
|
||||
});
|
||||
|
||||
// Then, add the drawable file creation
|
||||
return withDangerousMod(config, [
|
||||
"android",
|
||||
async (config) => {
|
||||
const drawablePath = path.join(
|
||||
config.modRequest.platformProjectRoot,
|
||||
"app",
|
||||
"src",
|
||||
"main",
|
||||
"res",
|
||||
"drawable"
|
||||
);
|
||||
const filePath = path.join(drawablePath, "bottom_nav_background.xml");
|
||||
|
||||
const fileContent = `<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?attr/colorSurfaceVariant" />
|
||||
<corners android:radius="28dp" />
|
||||
</shape>`;
|
||||
|
||||
await fs.promises.mkdir(drawablePath, { recursive: true });
|
||||
await fs.promises.writeFile(filePath, fileContent);
|
||||
|
||||
return config;
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = withNativeTabBarStyles;
|
||||
Reference in New Issue
Block a user