mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-05-31 11:08:26 +01:00
Compatibility migration from SDK 55 to SDK 56 (react-native-tvos 0.85.3-0, React 19.2.3). Phase 1 = breaking changes needed to build; new-feature adoption and TypeScript 6 are deferred to Phase 2. - Deps aligned to SDK 56 via `expo install --fix` (all expo-* 56.x, screens 4.25.2, reanimated 4.3.1, worklets 0.8.3, gesture-handler 2.31.x, svg 15.15.4) - react-native -> react-native-tvos@0.85.3-0; react/react-dom 19.2.3 - expo-router forked React Navigation: ran the SDK 56 codemod (@react-navigation/* imports -> expo-router/*), removed the 3 now-unused direct @react-navigation/* dependencies, retyped NestedTabPageStack via expo-router Stack.Screen options - StyleSheet.absoluteFillObject -> absoluteFill (removed from RN 0.85 types) - app.json ios.deploymentTarget 15.6 -> 16.4 (SDK 56 minimum) - CI: Xcode 26.2 -> 26.4; made xcode-version Renovate-managed via a customManager + xcodereleases customDatasource - @babel/core 7.29.7; dropped version-locked screens/codegen bun-patches (no longer applicable on SDK 56) Deferred to Phase 2: TypeScript 6 (toolchain: @types/node, jest globals, UdpSocket typing), @expo/vector-icons -> @react-native-vector-icons codemod. typecheck passes. expo-doctor: 2 known failures remain (react-native-track-player New Arch fork; typescript major mismatch pending the deferred TS6 bump).
147 lines
4.7 KiB
TypeScript
147 lines
4.7 KiB
TypeScript
import {
|
|
createNativeBottomTabNavigator,
|
|
type NativeBottomTabNavigationEventMap,
|
|
type NativeBottomTabNavigationOptions,
|
|
} from "@bottom-tabs/react-navigation";
|
|
import { withLayoutContext } from "expo-router";
|
|
import type {
|
|
ParamListBase,
|
|
TabNavigationState,
|
|
} from "expo-router/react-navigation";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Platform, View } from "react-native";
|
|
import { SystemBars } from "react-native-edge-to-edge";
|
|
import { Colors } from "@/constants/Colors";
|
|
import { useTVHomeBackHandler } from "@/hooks/useTVBackHandler";
|
|
import { useSettings } from "@/utils/atoms/settings";
|
|
import { eventBus } from "@/utils/eventBus";
|
|
|
|
// Music components are not available on tvOS (TrackPlayer not supported)
|
|
const MiniPlayerBar = Platform.isTV
|
|
? () => null
|
|
: require("@/components/music/MiniPlayerBar").MiniPlayerBar;
|
|
const MusicPlaybackEngine = Platform.isTV
|
|
? () => null
|
|
: require("@/components/music/MusicPlaybackEngine").MusicPlaybackEngine;
|
|
|
|
const { Navigator } = createNativeBottomTabNavigator();
|
|
|
|
export const NativeTabs = withLayoutContext<
|
|
NativeBottomTabNavigationOptions,
|
|
typeof Navigator,
|
|
TabNavigationState<ParamListBase>,
|
|
NativeBottomTabNavigationEventMap
|
|
>(Navigator);
|
|
|
|
export default function TabLayout() {
|
|
const { settings } = useSettings();
|
|
const { t } = useTranslation();
|
|
|
|
// Handle TV back button - prevent app exit when at root
|
|
useTVHomeBackHandler();
|
|
|
|
return (
|
|
<View style={{ flex: 1 }}>
|
|
<SystemBars hidden={false} style='light' />
|
|
<NativeTabs
|
|
sidebarAdaptable={false}
|
|
tabBarStyle={{
|
|
backgroundColor: "#121212",
|
|
}}
|
|
tabBarActiveTintColor={Colors.primary}
|
|
activeIndicatorColor={"#392c3b"}
|
|
scrollEdgeAppearance='default'
|
|
>
|
|
<NativeTabs.Screen redirect name='index' />
|
|
<NativeTabs.Screen
|
|
listeners={(_e) => ({
|
|
tabPress: (_e) => {
|
|
eventBus.emit("scrollToTop");
|
|
},
|
|
})}
|
|
name='(home)'
|
|
options={{
|
|
title: t("tabs.home"),
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/house.fill.png")
|
|
: (_e) => ({ sfSymbol: "house.fill" }),
|
|
}}
|
|
/>
|
|
<NativeTabs.Screen
|
|
listeners={(_e) => ({
|
|
tabPress: (_e) => {
|
|
eventBus.emit("searchTabPressed");
|
|
},
|
|
})}
|
|
name='(search)'
|
|
options={{
|
|
role: "search",
|
|
title: t("tabs.search"),
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/magnifyingglass.png")
|
|
: (_e) => ({ sfSymbol: "magnifyingglass" }),
|
|
}}
|
|
/>
|
|
<NativeTabs.Screen
|
|
name='(favorites)'
|
|
options={{
|
|
title: t("tabs.favorites"),
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/heart.fill.png")
|
|
: (_e) => ({ sfSymbol: "heart.fill" }),
|
|
}}
|
|
/>
|
|
<NativeTabs.Screen
|
|
name='(watchlists)'
|
|
options={{
|
|
title: t("watchlists.title"),
|
|
tabBarItemHidden:
|
|
!settings?.streamyStatsServerUrl || settings?.hideWatchlistsTab,
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/list.png")
|
|
: (_e) => ({ sfSymbol: "list.bullet.rectangle" }),
|
|
}}
|
|
/>
|
|
<NativeTabs.Screen
|
|
name='(libraries)'
|
|
options={{
|
|
title: t("tabs.library"),
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/server.rack.png")
|
|
: (_e) => ({ sfSymbol: "rectangle.stack.fill" }),
|
|
}}
|
|
/>
|
|
<NativeTabs.Screen
|
|
name='(custom-links)'
|
|
options={{
|
|
title: t("tabs.custom_links"),
|
|
tabBarItemHidden: !settings?.showCustomMenuLinks,
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/list.png")
|
|
: (_e) => ({ sfSymbol: "list.dash.fill" }),
|
|
}}
|
|
/>
|
|
<NativeTabs.Screen
|
|
name='(settings)'
|
|
options={{
|
|
title: t("tabs.settings"),
|
|
tabBarItemHidden: !Platform.isTV,
|
|
tabBarIcon:
|
|
Platform.OS === "android"
|
|
? (_e) => require("@/assets/icons/gear.png") //Should maybe use other libraries to have it uniform
|
|
: (_e) => ({ sfSymbol: "gearshape.fill" }),
|
|
}}
|
|
/>
|
|
</NativeTabs>
|
|
<MiniPlayerBar />
|
|
<MusicPlaybackEngine />
|
|
</View>
|
|
);
|
|
}
|