diff --git a/app/(auth)/(tabs)/(home)/_layout.tsx b/app/(auth)/(tabs)/(home)/_layout.tsx index 6c111607..dee024fd 100644 --- a/app/(auth)/(tabs)/(home)/_layout.tsx +++ b/app/(auth)/(tabs)/(home)/_layout.tsx @@ -3,7 +3,7 @@ import { Ionicons, Feather } from "@expo/vector-icons"; import { Stack, useRouter } from "expo-router"; import { Platform, TouchableOpacity, View } from "react-native"; import { useTranslation } from "react-i18next"; -const Chromecast = !Platform.isTV ? require("@/components/Chromecast") : null; +const Chromecast = Platform.isTV ? null : require("@/components/Chromecast"); import { useAtom } from "jotai"; import { userAtom } from "@/providers/JellyfinProvider"; import { useSessions, useSessionsProps } from "@/hooks/useSessions"; @@ -25,7 +25,7 @@ export default function IndexLayout() { headerLargeStyle: { backgroundColor: "black", }, - headerTransparent: Platform.OS === "ios" ? true : false, + headerTransparent: Platform.OS === "ios", headerShadowVisible: false, headerRight: () => ( @@ -113,7 +113,7 @@ export default function IndexLayout() { title: "", headerShown: true, headerBlurEffect: "prominent", - headerTransparent: Platform.OS === "ios" ? true : false, + headerTransparent: Platform.OS === "ios", headerShadowVisible: false, }} /> @@ -137,7 +137,7 @@ const SettingsButton = () => { const SessionsButton = () => { const router = useRouter(); - const { sessions = [], _ } = useSessions({} as useSessionsProps); + const { sessions = [] } = useSessions({} as useSessionsProps); return ( { }} > - { useEffect(() => { (async () => { if (_apiUrl) { - setServer({ + await setServer({ address: _apiUrl, }); @@ -181,7 +181,7 @@ const Login: React.FC = () => { return; } - setServer({ address: url }); + await setServer({ address: url }); }, []); const handleQuickConnect = async () => { @@ -237,11 +237,12 @@ const Login: React.FC = () => { setCredentials({ ...credentials, username: text }) } value={credentials.username} - secureTextEntry={false} keyboardType="default" returnKeyType="done" autoCapitalize="none" - textContentType="username" + // Changed from username to oneTimeCode because it is a known issue in RN + // https://github.com/facebook/react-native/issues/47106#issuecomment-2521270037 + textContentType="oneTimeCode" clearButtonMode="while-editing" maxLength={500} /> @@ -324,17 +325,17 @@ const Login: React.FC = () => { {t("server.connect_button")} { + onServerSelect={async (server) => { setServerURL(server.address); if (server.serverName) { setServerName(server.serverName); } - handleConnect(server.address); + await handleConnect(server.address); }} /> { - handleConnect(s.address); + onServerSelect={async (s) => { + await handleConnect(s.address); }} /> diff --git a/components/AddToFavorites.tsx b/components/AddToFavorites.tsx index 945e9988..b190dced 100644 --- a/components/AddToFavorites.tsx +++ b/components/AddToFavorites.tsx @@ -1,16 +1,17 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client"; import { useFavorite } from "@/hooks/useFavorite"; -import { View } from "react-native"; +import {View, ViewProps} from "react-native"; import { RoundButton } from "@/components/RoundButton"; +import {FC} from "react"; interface Props extends ViewProps { item: BaseItemDto; } -export const AddToFavorites = ({ item, ...props }) => { - const { isFavorite, toggleFavorite, _} = useFavorite(item); - +export const AddToFavorites:FC = ({ item, ...props }) => { + const { isFavorite, toggleFavorite } = useFavorite(item); + return ( void; } -export const ItemImage: React.FC = ({ +export const ItemImage: FC = ({ item, variant = "Primary", quality = 90, @@ -53,7 +52,7 @@ export const ItemImage: React.FC = ({ if (!source?.uri) return ( void; } const AudioSlider: React.FC = ({ setVisibility }) => { - if (Platform.isTV) return; + if (Platform.isTV) { + return; + } const volume = useSharedValue(50); // Explicitly type as number const min = useSharedValue(0); // Explicitly type as number const max = useSharedValue(100); // Explicitly type as number - const timeoutRef = useRef(null); // Use a ref to store the timeout ID + const timeoutRef = useRef(null); // Use a ref to store the timeout ID useEffect(() => { const fetchInitialVolume = async () => { @@ -50,7 +50,7 @@ const AudioSlider: React.FC = ({ setVisibility }) => { }; useEffect(() => { - const volumeListener = VolumeManager.addVolumeListener((result) => { + const volumeListener = VolumeManager.addVolumeListener((result: VolumeResult) => { volume.value = result.volume * 100; setVisibility(true); diff --git a/providers/WebSocketProvider.tsx b/providers/WebSocketProvider.tsx index 1311459f..b61c1967 100644 --- a/providers/WebSocketProvider.tsx +++ b/providers/WebSocketProvider.tsx @@ -7,16 +7,13 @@ import React, { useMemo, useCallback, } from "react"; -import { Alert, AppState, AppStateStatus } from "react-native"; +import { AppState, AppStateStatus } from "react-native"; import { useAtomValue } from "jotai"; -import { useQuery } from "@tanstack/react-query"; import { apiAtom, getOrSetDeviceId, - userAtom, } from "@/providers/JellyfinProvider"; import { getSessionApi } from "@jellyfin/sdk/lib/utils/api"; -import native from "@/utils/profiles/native"; interface WebSocketProviderProps { children: ReactNode; @@ -30,7 +27,6 @@ interface WebSocketContextType { const WebSocketContext = createContext(null); export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { - const user = useAtomValue(userAtom); const api = useAtomValue(apiAtom); const [ws, setWs] = useState(null); const [isConnected, setIsConnected] = useState(false); @@ -40,7 +36,9 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { }, []); const connectWebSocket = useCallback(() => { - if (!deviceId || !api?.accessToken) return; + if (!deviceId || !api?.accessToken) { + return; + } const protocol = api.basePath.includes("https") ? "wss" : "ws"; const url = `${protocol}://${api.basePath @@ -50,7 +48,7 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { }&deviceId=${deviceId}`; const newWebSocket = new WebSocket(url); - let keepAliveInterval: NodeJS.Timeout | null = null; + let keepAliveInterval: number | null = null; newWebSocket.onopen = () => { setIsConnected(true); @@ -67,14 +65,18 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { }; newWebSocket.onclose = () => { - if (keepAliveInterval) clearInterval(keepAliveInterval); + if (keepAliveInterval) { + clearInterval(keepAliveInterval); + } setIsConnected(false); }; setWs(newWebSocket); return () => { - if (keepAliveInterval) clearInterval(keepAliveInterval); + if (keepAliveInterval) { + clearInterval(keepAliveInterval); + } newWebSocket.close(); }; }, [api, deviceId]); @@ -85,7 +87,9 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { }, [connectWebSocket]); useEffect(() => { - if (!deviceId || !api || !api?.accessToken) return; + if (!deviceId || !api || !api?.accessToken) { + return; + } const init = async () => { await getSessionApi(api).postFullCapabilities({ diff --git a/utils/jellyfin/session/capabilities.ts b/utils/jellyfin/session/capabilities.ts index 99ef5cb1..c0f3b295 100644 --- a/utils/jellyfin/session/capabilities.ts +++ b/utils/jellyfin/session/capabilities.ts @@ -1,12 +1,8 @@ import { Settings } from "@/utils/atoms/settings"; -import ios from "@/utils/profiles/ios"; import native from "@/utils/profiles/native"; -import old from "@/utils/profiles/old"; import { Api } from "@jellyfin/sdk"; import { AxiosError, AxiosResponse } from "axios"; -import { useMemo } from "react"; import { getAuthHeaders } from "../jellyfin"; -import iosFmp4 from "@/utils/profiles/iosFmp4"; interface PostCapabilitiesParams { api: Api | null | undefined; @@ -25,7 +21,6 @@ export const postCapabilities = async ({ api, itemId, sessionId, - deviceProfile, }: PostCapabilitiesParams): Promise => { if (!api || !itemId || !sessionId) { throw new Error("Missing parameters for marking item as not played");