Ios #14
3 changed files with 67 additions and 18 deletions
|
|
@ -9,6 +9,7 @@ import * as ScreenOrientation from 'expo-screen-orientation';
|
|||
import { storageService } from '../../services/storageService';
|
||||
import { logger } from '../../utils/logger';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { MaterialIcons } from '@expo/vector-icons';
|
||||
|
||||
import {
|
||||
DEFAULT_SUBTITLE_SIZE,
|
||||
|
|
@ -747,6 +748,14 @@ const VideoPlayer: React.FC = () => {
|
|||
]}
|
||||
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}>
|
||||
<ActivityIndicator size="large" color="#E50914" />
|
||||
<Text style={styles.openingText}>Loading video...</Text>
|
||||
|
|
|
|||
|
|
@ -752,4 +752,16 @@ export const styles = StyleSheet.create({
|
|||
fontSize: 12,
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
|
@ -856,11 +856,8 @@ export const StreamsScreen = () => {
|
|||
|
||||
const renderItem = useCallback(({ item, index, section }: { item: Stream; index: number; section: any }) => {
|
||||
const stream = item;
|
||||
const isLoading = loadingProviders[section.addonId];
|
||||
|
||||
// Special handling for HDRezka streams
|
||||
const quality = stream.title?.match(/(\d+)p/)?.[1] || null;
|
||||
const isHDRezka = section.addonId === 'hdrezka';
|
||||
// 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
|
||||
|
||||
return (
|
||||
<StreamCard
|
||||
|
|
@ -869,20 +866,35 @@ export const StreamsScreen = () => {
|
|||
onPress={() => handleStreamPress(stream)}
|
||||
index={index}
|
||||
isLoading={isLoading}
|
||||
statusMessage={providerStatus[section.addonId]?.message}
|
||||
statusMessage={undefined}
|
||||
theme={currentTheme}
|
||||
/>
|
||||
);
|
||||
}, [handleStreamPress, loadingProviders, providerStatus, currentTheme]);
|
||||
}, [handleStreamPress, currentTheme]);
|
||||
|
||||
const renderSectionHeader = useCallback(({ section }: { section: { title: string; addonId: string } }) => (
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(400)}
|
||||
layout={Layout.springify()}
|
||||
>
|
||||
<Text style={styles.streamGroupTitle}>{section.title}</Text>
|
||||
</Animated.View>
|
||||
), [styles.streamGroupTitle]);
|
||||
const renderSectionHeader = useCallback(({ section }: { section: { title: string; addonId: string } }) => {
|
||||
const isProviderLoading = loadingProviders[section.addonId];
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(400)}
|
||||
layout={Layout.springify()}
|
||||
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
|
||||
useEffect(() => {
|
||||
|
|
@ -1088,7 +1100,8 @@ export const StreamsScreen = () => {
|
|||
)}
|
||||
</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
|
||||
entering={FadeIn.duration(300)}
|
||||
style={styles.loadingContainer}
|
||||
|
|
@ -1096,7 +1109,7 @@ export const StreamsScreen = () => {
|
|||
<ActivityIndicator size="large" color={colors.primary} />
|
||||
<Text style={styles.loadingText}>Finding available streams...</Text>
|
||||
</Animated.View>
|
||||
) : Object.keys(streams).length === 0 ? (
|
||||
) : Object.keys(streams).length === 0 && !loadingStreams && !loadingEpisodeStreams ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.duration(300)}
|
||||
style={styles.noStreams}
|
||||
|
|
@ -1122,7 +1135,7 @@ export const StreamsScreen = () => {
|
|||
bounces={true}
|
||||
overScrollMode="never"
|
||||
ListFooterComponent={
|
||||
isLoading ? (
|
||||
(loadingStreams || loadingEpisodeStreams) ? (
|
||||
<View style={styles.footerLoading}>
|
||||
<ActivityIndicator size="small" color={colors.primary} />
|
||||
<Text style={styles.footerLoadingText}>Loading more sources...</Text>
|
||||
|
|
@ -1540,6 +1553,21 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
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);
|
||||
Loading…
Reference in a new issue