diff --git a/app/(auth)/(tabs)/home/index.tsx b/app/(auth)/(tabs)/home/index.tsx index 3dde6087..b314910f 100644 --- a/app/(auth)/(tabs)/home/index.tsx +++ b/app/(auth)/(tabs)/home/index.tsx @@ -2,6 +2,7 @@ import { Button } from "@/components/Button"; import { Text } from "@/components/common/Text"; import { LargeMovieCarousel } from "@/components/home/LargeMovieCarousel"; import { ScrollingCollectionList } from "@/components/home/ScrollingCollectionList"; +import { Loader } from "@/components/Loader"; import { MediaListSection } from "@/components/medialists/MediaListSection"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { useSettings } from "@/utils/atoms/settings"; @@ -19,12 +20,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useRouter } from "expo-router"; import { useAtom } from "jotai"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { - ActivityIndicator, - RefreshControl, - ScrollView, - View, -} from "react-native"; +import { RefreshControl, ScrollView, View } from "react-native"; export default function index() { const router = useRouter(); @@ -250,10 +246,10 @@ export default function index() { ); - if (isLoading) + if (true) return ( - + ); diff --git a/app/(auth)/(tabs)/library/collections/[collectionId].tsx b/app/(auth)/(tabs)/library/collections/[collectionId].tsx index 90156f77..626366b6 100644 --- a/app/(auth)/(tabs)/library/collections/[collectionId].tsx +++ b/app/(auth)/(tabs)/library/collections/[collectionId].tsx @@ -3,6 +3,7 @@ import { TouchableItemRouter } from "@/components/common/TouchableItemRouter"; import { FilterButton } from "@/components/filters/FilterButton"; import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton"; import { ItemCardText } from "@/components/ItemCardText"; +import { Loader } from "@/components/Loader"; import MoviePoster from "@/components/posters/MoviePoster"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { @@ -24,7 +25,7 @@ import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; import { useLocalSearchParams } from "expo-router"; import { useAtom } from "jotai"; import React, { useCallback, useMemo } from "react"; -import { ActivityIndicator, ScrollView, View } from "react-native"; +import { ScrollView, View } from "react-native"; const page: React.FC = () => { const searchParams = useLocalSearchParams(); @@ -284,12 +285,10 @@ const page: React.FC = () => { {!type && isFetching && ( - )} diff --git a/app/(auth)/(tabs)/library/index.tsx b/app/(auth)/(tabs)/library/index.tsx index ec2952f5..56295670 100644 --- a/app/(auth)/(tabs)/library/index.tsx +++ b/app/(auth)/(tabs)/library/index.tsx @@ -1,35 +1,21 @@ import { Text } from "@/components/common/Text"; +import { Loader } from "@/components/Loader"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; -import { getItemsApi, getUserViewsApi } from "@jellyfin/sdk/lib/utils/api"; -import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl"; +import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; +import { getUserViewsApi } from "@jellyfin/sdk/lib/utils/api"; +import { FlashList } from "@shopify/flash-list"; +import { useQuery } from "@tanstack/react-query"; +import { Image } from "expo-image"; import { useRouter } from "expo-router"; import { useAtom } from "jotai"; -import { useCallback, useMemo, useState } from "react"; -import { - ActivityIndicator, - RefreshControl, - ScrollView, - TouchableOpacity, - View, -} from "react-native"; -import { Ionicons } from "@expo/vector-icons"; -import { useSettings } from "@/utils/atoms/settings"; -import { FlashList } from "@shopify/flash-list"; -import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; -import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl"; -import { Image } from "expo-image"; -import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { useMemo } from "react"; +import { TouchableOpacity, View } from "react-native"; export default function index() { - const router = useRouter(); - const queryClient = useQueryClient(); - const [api] = useAtom(apiAtom); const [user] = useAtom(userAtom); - const [loading, setLoading] = useState(false); - const [settings, _] = useSettings(); - const { data, isLoading: isLoading } = useQuery({ queryKey: ["user-views", user?.Id], queryFn: async () => { @@ -50,7 +36,7 @@ export default function index() { if (isLoading) return ( - + ); diff --git a/app/(auth)/(tabs)/search/index.tsx b/app/(auth)/(tabs)/search/index.tsx index 7465a3a7..3465da81 100644 --- a/app/(auth)/(tabs)/search/index.tsx +++ b/app/(auth)/(tabs)/search/index.tsx @@ -4,28 +4,19 @@ import { Text } from "@/components/common/Text"; import { TouchableItemRouter } from "@/components/common/TouchableItemRouter"; import ContinueWatchingPoster from "@/components/ContinueWatchingPoster"; import { ItemCardText } from "@/components/ItemCardText"; +import { Loader } from "@/components/Loader"; import AlbumCover from "@/components/posters/AlbumCover"; import MoviePoster from "@/components/posters/MoviePoster"; -import Poster from "@/components/posters/Poster"; import SeriesPoster from "@/components/posters/SeriesPoster"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; -import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl"; import { getUserItemData } from "@/utils/jellyfin/user-library/getUserItemData"; -import { Ionicons } from "@expo/vector-icons"; import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { getSearchApi } from "@jellyfin/sdk/lib/utils/api"; import { useQuery } from "@tanstack/react-query"; -import { router, Stack, useNavigation } from "expo-router"; +import { router, useNavigation } from "expo-router"; import { useAtom } from "jotai"; import React, { useLayoutEffect, useMemo, useState } from "react"; -import { - ActivityIndicator, - Platform, - ScrollView, - TouchableOpacity, - View, -} from "react-native"; -import _ from "lodash"; +import { Platform, ScrollView, TouchableOpacity, View } from "react-native"; import { useDebounce } from "use-debounce"; const exampleSearches = [ @@ -308,7 +299,7 @@ export default function search() { /> {loading ? ( - + ) : noResults && debouncedSearch.length > 0 ? ( diff --git a/app/(auth)/collections/[collectionId].tsx b/app/(auth)/collections/[collectionId].tsx index e7999e6e..00601193 100644 --- a/app/(auth)/collections/[collectionId].tsx +++ b/app/(auth)/collections/[collectionId].tsx @@ -1,4 +1,5 @@ import { Text } from "@/components/common/Text"; +import { Loader } from "@/components/Loader"; import ArtistPoster from "@/components/posters/ArtistPoster"; import MoviePoster from "@/components/posters/MoviePoster"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; @@ -13,12 +14,7 @@ import { useQuery } from "@tanstack/react-query"; import { router, useLocalSearchParams } from "expo-router"; import { useAtom } from "jotai"; import { useMemo, useState } from "react"; -import { - ActivityIndicator, - ScrollView, - TouchableOpacity, - View, -} from "react-native"; +import { ScrollView, TouchableOpacity, View } from "react-native"; const page: React.FC = () => { const searchParams = useLocalSearchParams(); @@ -154,7 +150,7 @@ const page: React.FC = () => { {isLoading ? ( - + ) : ( diff --git a/app/(auth)/downloads.tsx b/app/(auth)/downloads.tsx index 2aff6483..73603158 100644 --- a/app/(auth)/downloads.tsx +++ b/app/(auth)/downloads.tsx @@ -1,23 +1,18 @@ import { Text } from "@/components/common/Text"; import { MovieCard } from "@/components/downloads/MovieCard"; import { SeriesCard } from "@/components/downloads/SeriesCard"; +import { Loader } from "@/components/Loader"; +import { runningProcesses } from "@/utils/atoms/downloads"; +import { queueAtom } from "@/utils/atoms/queue"; +import { Ionicons } from "@expo/vector-icons"; import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { useQuery } from "@tanstack/react-query"; -import { useEffect, useMemo } from "react"; -import { - ActivityIndicator, - ScrollView, - TouchableOpacity, - View, -} from "react-native"; -import { useAtom } from "jotai"; -import { runningProcesses } from "@/utils/atoms/downloads"; import { router } from "expo-router"; -import { Ionicons } from "@expo/vector-icons"; import { FFmpegKit } from "ffmpeg-kit-react-native"; -import * as FileSystem from "expo-file-system"; -import { queueAtom } from "@/utils/atoms/queue"; +import { useAtom } from "jotai"; +import { useMemo } from "react"; +import { ScrollView, TouchableOpacity, View } from "react-native"; const downloads: React.FC = () => { const [process, setProcess] = useAtom(runningProcesses); @@ -27,14 +22,14 @@ const downloads: React.FC = () => { queryKey: ["downloaded_files", process?.item.Id], queryFn: async () => JSON.parse( - (await AsyncStorage.getItem("downloaded_files")) || "[]", + (await AsyncStorage.getItem("downloaded_files")) || "[]" ) as BaseItemDto[], staleTime: 0, }); const movies = useMemo( () => downloadedFiles?.filter((f) => f.Type === "Movie") || [], - [downloadedFiles], + [downloadedFiles] ); const groupedBySeries = useMemo(() => { @@ -61,7 +56,7 @@ const downloads: React.FC = () => { if (isLoading) { return ( - + ); } diff --git a/app/(auth)/items/[id].tsx b/app/(auth)/items/[id].tsx index fe4d5f3e..91cbc7cf 100644 --- a/app/(auth)/items/[id].tsx +++ b/app/(auth)/items/[id].tsx @@ -6,6 +6,7 @@ import { playingAtom, } from "@/components/CurrentlyPlayingBar"; import { DownloadItem } from "@/components/DownloadItem"; +import { Loader } from "@/components/Loader"; import { OverviewText } from "@/components/OverviewText"; import { PlayButton } from "@/components/PlayButton"; import { PlayedStatus } from "@/components/PlayedStatus"; @@ -34,7 +35,7 @@ import { Image } from "expo-image"; import { useLocalSearchParams } from "expo-router"; import { useAtom } from "jotai"; import { useCallback, useMemo, useState } from "react"; -import { ActivityIndicator, ScrollView, View } from "react-native"; +import { View } from "react-native"; import CastContext, { PlayServicesState, useCastDevice, @@ -194,7 +195,7 @@ const page: React.FC = () => { if (l1) return ( - + ); diff --git a/app/(auth)/songs/[songId].tsx b/app/(auth)/songs/[songId].tsx index cf6e74f0..4d1aa7f3 100644 --- a/app/(auth)/songs/[songId].tsx +++ b/app/(auth)/songs/[songId].tsx @@ -1,37 +1,38 @@ +import { AudioTrackSelector } from "@/components/AudioTrackSelector"; +import { Bitrate, BitrateSelector } from "@/components/BitrateSelector"; +import { Chromecast } from "@/components/Chromecast"; import { Text } from "@/components/common/Text"; +import { + currentlyPlayingItemAtom, + playingAtom, +} from "@/components/CurrentlyPlayingBar"; import { DownloadItem } from "@/components/DownloadItem"; +import { Loader } from "@/components/Loader"; +import { MoviesTitleHeader } from "@/components/movies/MoviesTitleHeader"; +import { ParallaxScrollView } from "@/components/ParallaxPage"; +import { PlayButton } from "@/components/PlayButton"; +import { NextEpisodeButton } from "@/components/series/NextEpisodeButton"; import { SimilarItems } from "@/components/SimilarItems"; +import { SubtitleTrackSelector } from "@/components/SubtitleTrackSelector"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; +import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl"; +import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById"; +import { getStreamUrl } from "@/utils/jellyfin/media/getStreamUrl"; +import { getUserItemData } from "@/utils/jellyfin/user-library/getUserItemData"; +import { chromecastProfile } from "@/utils/profiles/chromecast"; +import ios from "@/utils/profiles/ios"; +import { getMediaInfoApi } from "@jellyfin/sdk/lib/utils/api"; import { useQuery } from "@tanstack/react-query"; import { Image } from "expo-image"; import { useLocalSearchParams, useNavigation } from "expo-router"; import { useAtom } from "jotai"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { ActivityIndicator, ScrollView, View } from "react-native"; -import { getUserItemData } from "@/utils/jellyfin/user-library/getUserItemData"; -import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl"; -import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById"; -import { PlayButton } from "@/components/PlayButton"; -import { Bitrate, BitrateSelector } from "@/components/BitrateSelector"; -import { getMediaInfoApi } from "@jellyfin/sdk/lib/utils/api"; -import { getStreamUrl } from "@/utils/jellyfin/media/getStreamUrl"; +import { ScrollView, View } from "react-native"; import CastContext, { PlayServicesState, useCastDevice, useRemoteMediaClient, } from "react-native-google-cast"; -import { chromecastProfile } from "@/utils/profiles/chromecast"; -import { - currentlyPlayingItemAtom, - playingAtom, -} from "@/components/CurrentlyPlayingBar"; -import { AudioTrackSelector } from "@/components/AudioTrackSelector"; -import { SubtitleTrackSelector } from "@/components/SubtitleTrackSelector"; -import { NextEpisodeButton } from "@/components/series/NextEpisodeButton"; -import { MoviesTitleHeader } from "@/components/movies/MoviesTitleHeader"; -import { ParallaxScrollView } from "@/components/ParallaxPage"; -import { Chromecast } from "@/components/Chromecast"; -import ios from "@/utils/profiles/ios"; const page: React.FC = () => { const local = useLocalSearchParams(); @@ -84,12 +85,12 @@ const page: React.FC = () => { quality: 90, width: 1000, }), - [item], + [item] ); const logoUrl = useMemo( () => (item?.Type === "Movie" ? getLogoImageUrlById({ api, item }) : null), - [item], + [item] ); const { data: sessionData } = useQuery({ @@ -173,13 +174,13 @@ const page: React.FC = () => { setPlaying(true); } }, - [playbackUrl, item], + [playbackUrl, item] ); if (l1) return ( - + ); diff --git a/components/Button.tsx b/components/Button.tsx index 01b88963..813c4222 100644 --- a/components/Button.tsx +++ b/components/Button.tsx @@ -1,6 +1,7 @@ -import React, { PropsWithChildren, ReactNode, useMemo } from "react"; -import { TouchableOpacity, Text, ActivityIndicator, View } from "react-native"; import * as Haptics from "expo-haptics"; +import React, { PropsWithChildren, ReactNode, useMemo } from "react"; +import { Text, TouchableOpacity, View } from "react-native"; +import { Loader } from "./Loader"; interface ButtonProps extends React.ComponentProps { onPress?: () => void; @@ -57,7 +58,7 @@ export const Button: React.FC> = ({ {...props} > {loading ? ( - + ) : ( { renderLoader={ item?.Type !== "Audio" && ( - + ) } diff --git a/components/DownloadItem.tsx b/components/DownloadItem.tsx index df7d8b92..e58a5a3e 100644 --- a/components/DownloadItem.tsx +++ b/components/DownloadItem.tsx @@ -9,7 +9,8 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; import { useQuery } from "@tanstack/react-query"; import { router } from "expo-router"; import { useAtom } from "jotai"; -import { ActivityIndicator, TouchableOpacity, View } from "react-native"; +import { TouchableOpacity, View } from "react-native"; +import { Loader } from "./Loader"; import ProgressCircle from "./ProgressCircle"; type DownloadProps = { @@ -39,7 +40,7 @@ export const DownloadItem: React.FC = ({ if (!item.Id) return false; const data: BaseItemDto[] = JSON.parse( - (await AsyncStorage.getItem("downloaded_files")) || "[]", + (await AsyncStorage.getItem("downloaded_files")) || "[]" ); return data.some((d) => d.Id === item.Id); @@ -50,7 +51,7 @@ export const DownloadItem: React.FC = ({ if (isLoading || isLoadingDownloaded) { return ( - + ); } @@ -72,7 +73,7 @@ export const DownloadItem: React.FC = ({ > {process.progress === 0 ? ( - + ) : ( = ({ ...props }) => { + return ( + + ); +}; diff --git a/components/Loading.tsx b/components/Loading.tsx deleted file mode 100644 index bee94aad..00000000 --- a/components/Loading.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { ActivityIndicator, View } from "react-native"; - -export const Loading: React.FC = () => { - return ( - - - - ); -}; diff --git a/components/SimilarItems.tsx b/components/SimilarItems.tsx index 2879c05d..45624a52 100644 --- a/components/SimilarItems.tsx +++ b/components/SimilarItems.tsx @@ -6,14 +6,10 @@ import { useQuery } from "@tanstack/react-query"; import { router } from "expo-router"; import { useAtom } from "jotai"; import { useMemo } from "react"; -import { - ActivityIndicator, - ScrollView, - TouchableOpacity, - View, -} from "react-native"; -import { ItemCardText } from "./ItemCardText"; +import { ScrollView, TouchableOpacity, View } from "react-native"; import { Text } from "./common/Text"; +import { ItemCardText } from "./ItemCardText"; +import { Loader } from "./Loader"; type SimilarItemsProps = { itemId: string; @@ -49,7 +45,7 @@ export const SimilarItems: React.FC = ({ itemId }) => { Similar items {isLoading ? ( - + ) : ( diff --git a/components/common/HorrizontalScroll.tsx b/components/common/HorrizontalScroll.tsx index 40a8deaf..b5b78c6a 100644 --- a/components/common/HorrizontalScroll.tsx +++ b/components/common/HorrizontalScroll.tsx @@ -1,16 +1,11 @@ import React, { useEffect } from "react"; -import { - ScrollView, - View, - ViewStyle, - ActivityIndicator, - ScrollViewProps, -} from "react-native"; +import { ScrollView, ScrollViewProps, View, ViewStyle } from "react-native"; import Animated, { useAnimatedStyle, useSharedValue, withTiming, } from "react-native-reanimated"; +import { Loader } from "../Loader"; import { Text } from "./Text"; interface HorizontalScrollProps extends ScrollViewProps { @@ -58,7 +53,7 @@ export function HorizontalScroll({ loadingContainerStyle, ]} > - + ); } diff --git a/components/home/LargeMovieCarousel.tsx b/components/home/LargeMovieCarousel.tsx index 1ca37a44..70d64814 100644 --- a/components/home/LargeMovieCarousel.tsx +++ b/components/home/LargeMovieCarousel.tsx @@ -1,22 +1,22 @@ -import { ActivityIndicator, View, ViewProps } from "react-native"; +import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; +import { useSettings } from "@/utils/atoms/settings"; +import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl"; +import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById"; import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { getItemsApi } from "@jellyfin/sdk/lib/utils/api"; import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; +import { Image } from "expo-image"; import { useRouter } from "expo-router"; import { useAtom } from "jotai"; -import { useSettings } from "@/utils/atoms/settings"; -import { Dimensions } from "react-native"; +import React, { useMemo } from "react"; +import { Dimensions, View, ViewProps } from "react-native"; import { useSharedValue } from "react-native-reanimated"; import Carousel, { ICarouselInstance, Pagination, } from "react-native-reanimated-carousel"; -import React, { useMemo } from "react"; -import { Image } from "expo-image"; -import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById"; -import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl"; import { TouchableItemRouter } from "../common/TouchableItemRouter"; +import { Loader } from "../Loader"; interface Props extends ViewProps {} @@ -84,7 +84,7 @@ export const LargeMovieCarousel: React.FC = ({ ...props }) => { if (l1 || l2) return ( - + ); diff --git a/components/settings/SettingToggles.tsx b/components/settings/SettingToggles.tsx index f64d6db4..7028f7b8 100644 --- a/components/settings/SettingToggles.tsx +++ b/components/settings/SettingToggles.tsx @@ -1,18 +1,12 @@ -import { - ActivityIndicator, - Linking, - Switch, - TouchableOpacity, - View, -} from "react-native"; -import { Text } from "../common/Text"; -import { useSettings } from "@/utils/atoms/settings"; -import * as DropdownMenu from "zeego/dropdown-menu"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; +import { useSettings } from "@/utils/atoms/settings"; import { getItemsApi } from "@jellyfin/sdk/lib/utils/api"; import { useQuery } from "@tanstack/react-query"; import { useAtom } from "jotai"; -import { useState } from "react"; +import { Linking, Switch, TouchableOpacity, View } from "react-native"; +import * as DropdownMenu from "zeego/dropdown-menu"; +import { Text } from "../common/Text"; +import { Loader } from "../Loader"; export const SettingToggles: React.FC = () => { const [settings, updateSettings] = useSettings(); @@ -83,7 +77,7 @@ export const SettingToggles: React.FC = () => { { Linking.openURL( - "https://github.com/lostb1t/jellyfin-plugin-media-lists", + "https://github.com/lostb1t/jellyfin-plugin-media-lists" ); }} > @@ -121,7 +115,7 @@ export const SettingToggles: React.FC = () => { mediaListCollectionIds: settings?.mediaListCollectionIds.includes(mlc.Id!) ? settings?.mediaListCollectionIds.filter( - (id) => id !== mlc.Id, + (id) => id !== mlc.Id ) : [...settings?.mediaListCollectionIds, mlc.Id!], }); @@ -131,7 +125,7 @@ export const SettingToggles: React.FC = () => { ))} {isLoadingMediaListCollections && ( - + )} {mediaListCollections?.length === 0 && (