From a4b09e6afe5d20c7fce2a103a996dc26f4cf0495 Mon Sep 17 00:00:00 2001 From: tapframe Date: Tue, 27 May 2025 21:21:48 +0530 Subject: [PATCH] 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. --- src/screens/StreamsScreen.tsx | 166 +++++++++++++++++++++++++--------- 1 file changed, 122 insertions(+), 44 deletions(-) diff --git a/src/screens/StreamsScreen.tsx b/src/screens/StreamsScreen.tsx index 40b04b2..456e3fc 100644 --- a/src/screens/StreamsScreen.tsx +++ b/src/screens/StreamsScreen.tsx @@ -267,41 +267,108 @@ export const StreamsScreen = () => { } }>({}); - // Monitor streams loading start + // Monitor streams loading start and completion useEffect(() => { + const now = Date.now(); + // Define all providers you expect to load. This could be dynamic. + const expectedProviders = ['stremio', 'hdrezka']; + if (loadingStreams || loadingEpisodeStreams) { - logger.log("⏱️ Stream loading started"); - const now = Date.now(); - setLoadStartTime(now); - setProviderLoadTimes({}); + // --- Stream Loading has STARTED or is IN PROGRESS --- + logger.log("⏱️ Stream loading started or in progress..."); - // Reset provider status - include HDRezka - setProviderStatus({ - 'stremio': { - loading: true, - success: false, - error: false, - message: 'Loading...', - timeStarted: now, - timeCompleted: 0 - }, - 'hdrezka': { - loading: true, - success: false, - error: false, - message: 'Loading...', - timeStarted: now, - timeCompleted: 0 - } - }); + // Set load start time only if this is the beginning of a new loading cycle + if (loadStartTime === 0) { + setLoadStartTime(now); + } - // Also update the simpler loading state - include HDRezka - setLoadingProviders({ - 'stremio': true, - 'hdrezka': true + setProviderLoadTimes({}); // Reset individual provider load times tracker + + // Update provider status to loading for all expected providers + setProviderStatus(prevStatus => { + const newStatus = { ...prevStatus }; + expectedProviders.forEach(providerId => { + // If not already marked as loading, or if it's a fresh cycle, set to loading + if (!newStatus[providerId] || !newStatus[providerId].loading || loadStartTime === 0) { + newStatus[providerId] = { + loading: true, + success: false, + error: false, + message: 'Loading...', + timeStarted: (newStatus[providerId]?.loading && newStatus[providerId]?.timeStarted) ? newStatus[providerId].timeStarted : now, + timeCompleted: 0, + }; + } + }); + return newStatus; }); + + // Update simple loading flag for all expected providers + setLoadingProviders(prevLoading => { + const newLoading = { ...prevLoading }; + 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(() => { if (type === 'series' && episodeId) { @@ -314,20 +381,14 @@ export const StreamsScreen = () => { loadEpisodeStreams(episodeId); } else if (type === 'movie') { logger.log(`🎬 Loading movie streams for: ${id}`); - setLoadingProviders({ - 'stremio': true, - 'hdrezka': true - }); + // setLoadingProviders({ // This is now handled by the main effect + // 'stremio': true, + // 'hdrezka': true + // }); loadStreams(); } }, [type, episodeId]); - React.useEffect(() => { - const streams = type === 'series' ? episodeStreams : groupedStreams; - const providers = new Set(Object.keys(streams)); - setAvailableProviders(providers); - }, [type, groupedStreams, episodeStreams]); - React.useEffect(() => { // Trigger entrance animations headerOpacity.value = withTiming(1, { duration: 400 }); @@ -609,6 +670,13 @@ export const StreamsScreen = () => { const streams = type === 'series' ? episodeStreams : groupedStreams; 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" const filteredEntries = Object.entries(streams) .filter(([addonId]) => { @@ -633,11 +701,21 @@ export const StreamsScreen = () => { if (indexB !== -1) return 1; return 0; }) - .map(([addonId, { addonName, streams }]) => ({ - title: addonName, - addonId, - data: streams - })); + .map(([addonId, { addonName, streams: providerStreams }]) => { + let sortedProviderStreams = providerStreams; + if (addonId === 'hdrezka') { + 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; }, [selectedProvider, type, episodeStreams, groupedStreams]);