fix: loading indicator style

This commit is contained in:
Fredrik Burmester
2024-08-18 07:44:28 +02:00
parent d56bb79ac2
commit 550fc39faa
17 changed files with 116 additions and 161 deletions

View File

@@ -2,6 +2,7 @@ import { Button } from "@/components/Button";
import { Text } from "@/components/common/Text"; import { Text } from "@/components/common/Text";
import { LargeMovieCarousel } from "@/components/home/LargeMovieCarousel"; import { LargeMovieCarousel } from "@/components/home/LargeMovieCarousel";
import { ScrollingCollectionList } from "@/components/home/ScrollingCollectionList"; import { ScrollingCollectionList } from "@/components/home/ScrollingCollectionList";
import { Loader } from "@/components/Loader";
import { MediaListSection } from "@/components/medialists/MediaListSection"; import { MediaListSection } from "@/components/medialists/MediaListSection";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { useSettings } from "@/utils/atoms/settings"; import { useSettings } from "@/utils/atoms/settings";
@@ -19,12 +20,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useRouter } from "expo-router"; import { useRouter } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { import { RefreshControl, ScrollView, View } from "react-native";
ActivityIndicator,
RefreshControl,
ScrollView,
View,
} from "react-native";
export default function index() { export default function index() {
const router = useRouter(); const router = useRouter();
@@ -250,10 +246,10 @@ export default function index() {
</View> </View>
); );
if (isLoading) if (true)
return ( return (
<View className="justify-center items-center h-full"> <View className="justify-center items-center h-full">
<ActivityIndicator /> <Loader />
</View> </View>
); );

View File

@@ -3,6 +3,7 @@ import { TouchableItemRouter } from "@/components/common/TouchableItemRouter";
import { FilterButton } from "@/components/filters/FilterButton"; import { FilterButton } from "@/components/filters/FilterButton";
import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton"; import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton";
import { ItemCardText } from "@/components/ItemCardText"; import { ItemCardText } from "@/components/ItemCardText";
import { Loader } from "@/components/Loader";
import MoviePoster from "@/components/posters/MoviePoster"; import MoviePoster from "@/components/posters/MoviePoster";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { import {
@@ -24,7 +25,7 @@ import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
import { useLocalSearchParams } from "expo-router"; import { useLocalSearchParams } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import React, { useCallback, useMemo } from "react"; import React, { useCallback, useMemo } from "react";
import { ActivityIndicator, ScrollView, View } from "react-native"; import { ScrollView, View } from "react-native";
const page: React.FC = () => { const page: React.FC = () => {
const searchParams = useLocalSearchParams(); const searchParams = useLocalSearchParams();
@@ -284,12 +285,10 @@ const page: React.FC = () => {
</View> </View>
</ScrollView> </ScrollView>
{!type && isFetching && ( {!type && isFetching && (
<ActivityIndicator <Loader
style={{ style={{
marginTop: 300, marginTop: 300,
}} }}
size={"small"}
color={"white"}
/> />
)} )}
</View> </View>

View File

@@ -1,35 +1,21 @@
import { Text } from "@/components/common/Text"; import { Text } from "@/components/common/Text";
import { Loader } from "@/components/Loader";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { getItemsApi, getUserViewsApi } from "@jellyfin/sdk/lib/utils/api"; import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl";
import { useQuery, useQueryClient } from "@tanstack/react-query"; 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 { useRouter } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useCallback, useMemo, useState } from "react"; import { useMemo } from "react";
import { import { TouchableOpacity, View } from "react-native";
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";
export default function index() { export default function index() {
const router = useRouter();
const queryClient = useQueryClient();
const [api] = useAtom(apiAtom); const [api] = useAtom(apiAtom);
const [user] = useAtom(userAtom); const [user] = useAtom(userAtom);
const [loading, setLoading] = useState(false);
const [settings, _] = useSettings();
const { data, isLoading: isLoading } = useQuery({ const { data, isLoading: isLoading } = useQuery({
queryKey: ["user-views", user?.Id], queryKey: ["user-views", user?.Id],
queryFn: async () => { queryFn: async () => {
@@ -50,7 +36,7 @@ export default function index() {
if (isLoading) if (isLoading)
return ( return (
<View className="justify-center items-center h-full"> <View className="justify-center items-center h-full">
<ActivityIndicator /> <Loader />
</View> </View>
); );

View File

@@ -4,28 +4,19 @@ import { Text } from "@/components/common/Text";
import { TouchableItemRouter } from "@/components/common/TouchableItemRouter"; import { TouchableItemRouter } from "@/components/common/TouchableItemRouter";
import ContinueWatchingPoster from "@/components/ContinueWatchingPoster"; import ContinueWatchingPoster from "@/components/ContinueWatchingPoster";
import { ItemCardText } from "@/components/ItemCardText"; import { ItemCardText } from "@/components/ItemCardText";
import { Loader } from "@/components/Loader";
import AlbumCover from "@/components/posters/AlbumCover"; import AlbumCover from "@/components/posters/AlbumCover";
import MoviePoster from "@/components/posters/MoviePoster"; import MoviePoster from "@/components/posters/MoviePoster";
import Poster from "@/components/posters/Poster";
import SeriesPoster from "@/components/posters/SeriesPoster"; import SeriesPoster from "@/components/posters/SeriesPoster";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl";
import { getUserItemData } from "@/utils/jellyfin/user-library/getUserItemData"; import { getUserItemData } from "@/utils/jellyfin/user-library/getUserItemData";
import { Ionicons } from "@expo/vector-icons";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { getSearchApi } from "@jellyfin/sdk/lib/utils/api"; import { getSearchApi } from "@jellyfin/sdk/lib/utils/api";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { router, Stack, useNavigation } from "expo-router"; import { router, useNavigation } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import React, { useLayoutEffect, useMemo, useState } from "react"; import React, { useLayoutEffect, useMemo, useState } from "react";
import { import { Platform, ScrollView, TouchableOpacity, View } from "react-native";
ActivityIndicator,
Platform,
ScrollView,
TouchableOpacity,
View,
} from "react-native";
import _ from "lodash";
import { useDebounce } from "use-debounce"; import { useDebounce } from "use-debounce";
const exampleSearches = [ const exampleSearches = [
@@ -308,7 +299,7 @@ export default function search() {
/> />
{loading ? ( {loading ? (
<View className="mt-4 flex justify-center items-center"> <View className="mt-4 flex justify-center items-center">
<ActivityIndicator size="small" color="white" /> <Loader />
</View> </View>
) : noResults && debouncedSearch.length > 0 ? ( ) : noResults && debouncedSearch.length > 0 ? (
<View> <View>

View File

@@ -1,4 +1,5 @@
import { Text } from "@/components/common/Text"; import { Text } from "@/components/common/Text";
import { Loader } from "@/components/Loader";
import ArtistPoster from "@/components/posters/ArtistPoster"; import ArtistPoster from "@/components/posters/ArtistPoster";
import MoviePoster from "@/components/posters/MoviePoster"; import MoviePoster from "@/components/posters/MoviePoster";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
@@ -13,12 +14,7 @@ import { useQuery } from "@tanstack/react-query";
import { router, useLocalSearchParams } from "expo-router"; import { router, useLocalSearchParams } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { import { ScrollView, TouchableOpacity, View } from "react-native";
ActivityIndicator,
ScrollView,
TouchableOpacity,
View,
} from "react-native";
const page: React.FC = () => { const page: React.FC = () => {
const searchParams = useLocalSearchParams(); const searchParams = useLocalSearchParams();
@@ -154,7 +150,7 @@ const page: React.FC = () => {
</View> </View>
{isLoading ? ( {isLoading ? (
<View className="my-12"> <View className="my-12">
<ActivityIndicator color={"white"} /> <Loader />
</View> </View>
) : ( ) : (
<View className="flex flex-row flex-wrap"> <View className="flex flex-row flex-wrap">

View File

@@ -1,23 +1,18 @@
import { Text } from "@/components/common/Text"; import { Text } from "@/components/common/Text";
import { MovieCard } from "@/components/downloads/MovieCard"; import { MovieCard } from "@/components/downloads/MovieCard";
import { SeriesCard } from "@/components/downloads/SeriesCard"; 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 { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { useQuery } from "@tanstack/react-query"; 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 { router } from "expo-router";
import { Ionicons } from "@expo/vector-icons";
import { FFmpegKit } from "ffmpeg-kit-react-native"; import { FFmpegKit } from "ffmpeg-kit-react-native";
import * as FileSystem from "expo-file-system"; import { useAtom } from "jotai";
import { queueAtom } from "@/utils/atoms/queue"; import { useMemo } from "react";
import { ScrollView, TouchableOpacity, View } from "react-native";
const downloads: React.FC = () => { const downloads: React.FC = () => {
const [process, setProcess] = useAtom(runningProcesses); const [process, setProcess] = useAtom(runningProcesses);
@@ -27,14 +22,14 @@ const downloads: React.FC = () => {
queryKey: ["downloaded_files", process?.item.Id], queryKey: ["downloaded_files", process?.item.Id],
queryFn: async () => queryFn: async () =>
JSON.parse( JSON.parse(
(await AsyncStorage.getItem("downloaded_files")) || "[]", (await AsyncStorage.getItem("downloaded_files")) || "[]"
) as BaseItemDto[], ) as BaseItemDto[],
staleTime: 0, staleTime: 0,
}); });
const movies = useMemo( const movies = useMemo(
() => downloadedFiles?.filter((f) => f.Type === "Movie") || [], () => downloadedFiles?.filter((f) => f.Type === "Movie") || [],
[downloadedFiles], [downloadedFiles]
); );
const groupedBySeries = useMemo(() => { const groupedBySeries = useMemo(() => {
@@ -61,7 +56,7 @@ const downloads: React.FC = () => {
if (isLoading) { if (isLoading) {
return ( return (
<View className="h-full flex flex-col items-center justify-center -mt-6"> <View className="h-full flex flex-col items-center justify-center -mt-6">
<ActivityIndicator size="small" color="white" /> <Loader />
</View> </View>
); );
} }

View File

@@ -6,6 +6,7 @@ import {
playingAtom, playingAtom,
} from "@/components/CurrentlyPlayingBar"; } from "@/components/CurrentlyPlayingBar";
import { DownloadItem } from "@/components/DownloadItem"; import { DownloadItem } from "@/components/DownloadItem";
import { Loader } from "@/components/Loader";
import { OverviewText } from "@/components/OverviewText"; import { OverviewText } from "@/components/OverviewText";
import { PlayButton } from "@/components/PlayButton"; import { PlayButton } from "@/components/PlayButton";
import { PlayedStatus } from "@/components/PlayedStatus"; import { PlayedStatus } from "@/components/PlayedStatus";
@@ -34,7 +35,7 @@ import { Image } from "expo-image";
import { useLocalSearchParams } from "expo-router"; import { useLocalSearchParams } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useMemo, useState } from "react";
import { ActivityIndicator, ScrollView, View } from "react-native"; import { View } from "react-native";
import CastContext, { import CastContext, {
PlayServicesState, PlayServicesState,
useCastDevice, useCastDevice,
@@ -194,7 +195,7 @@ const page: React.FC = () => {
if (l1) if (l1)
return ( return (
<View className="justify-center items-center h-full"> <View className="justify-center items-center h-full">
<ActivityIndicator /> <Loader />
</View> </View>
); );

View File

@@ -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 { Text } from "@/components/common/Text";
import {
currentlyPlayingItemAtom,
playingAtom,
} from "@/components/CurrentlyPlayingBar";
import { DownloadItem } from "@/components/DownloadItem"; 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 { SimilarItems } from "@/components/SimilarItems";
import { SubtitleTrackSelector } from "@/components/SubtitleTrackSelector";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; 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 { useQuery } from "@tanstack/react-query";
import { Image } from "expo-image"; import { Image } from "expo-image";
import { useLocalSearchParams, useNavigation } from "expo-router"; import { useLocalSearchParams, useNavigation } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { ActivityIndicator, ScrollView, View } from "react-native"; import { 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 CastContext, { import CastContext, {
PlayServicesState, PlayServicesState,
useCastDevice, useCastDevice,
useRemoteMediaClient, useRemoteMediaClient,
} from "react-native-google-cast"; } 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 page: React.FC = () => {
const local = useLocalSearchParams(); const local = useLocalSearchParams();
@@ -84,12 +85,12 @@ const page: React.FC = () => {
quality: 90, quality: 90,
width: 1000, width: 1000,
}), }),
[item], [item]
); );
const logoUrl = useMemo( const logoUrl = useMemo(
() => (item?.Type === "Movie" ? getLogoImageUrlById({ api, item }) : null), () => (item?.Type === "Movie" ? getLogoImageUrlById({ api, item }) : null),
[item], [item]
); );
const { data: sessionData } = useQuery({ const { data: sessionData } = useQuery({
@@ -173,13 +174,13 @@ const page: React.FC = () => {
setPlaying(true); setPlaying(true);
} }
}, },
[playbackUrl, item], [playbackUrl, item]
); );
if (l1) if (l1)
return ( return (
<View className="justify-center items-center h-full"> <View className="justify-center items-center h-full">
<ActivityIndicator /> <Loader />
</View> </View>
); );

View File

@@ -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 * 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<typeof TouchableOpacity> { interface ButtonProps extends React.ComponentProps<typeof TouchableOpacity> {
onPress?: () => void; onPress?: () => void;
@@ -57,7 +58,7 @@ export const Button: React.FC<PropsWithChildren<ButtonProps>> = ({
{...props} {...props}
> >
{loading ? ( {loading ? (
<ActivityIndicator color={"white"} size={24} /> <Loader />
) : ( ) : (
<View <View
className={` className={`

View File

@@ -1,5 +1,4 @@
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { useSettings } from "@/utils/atoms/settings";
import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl"; import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl";
import { getAuthHeaders } from "@/utils/jellyfin/jellyfin"; import { getAuthHeaders } from "@/utils/jellyfin/jellyfin";
import { reportPlaybackProgress } from "@/utils/jellyfin/playstate/reportPlaybackProgress"; import { reportPlaybackProgress } from "@/utils/jellyfin/playstate/reportPlaybackProgress";
@@ -14,13 +13,7 @@ import { BlurView } from "expo-blur";
import { useRouter, useSegments } from "expo-router"; import { useRouter, useSegments } from "expo-router";
import { atom, useAtom } from "jotai"; import { atom, useAtom } from "jotai";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { import { Alert, Platform, TouchableOpacity, View } from "react-native";
ActivityIndicator,
Alert,
Platform,
TouchableOpacity,
View,
} from "react-native";
import Animated, { import Animated, {
useAnimatedStyle, useAnimatedStyle,
useSharedValue, useSharedValue,
@@ -28,6 +21,7 @@ import Animated, {
} from "react-native-reanimated"; } from "react-native-reanimated";
import Video, { OnProgressData, VideoRef } from "react-native-video"; import Video, { OnProgressData, VideoRef } from "react-native-video";
import { Text } from "./common/Text"; import { Text } from "./common/Text";
import { Loader } from "./Loader";
export const currentlyPlayingItemAtom = atom<{ export const currentlyPlayingItemAtom = atom<{
item: BaseItemDto; item: BaseItemDto;
@@ -292,7 +286,7 @@ export const CurrentlyPlayingBar: React.FC = () => {
renderLoader={ renderLoader={
item?.Type !== "Audio" && ( item?.Type !== "Audio" && (
<View className="flex flex-col items-center justify-center h-full"> <View className="flex flex-col items-center justify-center h-full">
<ActivityIndicator size={"small"} color={"white"} /> <Loader />
</View> </View>
) )
} }

View File

@@ -9,7 +9,8 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { router } from "expo-router"; import { router } from "expo-router";
import { useAtom } from "jotai"; 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"; import ProgressCircle from "./ProgressCircle";
type DownloadProps = { type DownloadProps = {
@@ -39,7 +40,7 @@ export const DownloadItem: React.FC<DownloadProps> = ({
if (!item.Id) return false; if (!item.Id) return false;
const data: BaseItemDto[] = JSON.parse( const data: BaseItemDto[] = JSON.parse(
(await AsyncStorage.getItem("downloaded_files")) || "[]", (await AsyncStorage.getItem("downloaded_files")) || "[]"
); );
return data.some((d) => d.Id === item.Id); return data.some((d) => d.Id === item.Id);
@@ -50,7 +51,7 @@ export const DownloadItem: React.FC<DownloadProps> = ({
if (isLoading || isLoadingDownloaded) { if (isLoading || isLoadingDownloaded) {
return ( return (
<View className="rounded h-10 aspect-square flex items-center justify-center"> <View className="rounded h-10 aspect-square flex items-center justify-center">
<ActivityIndicator size={"small"} color={"white"} /> <Loader />
</View> </View>
); );
} }
@@ -72,7 +73,7 @@ export const DownloadItem: React.FC<DownloadProps> = ({
> >
<View className="rounded h-10 aspect-square flex items-center justify-center"> <View className="rounded h-10 aspect-square flex items-center justify-center">
{process.progress === 0 ? ( {process.progress === 0 ? (
<ActivityIndicator size={"small"} color={"white"} /> <Loader />
) : ( ) : (
<View className="-rotate-45"> <View className="-rotate-45">
<ProgressCircle <ProgressCircle

18
components/Loader.tsx Normal file
View File

@@ -0,0 +1,18 @@
import {
ActivityIndicator,
ActivityIndicatorProps,
Platform,
View,
} from "react-native";
interface Props extends ActivityIndicatorProps {}
export const Loader: React.FC<Props> = ({ ...props }) => {
return (
<ActivityIndicator
size={"small"}
color={Platform.OS === "ios" ? "white" : "#9333ea"}
{...props}
/>
);
};

View File

@@ -1,9 +0,0 @@
import { ActivityIndicator, View } from "react-native";
export const Loading: React.FC = () => {
return (
<View>
<ActivityIndicator />
</View>
);
};

View File

@@ -6,14 +6,10 @@ import { useQuery } from "@tanstack/react-query";
import { router } from "expo-router"; import { router } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useMemo } from "react"; import { useMemo } from "react";
import { import { ScrollView, TouchableOpacity, View } from "react-native";
ActivityIndicator,
ScrollView,
TouchableOpacity,
View,
} from "react-native";
import { ItemCardText } from "./ItemCardText";
import { Text } from "./common/Text"; import { Text } from "./common/Text";
import { ItemCardText } from "./ItemCardText";
import { Loader } from "./Loader";
type SimilarItemsProps = { type SimilarItemsProps = {
itemId: string; itemId: string;
@@ -49,7 +45,7 @@ export const SimilarItems: React.FC<SimilarItemsProps> = ({ itemId }) => {
<Text className="px-4 text-2xl font-bold mb-2">Similar items</Text> <Text className="px-4 text-2xl font-bold mb-2">Similar items</Text>
{isLoading ? ( {isLoading ? (
<View className="my-12"> <View className="my-12">
<ActivityIndicator /> <Loader />
</View> </View>
) : ( ) : (
<ScrollView horizontal> <ScrollView horizontal>

View File

@@ -1,16 +1,11 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { import { ScrollView, ScrollViewProps, View, ViewStyle } from "react-native";
ScrollView,
View,
ViewStyle,
ActivityIndicator,
ScrollViewProps,
} from "react-native";
import Animated, { import Animated, {
useAnimatedStyle, useAnimatedStyle,
useSharedValue, useSharedValue,
withTiming, withTiming,
} from "react-native-reanimated"; } from "react-native-reanimated";
import { Loader } from "../Loader";
import { Text } from "./Text"; import { Text } from "./Text";
interface HorizontalScrollProps<T> extends ScrollViewProps { interface HorizontalScrollProps<T> extends ScrollViewProps {
@@ -58,7 +53,7 @@ export function HorizontalScroll<T>({
loadingContainerStyle, loadingContainerStyle,
]} ]}
> >
<ActivityIndicator size="small" /> <Loader />
</View> </View>
); );
} }

View File

@@ -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 { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api"; import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { Image } from "expo-image";
import { useRouter } from "expo-router"; import { useRouter } from "expo-router";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useSettings } from "@/utils/atoms/settings"; import React, { useMemo } from "react";
import { Dimensions } from "react-native"; import { Dimensions, View, ViewProps } from "react-native";
import { useSharedValue } from "react-native-reanimated"; import { useSharedValue } from "react-native-reanimated";
import Carousel, { import Carousel, {
ICarouselInstance, ICarouselInstance,
Pagination, Pagination,
} from "react-native-reanimated-carousel"; } 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 { TouchableItemRouter } from "../common/TouchableItemRouter";
import { Loader } from "../Loader";
interface Props extends ViewProps {} interface Props extends ViewProps {}
@@ -84,7 +84,7 @@ export const LargeMovieCarousel: React.FC<Props> = ({ ...props }) => {
if (l1 || l2) if (l1 || l2)
return ( return (
<View className="h-[242px] flex items-center justify-center"> <View className="h-[242px] flex items-center justify-center">
<ActivityIndicator size={"small"} color="#fff" /> <Loader />
</View> </View>
); );

View File

@@ -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 { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { useSettings } from "@/utils/atoms/settings";
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api"; import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { useAtom } from "jotai"; 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 = () => { export const SettingToggles: React.FC = () => {
const [settings, updateSettings] = useSettings(); const [settings, updateSettings] = useSettings();
@@ -83,7 +77,7 @@ export const SettingToggles: React.FC = () => {
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
Linking.openURL( 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: mediaListCollectionIds:
settings?.mediaListCollectionIds.includes(mlc.Id!) settings?.mediaListCollectionIds.includes(mlc.Id!)
? settings?.mediaListCollectionIds.filter( ? settings?.mediaListCollectionIds.filter(
(id) => id !== mlc.Id, (id) => id !== mlc.Id
) )
: [...settings?.mediaListCollectionIds, mlc.Id!], : [...settings?.mediaListCollectionIds, mlc.Id!],
}); });
@@ -131,7 +125,7 @@ export const SettingToggles: React.FC = () => {
))} ))}
{isLoadingMediaListCollections && ( {isLoadingMediaListCollections && (
<View className="flex flex-row items-center justify-center bg-neutral-900 p-4"> <View className="flex flex-row items-center justify-center bg-neutral-900 p-4">
<ActivityIndicator size="small" color="#fff" /> <Loader />
</View> </View>
)} )}
{mediaListCollections?.length === 0 && ( {mediaListCollections?.length === 0 && (