Add close button to VideoPlayer and improve loading indicators in StreamsScreen

This update introduces a close button in the VideoPlayer component for better user control during video loading. Additionally, the StreamsScreen has been enhanced to show loading indicators for individual stream providers, improving the user experience by providing visual feedback during data fetching.
This commit is contained in:
tapframe 2025-06-09 02:21:41 +05:30
parent 988a746a5b
commit 6c44c0ec59
3 changed files with 67 additions and 18 deletions

View file

@ -9,6 +9,7 @@ import * as ScreenOrientation from 'expo-screen-orientation';
import { storageService } from '../../services/storageService'; import { storageService } from '../../services/storageService';
import { logger } from '../../utils/logger'; import { logger } from '../../utils/logger';
import AsyncStorage from '@react-native-async-storage/async-storage'; import AsyncStorage from '@react-native-async-storage/async-storage';
import { MaterialIcons } from '@expo/vector-icons';
import { import {
DEFAULT_SUBTITLE_SIZE, DEFAULT_SUBTITLE_SIZE,
@ -747,6 +748,14 @@ const VideoPlayer: React.FC = () => {
]} ]}
pointerEvents={isOpeningAnimationComplete ? 'none' : 'auto'} pointerEvents={isOpeningAnimationComplete ? 'none' : 'auto'}
> >
<TouchableOpacity
style={styles.loadingCloseButton}
onPress={handleClose}
activeOpacity={0.7}
>
<MaterialIcons name="close" size={24} color="#ffffff" />
</TouchableOpacity>
<View style={styles.openingContent}> <View style={styles.openingContent}>
<ActivityIndicator size="large" color="#E50914" /> <ActivityIndicator size="large" color="#E50914" />
<Text style={styles.openingText}>Loading video...</Text> <Text style={styles.openingText}>Loading video...</Text>

View file

@ -752,4 +752,16 @@ export const styles = StyleSheet.create({
fontSize: 12, fontSize: 12,
marginTop: 2, marginTop: 2,
}, },
loadingCloseButton: {
position: 'absolute',
top: 40,
right: 20,
width: 44,
height: 44,
backgroundColor: 'rgba(0, 0, 0, 0.6)',
borderRadius: 22,
justifyContent: 'center',
alignItems: 'center',
zIndex: 9999,
},
}); });

View file

@ -856,11 +856,8 @@ export const StreamsScreen = () => {
const renderItem = useCallback(({ item, index, section }: { item: Stream; index: number; section: any }) => { const renderItem = useCallback(({ item, index, section }: { item: Stream; index: number; section: any }) => {
const stream = item; const stream = item;
const isLoading = loadingProviders[section.addonId]; // Don't show loading for individual streams that are already available and displayed
const isLoading = false; // If streams are being rendered, they're available and shouldn't be loading
// Special handling for HDRezka streams
const quality = stream.title?.match(/(\d+)p/)?.[1] || null;
const isHDRezka = section.addonId === 'hdrezka';
return ( return (
<StreamCard <StreamCard
@ -869,20 +866,35 @@ export const StreamsScreen = () => {
onPress={() => handleStreamPress(stream)} onPress={() => handleStreamPress(stream)}
index={index} index={index}
isLoading={isLoading} isLoading={isLoading}
statusMessage={providerStatus[section.addonId]?.message} statusMessage={undefined}
theme={currentTheme} theme={currentTheme}
/> />
); );
}, [handleStreamPress, loadingProviders, providerStatus, currentTheme]); }, [handleStreamPress, currentTheme]);
const renderSectionHeader = useCallback(({ section }: { section: { title: string; addonId: string } }) => ( const renderSectionHeader = useCallback(({ section }: { section: { title: string; addonId: string } }) => {
<Animated.View const isProviderLoading = loadingProviders[section.addonId];
entering={FadeIn.duration(400)}
layout={Layout.springify()} return (
> <Animated.View
<Text style={styles.streamGroupTitle}>{section.title}</Text> entering={FadeIn.duration(400)}
</Animated.View> layout={Layout.springify()}
), [styles.streamGroupTitle]); style={styles.sectionHeaderContainer}
>
<View style={styles.sectionHeaderContent}>
<Text style={styles.streamGroupTitle}>{section.title}</Text>
{isProviderLoading && (
<View style={styles.sectionLoadingIndicator}>
<ActivityIndicator size="small" color={colors.primary} />
<Text style={[styles.sectionLoadingText, { color: colors.primary }]}>
Loading...
</Text>
</View>
)}
</View>
</Animated.View>
);
}, [styles.streamGroupTitle, styles.sectionHeaderContainer, styles.sectionHeaderContent, styles.sectionLoadingIndicator, styles.sectionLoadingText, loadingProviders, colors.primary]);
// Cleanup on unmount // Cleanup on unmount
useEffect(() => { useEffect(() => {
@ -1088,7 +1100,8 @@ export const StreamsScreen = () => {
)} )}
</Animated.View> </Animated.View>
{isLoading || (Object.keys(streams).length === 0 && (loadingStreams || loadingEpisodeStreams)) ? ( {/* Show streams immediately as they become available, with loading indicators for pending providers */}
{Object.keys(streams).length === 0 && (loadingStreams || loadingEpisodeStreams) ? (
<Animated.View <Animated.View
entering={FadeIn.duration(300)} entering={FadeIn.duration(300)}
style={styles.loadingContainer} style={styles.loadingContainer}
@ -1096,7 +1109,7 @@ export const StreamsScreen = () => {
<ActivityIndicator size="large" color={colors.primary} /> <ActivityIndicator size="large" color={colors.primary} />
<Text style={styles.loadingText}>Finding available streams...</Text> <Text style={styles.loadingText}>Finding available streams...</Text>
</Animated.View> </Animated.View>
) : Object.keys(streams).length === 0 ? ( ) : Object.keys(streams).length === 0 && !loadingStreams && !loadingEpisodeStreams ? (
<Animated.View <Animated.View
entering={FadeIn.duration(300)} entering={FadeIn.duration(300)}
style={styles.noStreams} style={styles.noStreams}
@ -1122,7 +1135,7 @@ export const StreamsScreen = () => {
bounces={true} bounces={true}
overScrollMode="never" overScrollMode="never"
ListFooterComponent={ ListFooterComponent={
isLoading ? ( (loadingStreams || loadingEpisodeStreams) ? (
<View style={styles.footerLoading}> <View style={styles.footerLoading}>
<ActivityIndicator size="small" color={colors.primary} /> <ActivityIndicator size="small" color={colors.primary} />
<Text style={styles.footerLoadingText}>Loading more sources...</Text> <Text style={styles.footerLoadingText}>Loading more sources...</Text>
@ -1540,6 +1553,21 @@ const createStyles = (colors: any) => StyleSheet.create({
alignItems: 'center', alignItems: 'center',
zIndex: 9999, zIndex: 9999,
}, },
sectionHeaderContainer: {
padding: 16,
},
sectionHeaderContent: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
sectionLoadingIndicator: {
flexDirection: 'row',
alignItems: 'center',
},
sectionLoadingText: {
marginLeft: 8,
},
}); });
export default memo(StreamsScreen); export default memo(StreamsScreen);