Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add loading status when fetching episodes, servers. #47

Merged
merged 1 commit into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useAtomValue, useSetAtom } from 'jotai/react';
import { RotateCwIcon } from 'lucide-react-native';
import React, { useEffect, useMemo } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { Else, If, Then } from 'react-if';

import { type FragmentType, graphql, useFragment } from '@/gql';
Expand Down Expand Up @@ -38,8 +38,15 @@ const EpisodeContainer: React.FC<EpisodeContainerProps> = ({
}) => {
const media = useFragment(EpisodeContainerFragment, mediaFragment);
const currentModuleId = useAtomValue(currentModuleIdAtom);

const { data, isLoading, isRefetching, refetch } = useEpisodes(media);
const [episodeFetchingStatus, setEpisodeFetchingStatus] = useState<{
isError: boolean;
status: string;
}>({ isError: false, status: '' });

const { data, isLoading, isRefetching, refetch } = useEpisodes(
media,
setEpisodeFetchingStatus
);
const setSectionEpisodes = useSetAtom(sectionEpisodesAtom);
const setEpisodeChunk = useSetAtom(episodeChunkAtom);

Expand Down Expand Up @@ -106,15 +113,23 @@ const EpisodeContainer: React.FC<EpisodeContainerProps> = ({
<Then>
<View className="mt-8">
<ActivityIndicator color={colors.primary[500]} size={48} />

{!episodeFetchingStatus.isError && (
<Text className="mt-2 text-center font-semibold text-gray-300">
{episodeFetchingStatus.status}
</Text>
)}
</View>
</Then>

<Else>
<If condition={!data?.length}>
<Then>
<Text className="text-center">
There are no episodes for this anime
</Text>
{episodeFetchingStatus.isError && (
<Text className="text-center">
{episodeFetchingStatus.status}
</Text>
)}
</Then>

<Else>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,47 @@ export const useAnimeEpisodeFragment = graphql(`
`);

const useEpisodes = (
mediaFragment: FragmentType<typeof useAnimeEpisodeFragment>
mediaFragment: FragmentType<typeof useAnimeEpisodeFragment>,
onStatusChange?: (change: { isError: boolean; status: string }) => void
) => {
const media = useFragment(useAnimeEpisodeFragment, mediaFragment);

const { data, isLoading: isAnimeIdLoading } = useAnimeId(media);
const { data: animeId, isLoading: isAnimeIdLoading } = useAnimeId(media);

const queryKey = ['episodes', media.id];

if (data?.data) {
queryKey.push(data.data);
if (animeId?.data) {
queryKey.push(animeId.data);
}

const episodes = useWebViewData(
queryKey,
async (webview) => {
if (!data?.data) {
onStatusChange?.({ isError: false, status: 'Loading anime id' });

if (!animeId?.data) {
if (isAnimeIdLoading) {
onStatusChange?.({ isError: false, status: 'Loading anime id' });
} else {
onStatusChange?.({ isError: true, status: 'Cannot find anime id' });
}

return [];
}

const nonValidatedEpisodesPromise = webview.sendMessage<Episode[]>(
'anime.getEpisodes',
{
animeId: data?.data,
extraData: data?.extraData,
animeId: animeId?.data,
extraData: animeId?.extraData,
}
);

onStatusChange?.({
isError: false,
status: 'Loading episodes',
});

const metadataEpisodesPromise = getEpisodeInfo(media);

const [nonValidatedEpisodesResult, metadataEpisodesResult] =
Expand All @@ -70,6 +84,11 @@ const useEpisodes = (
]);

if (nonValidatedEpisodesResult.status === 'rejected') {
onStatusChange?.({
isError: true,
status: 'Cannot find episodes',
});

return [];
}

Expand All @@ -78,10 +97,9 @@ const useEpisodes = (
.safeParse(nonValidatedEpisodesResult.value);

if (!validation.success) {
Toast.show({
type: 'error',
text1: 'Cannot find episodes',
text2: validation.error.message,
onStatusChange?.({
isError: true,
status: 'Cannot find episodes',
});

return [];
Expand Down Expand Up @@ -117,8 +135,6 @@ const useEpisodes = (
};
});

console.log('episodes', episodes);

return episodes;
},

Expand All @@ -130,7 +146,6 @@ const useEpisodes = (
text2: err,
});
},
enabled: !isAnimeIdLoading,
retry: 0,

// For some reason, when calling useEpisodes in watch screen, it will return empty episodes
Expand Down
20 changes: 16 additions & 4 deletions src/screens/anime/watch/components/error-message.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { useNavigation } from '@react-navigation/native';
import { ArrowLeft, RefreshCcw } from 'lucide-react-native';
import React from 'react';

import { Button, Text, View } from '@/ui';
import Sticker from '@/ui/sticker';

interface ErrorMessageProps {
message: string;
onRetry?: () => void;
}

const ErrorMessage: React.FC<ErrorMessageProps> = ({ message }) => {
const ErrorMessage: React.FC<ErrorMessageProps> = ({ message, onRetry }) => {
const navigation = useNavigation();

const handleGoBack = () => {
Expand All @@ -25,9 +27,19 @@ const ErrorMessage: React.FC<ErrorMessageProps> = ({ message }) => {

<Text>{message}</Text>

<Button className="mt-2" onPress={handleGoBack}>
<Text>Go back</Text>
</Button>
<View className="mt-2 flex flex-row items-center space-x-2">
<Button onPress={handleGoBack}>
<ArrowLeft size={16} style={{ color: 'white' }} />

<Text>Go back</Text>
</Button>

<Button className="bg-gray-600" onPress={onRetry}>
<RefreshCcw size={16} style={{ color: 'white' }} />

<Text className="ml-2">Retry</Text>
</Button>
</View>
</View>
);
};
Expand Down
27 changes: 23 additions & 4 deletions src/screens/anime/watch/components/media-container.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useSetAtom } from 'jotai/react';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';

import type { FragmentType } from '@/gql';
import { ActivityIndicator, View } from '@/ui';
import { ActivityIndicator, Text, View } from '@/ui';
import colors from '@/ui/theme/colors';

import type { useAnimeEpisodeFragment } from '../../details/screens/episode-screen/hooks/use-episodes';
Expand All @@ -29,6 +29,11 @@ const MediaContainer: React.FC<MediaContainerProps> = ({
const setMediaId = useSetAtom(mediaIdAtom);
const setIsAdult = useSetAtom(isAdultAtom);

const [episodeFetchingStatus, setEpisodeFetchingStatus] = useState<{
isError: boolean;
status: string;
}>({ isError: false, status: '' });

useEffect(() => {
setMediaId({
anilistId,
Expand All @@ -40,18 +45,32 @@ const MediaContainer: React.FC<MediaContainerProps> = ({
setIsAdult(isAdult);
}, [setIsAdult, isAdult]);

const { data, isLoading } = useEpisodes(mediaFragment);
const { data, isLoading, refetch } = useEpisodes(
mediaFragment,
setEpisodeFetchingStatus
);

if (isLoading) {
return (
<View className="flex h-full w-full flex-1 items-center justify-center">
<ActivityIndicator color={colors.primary[500]} size={48} />

{!episodeFetchingStatus.isError && (
<Text className="mt-2 text-center font-semibold text-gray-300">
{episodeFetchingStatus.status}
</Text>
)}
</View>
);
}

if (!data?.length) {
return <ErrorMessage message="Cannot find episodes. Please try again" />;
return (
<ErrorMessage
onRetry={refetch}
message="Cannot find episodes. Please try again"
/>
);
}

return (
Expand Down
4 changes: 4 additions & 0 deletions src/screens/anime/watch/components/player-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ const PlayerContainer: React.FC<PlayerContainerProps> = ({
{isLoading || isServerLoading ? (
<View className="absolute z-10 flex h-full w-full items-center justify-center whitespace-pre-wrap">
<ActivityIndicator size={48} color={colors.primary[500]} />

<Text className="mt-2 text-center font-semibold text-gray-300">
{isLoading ? 'Loading video...' : 'Loading server...'}
</Text>
</View>
) : null}

Expand Down
12 changes: 9 additions & 3 deletions src/screens/anime/watch/components/servers-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ const ServersContainer: React.FC<ServersContainerProps> = ({
const setServers = useSetAtom(serversAtom);
const [currentServer, setCurrentServer] = useAtom(currentServerAtom);

const { data: videoServers, isLoading: videoServersLoading } =
useLoadVideoServers(currentEpisode.id, currentEpisode.extra || undefined);
const {
data: videoServers,
isLoading: videoServersLoading,
refetch,
} = useLoadVideoServers(currentEpisode.id, currentEpisode.extra || undefined);

useEffect(() => {
if (!videoServers?.length) {
Expand All @@ -35,7 +38,10 @@ const ServersContainer: React.FC<ServersContainerProps> = ({

if (!videoServers?.length && !videoServersLoading)
return (
<ErrorMessage message="Cannot find video servers. Please try again" />
<ErrorMessage
onRetry={refetch}
message="Cannot find video servers. Please try again"
/>
);

return (
Expand Down
Loading