diff --git a/app/(auth)/(tabs)/(custom-links)/_layout.tsx b/app/(auth)/(tabs)/(custom-links)/_layout.tsx new file mode 100644 index 00000000..ed0529d4 --- /dev/null +++ b/app/(auth)/(tabs)/(custom-links)/_layout.tsx @@ -0,0 +1,20 @@ +import {Stack} from "expo-router"; +import { Platform } from "react-native"; + +export default function CustomMenuLayout() { + return ( + + + + ); +} diff --git a/app/(auth)/(tabs)/(custom-links)/index.tsx b/app/(auth)/(tabs)/(custom-links)/index.tsx new file mode 100644 index 00000000..76b10fb8 --- /dev/null +++ b/app/(auth)/(tabs)/(custom-links)/index.tsx @@ -0,0 +1,73 @@ +import {FlatList, TouchableOpacity, View} from "react-native"; +import {useSafeAreaInsets} from "react-native-safe-area-context"; +import React, {useCallback, useEffect, useState} from "react"; +import {useAtom} from "jotai/index"; +import {apiAtom} from "@/providers/JellyfinProvider"; +import {ListItem} from "@/components/ListItem"; +import * as WebBrowser from 'expo-web-browser'; +import Ionicons from '@expo/vector-icons/Ionicons'; +import {Text} from "@/components/common/Text"; + +export interface MenuLink { + name: string, + url: string, + icon: string +} + +export default function menuLinks() { + const [api] = useAtom(apiAtom); + const insets = useSafeAreaInsets() + const [menuLinks, setMenuLinks] = useState([]) + + const getMenuLinks = useCallback(async () => { + try { + const response = await api?.axiosInstance.get(api?.basePath + "/web/config.json") + const config = response?.data; + + if (!config && !config.hasOwnProperty("menuLinks")) { + console.error("Menu links not found"); + return; + } + + setMenuLinks(config?.menuLinks as MenuLink[]) + } catch (error) { + console.error("Failed to retrieve config:", error); + } + }, + [api] + ) + + useEffect(() => { getMenuLinks() }, []); + return ( + ( + WebBrowser.openBrowserAsync(item.url) }> + } + /> + + ) + } + ItemSeparatorComponent={() => ( + + )} + ListEmptyComponent={ + + No links + + } + /> + ); +} \ No newline at end of file diff --git a/app/(auth)/(tabs)/_layout.tsx b/app/(auth)/(tabs)/_layout.tsx index e717d16d..01e7ea73 100644 --- a/app/(auth)/(tabs)/_layout.tsx +++ b/app/(auth)/(tabs)/_layout.tsx @@ -18,6 +18,7 @@ import type { TabNavigationState, } from "@react-navigation/native"; import { SystemBars } from "react-native-edge-to-edge"; +import {useSettings} from "@/utils/atoms/settings"; export const NativeTabs = withLayoutContext< BottomTabNavigationOptions, @@ -27,6 +28,7 @@ export const NativeTabs = withLayoutContext< >(Navigator); export default function TabLayout() { + const [settings] = useSettings(); return ( <> )} + + + + Show Custom Menu Links + + Show custom menu links defined inside your Jellyfin web config.json file + + + Linking.openURL("https://jellyfin.org/docs/general/clients/web-config/#custom-menu-links") + } + > + More info + + + updateSettings({ showCustomMenuLinks: value })} + /> + diff --git a/utils/atoms/settings.ts b/utils/atoms/settings.ts index 5d47c3dd..bb1f26ab 100644 --- a/utils/atoms/settings.ts +++ b/utils/atoms/settings.ts @@ -73,7 +73,8 @@ export type Settings = { rewindSkipTime: number; optimizedVersionsServerUrl?: string | null; downloadMethod: "optimized" | "remux"; - autoDownload: boolean; + autoDownload: boolean, + showCustomMenuLinks: boolean; }; const loadSettings = (): Settings => { @@ -103,6 +104,7 @@ const loadSettings = (): Settings => { optimizedVersionsServerUrl: null, downloadMethod: "remux", autoDownload: false, + showCustomMenuLinks: false, }; try {