Enhance StreamsScreen loading state management and provider status updates

This update improves the loading state management in the StreamsScreen component by refining how loading cycles are tracked and provider statuses are updated. It introduces a more dynamic approach to handling expected providers, ensuring accurate loading indicators and success/error messages based on the availability of streams. Additionally, a helper function for sorting stream quality has been added, enhancing the user experience when selecting streams. Overall, these changes contribute to a more robust and user-friendly streaming experience.
This commit is contained in:
tapframe 2025-05-27 21:21:48 +05:30
parent 5751d755db
commit a4b09e6afe

View file

@ -267,41 +267,108 @@ export const StreamsScreen = () => {
} }
}>({}); }>({});
// Monitor streams loading start // Monitor streams loading start and completion
useEffect(() => { useEffect(() => {
const now = Date.now();
// Define all providers you expect to load. This could be dynamic.
const expectedProviders = ['stremio', 'hdrezka'];
if (loadingStreams || loadingEpisodeStreams) { if (loadingStreams || loadingEpisodeStreams) {
logger.log("⏱️ Stream loading started"); // --- Stream Loading has STARTED or is IN PROGRESS ---
const now = Date.now(); logger.log("⏱️ Stream loading started or in progress...");
setLoadStartTime(now);
setProviderLoadTimes({});
// Reset provider status - include HDRezka // Set load start time only if this is the beginning of a new loading cycle
setProviderStatus({ if (loadStartTime === 0) {
'stremio': { setLoadStartTime(now);
loading: true, }
success: false,
error: false, setProviderLoadTimes({}); // Reset individual provider load times tracker
message: 'Loading...',
timeStarted: now, // Update provider status to loading for all expected providers
timeCompleted: 0 setProviderStatus(prevStatus => {
}, const newStatus = { ...prevStatus };
'hdrezka': { expectedProviders.forEach(providerId => {
loading: true, // If not already marked as loading, or if it's a fresh cycle, set to loading
success: false, if (!newStatus[providerId] || !newStatus[providerId].loading || loadStartTime === 0) {
error: false, newStatus[providerId] = {
message: 'Loading...', loading: true,
timeStarted: now, success: false,
timeCompleted: 0 error: false,
} message: 'Loading...',
timeStarted: (newStatus[providerId]?.loading && newStatus[providerId]?.timeStarted) ? newStatus[providerId].timeStarted : now,
timeCompleted: 0,
};
}
});
return newStatus;
}); });
// Also update the simpler loading state - include HDRezka // Update simple loading flag for all expected providers
setLoadingProviders({ setLoadingProviders(prevLoading => {
'stremio': true, const newLoading = { ...prevLoading };
'hdrezka': true expectedProviders.forEach(providerId => {
newLoading[providerId] = true;
});
return newLoading;
}); });
} else if (loadStartTime > 0) {
// --- Stream Loading has FINISHED ---
// (loadStartTime > 0 implies a loading cycle was active and has now completed)
logger.log("🏁 Stream loading finished. Processing results.");
const currentStreamsData = type === 'series' ? episodeStreams : groupedStreams;
// Update simple loading flag: all expected providers are no longer loading
setLoadingProviders(prevLoading => {
const newLoading = { ...prevLoading };
expectedProviders.forEach(providerId => {
newLoading[providerId] = false;
});
return newLoading;
});
// Update detailed provider status based on results
setProviderStatus(prevStatus => {
const newStatus = { ...prevStatus };
expectedProviders.forEach(providerId => {
if (newStatus[providerId]) { // Ensure the provider entry exists
const providerHasStreams = currentStreamsData[providerId] &&
currentStreamsData[providerId].streams &&
currentStreamsData[providerId].streams.length > 0;
newStatus[providerId] = {
...newStatus[providerId], // Preserve timeStarted
loading: false,
success: providerHasStreams,
// Mark error if it was loading and now no streams, and wasn't already successful
error: !providerHasStreams && newStatus[providerId].loading && !newStatus[providerId].success,
message: providerHasStreams ? 'Loaded successfully' : (newStatus[providerId].error ? 'Error or no streams' : 'No streams found'),
timeCompleted: now,
};
} else {
// Fallback if somehow not initialized (should be caught by loading phase)
newStatus[providerId] = {
loading: false,
success: false,
error: true,
message: 'Provider status error (not initialized)',
timeStarted: 0,
timeCompleted: now,
};
}
});
return newStatus;
});
// Update the set of available providers based on what actually loaded streams
const providersWithStreams = new Set(Object.keys(currentStreamsData));
setAvailableProviders(providersWithStreams);
// Reset loadStartTime to signify the end of this loading cycle
setLoadStartTime(0);
} }
}, [loadingStreams, loadingEpisodeStreams]); }, [loadingStreams, loadingEpisodeStreams, groupedStreams, episodeStreams, type /* loadStartTime is intentionally omitted from deps here */]);
React.useEffect(() => { React.useEffect(() => {
if (type === 'series' && episodeId) { if (type === 'series' && episodeId) {
@ -314,20 +381,14 @@ export const StreamsScreen = () => {
loadEpisodeStreams(episodeId); loadEpisodeStreams(episodeId);
} else if (type === 'movie') { } else if (type === 'movie') {
logger.log(`🎬 Loading movie streams for: ${id}`); logger.log(`🎬 Loading movie streams for: ${id}`);
setLoadingProviders({ // setLoadingProviders({ // This is now handled by the main effect
'stremio': true, // 'stremio': true,
'hdrezka': true // 'hdrezka': true
}); // });
loadStreams(); loadStreams();
} }
}, [type, episodeId]); }, [type, episodeId]);
React.useEffect(() => {
const streams = type === 'series' ? episodeStreams : groupedStreams;
const providers = new Set(Object.keys(streams));
setAvailableProviders(providers);
}, [type, groupedStreams, episodeStreams]);
React.useEffect(() => { React.useEffect(() => {
// Trigger entrance animations // Trigger entrance animations
headerOpacity.value = withTiming(1, { duration: 400 }); headerOpacity.value = withTiming(1, { duration: 400 });
@ -609,6 +670,13 @@ export const StreamsScreen = () => {
const streams = type === 'series' ? episodeStreams : groupedStreams; const streams = type === 'series' ? episodeStreams : groupedStreams;
const installedAddons = stremioService.getInstalledAddons(); const installedAddons = stremioService.getInstalledAddons();
// Helper function to extract quality as a number for sorting
const getQualityNumeric = (title: string | undefined): number => {
if (!title) return 0;
const match = title.match(/(\d+)p/);
return match ? parseInt(match[1], 10) : 0;
};
// Filter streams by selected provider - only if not "all" // Filter streams by selected provider - only if not "all"
const filteredEntries = Object.entries(streams) const filteredEntries = Object.entries(streams)
.filter(([addonId]) => { .filter(([addonId]) => {
@ -633,11 +701,21 @@ export const StreamsScreen = () => {
if (indexB !== -1) return 1; if (indexB !== -1) return 1;
return 0; return 0;
}) })
.map(([addonId, { addonName, streams }]) => ({ .map(([addonId, { addonName, streams: providerStreams }]) => {
title: addonName, let sortedProviderStreams = providerStreams;
addonId, if (addonId === 'hdrezka') {
data: streams sortedProviderStreams = [...providerStreams].sort((a, b) => {
})); const qualityA = getQualityNumeric(a.title);
const qualityB = getQualityNumeric(b.title);
return qualityB - qualityA; // Sort descending (e.g., 1080p before 720p)
});
}
return {
title: addonName,
addonId,
data: sortedProviderStreams
};
});
return filteredEntries; return filteredEntries;
}, [selectedProvider, type, episodeStreams, groupedStreams]); }, [selectedProvider, type, episodeStreams, groupedStreams]);