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 && (