Update app.json icon, remove unused image, and refactor CatalogSection and StreamsScreen components for improved layout and performance

This commit updates the app.json to change the icon path, deletes an unused image file, and refactors the CatalogSection and StreamsScreen components. The CatalogSection now includes a title with a maximum line limit, while the StreamsScreen optimizes stream information handling and adjusts rendering parameters for better performance.
This commit is contained in:
tapframe 2025-07-04 16:25:53 +05:30
parent 01d86198ba
commit c4f5c9e374
5 changed files with 59 additions and 119 deletions

View file

@ -4,7 +4,7 @@
"slug": "nuvio",
"version": "1.0.0",
"orientation": "default",
"icon": "./assets/icon.png",
"icon": "./assets/splash-icon.png",
"userInterfaceStyle": "dark",
"scheme": "stremioexpo",
"newArchEnabled": true,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View file

@ -80,7 +80,7 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => {
>
<View style={styles.catalogHeader}>
<View style={styles.titleContainer}>
<Text style={[styles.catalogTitle, { color: currentTheme.colors.text }]}>{catalog.name}</Text>
<Text style={[styles.catalogTitle, { color: currentTheme.colors.text }]} numberOfLines={1}>{catalog.name}</Text>
<View style={[styles.titleUnderline, { backgroundColor: currentTheme.colors.primary }]} />
</View>
<TouchableOpacity
@ -141,6 +141,8 @@ const styles = StyleSheet.create({
},
titleContainer: {
position: 'relative',
flex: 1,
marginRight: 16,
},
catalogTitle: {
fontSize: 24,
@ -164,7 +166,6 @@ const styles = StyleSheet.create({
paddingHorizontal: 10,
borderRadius: 20,
backgroundColor: 'rgba(255,255,255,0.1)',
marginRight: -10,
},
viewAllText: {
fontSize: 14,

View file

@ -393,8 +393,6 @@ const WrappedScreen: React.FC<{Screen: React.ComponentType<any>}> = ({ Screen })
// Tab Navigator
const MainTabs = () => {
// Always use dark mode
const isDarkMode = true;
const { currentTheme } = useTheme();
const renderTabBar = (props: BottomTabBarProps) => {
@ -536,124 +534,57 @@ const MainTabs = () => {
<Tab.Navigator
tabBar={renderTabBar}
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName: IconNameType = 'home';
switch (route.name) {
case 'Home':
iconName = 'home';
break;
case 'Library':
iconName = 'play-box-multiple';
break;
case 'Search':
iconName = 'feature-search';
break;
case 'Settings':
iconName = 'cog';
break;
}
return <TabIcon focused={focused} color={color} iconName={iconName} />;
},
tabBarActiveTintColor: currentTheme.colors.primary,
tabBarInactiveTintColor: currentTheme.colors.white,
screenOptions={({ route, navigation, theme }) => ({
header: () => (route.name === 'Home' ? <NuvioHeader /> : null),
headerShown: route.name === 'Home',
tabBarShowLabel: false,
tabBarStyle: {
position: 'absolute',
backgroundColor: 'transparent',
borderTopWidth: 0,
elevation: 0,
height: 85,
paddingBottom: 20,
paddingTop: 12,
},
tabBarLabelStyle: {
fontSize: 12,
fontWeight: '600',
marginTop: 0,
},
// Completely disable animations between tabs for better performance
animationEnabled: false,
// Keep all screens mounted and active
lazy: false,
freezeOnBlur: false,
detachPreviousScreen: false,
// Configure how the screen renders
detachInactiveScreens: false,
tabBarBackground: () => (
Platform.OS === 'ios' ? (
<BlurView
tint="dark"
intensity={75}
style={{
position: 'absolute',
height: '100%',
width: '100%',
borderTopColor: currentTheme.colors.border,
borderTopWidth: 0.5,
shadowColor: currentTheme.colors.black,
shadowOffset: { width: 0, height: -2 },
shadowOpacity: 0.1,
shadowRadius: 3,
}}
/>
) : (
<LinearGradient
colors={[
'rgba(0, 0, 0, 0)',
'rgba(0, 0, 0, 0.65)',
'rgba(0, 0, 0, 0.85)',
'rgba(0, 0, 0, 0.98)',
]}
locations={[0, 0.2, 0.4, 0.8]}
style={{
position: 'absolute',
height: '100%',
width: '100%',
}}
/>
)
),
header: () => route.name === 'Home' ? <NuvioHeader /> : null,
headerShown: route.name === 'Home',
// Add fixed screen styling to help with consistency
contentStyle: {
backgroundColor: currentTheme.colors.darkBackground,
},
detachInactiveScreens: false,
})}
// Global configuration for the tab navigator
detachInactiveScreens={false}
>
<Tab.Screen
name="Home"
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size, focused }) => (
<MaterialCommunityIcons name={focused ? 'home' : 'home-outline'} size={size} color={color} />
),
}}
/>
<Tab.Screen
name="Library"
<Tab.Screen
name="Library"
component={LibraryScreen}
options={{
options={{
tabBarLabel: 'Library',
headerShown: false
tabBarIcon: ({ color, size, focused }) => (
<MaterialCommunityIcons name={focused ? 'play-box-multiple' : 'play-box-multiple-outline'} size={size} color={color} />
),
}}
/>
<Tab.Screen
name="Search"
<Tab.Screen
name="Search"
component={SearchScreen}
options={{
options={{
tabBarLabel: 'Search',
headerShown: false
tabBarIcon: ({ color, size, focused }) => (
<MaterialCommunityIcons name={focused ? 'feature-search' : 'feature-search-outline'} size={size} color={color} />
),
}}
/>
<Tab.Screen
name="Settings"
<Tab.Screen
name="Settings"
component={SettingsScreen}
options={{
options={{
tabBarLabel: 'Settings',
headerShown: false
tabBarIcon: ({ color, size, focused }) => (
<MaterialCommunityIcons name={focused ? 'cog' : 'cog-outline'} size={size} color={color} />
),
}}
/>
</Tab.Navigator>

View file

@ -56,7 +56,7 @@ const DOLBY_ICON = 'https://upload.wikimedia.org/wikipedia/en/thumb/3/3f/Dolby_V
const { width, height } = Dimensions.get('window');
// Extracted Components
const StreamCard = ({ stream, onPress, index, isLoading, statusMessage, theme }: {
const StreamCard = memo(({ stream, onPress, index, isLoading, statusMessage, theme }: {
stream: Stream;
onPress: () => void;
index: number;
@ -66,11 +66,19 @@ const StreamCard = ({ stream, onPress, index, isLoading, statusMessage, theme }:
}) => {
const styles = React.useMemo(() => createStyles(theme.colors), [theme.colors]);
const quality = stream.title?.match(/(\d+)p/)?.[1] || null;
const isHDR = stream.title?.toLowerCase().includes('hdr');
const isDolby = stream.title?.toLowerCase().includes('dolby') || stream.title?.includes('DV');
const size = stream.title?.match(/💾\s*([\d.]+\s*[GM]B)/)?.[1];
const isDebrid = stream.behaviorHints?.cached;
const streamInfo = useMemo(() => {
const title = stream.title || '';
const name = stream.name || '';
return {
quality: title.match(/(\d+)p/)?.[1] || null,
isHDR: title.toLowerCase().includes('hdr'),
isDolby: title.toLowerCase().includes('dolby') || title.includes('DV'),
size: title.match(/💾\s*([\d.]+\s*[GM]B)/)?.[1],
isDebrid: stream.behaviorHints?.cached,
displayName: name || title || 'Unnamed Stream',
subTitle: title && title !== name ? title : null
};
}, [stream.name, stream.title, stream.behaviorHints]);
// Animation delay based on index - stagger effect
const enterDelay = 100 + (index * 30);
@ -93,11 +101,11 @@ const StreamCard = ({ stream, onPress, index, isLoading, statusMessage, theme }:
<View style={styles.streamNameRow}>
<View style={styles.streamTitleContainer}>
<Text style={[styles.streamName, { color: theme.colors.highEmphasis }]}>
{stream.name || stream.title || 'Unnamed Stream'}
{streamInfo.displayName}
</Text>
{stream.title && stream.title !== stream.name && (
{streamInfo.subTitle && (
<Text style={[styles.streamAddonName, { color: theme.colors.mediumEmphasis }]}>
{stream.title}
{streamInfo.subTitle}
</Text>
)}
</View>
@ -114,21 +122,21 @@ const StreamCard = ({ stream, onPress, index, isLoading, statusMessage, theme }:
</View>
<View style={styles.streamMetaRow}>
{quality && quality >= "720" && (
{streamInfo.quality && streamInfo.quality >= "720" && (
<QualityBadge type="HD" />
)}
{isDolby && (
{streamInfo.isDolby && (
<QualityBadge type="VISION" />
)}
{size && (
{streamInfo.size && (
<View style={[styles.chip, { backgroundColor: theme.colors.darkGray }]}>
<Text style={[styles.chipText, { color: theme.colors.white }]}>{size}</Text>
<Text style={[styles.chipText, { color: theme.colors.white }]}>{streamInfo.size}</Text>
</View>
)}
{isDebrid && (
{streamInfo.isDebrid && (
<View style={[styles.chip, { backgroundColor: theme.colors.success }]}>
<Text style={[styles.chipText, { color: theme.colors.white }]}>DEBRID</Text>
</View>
@ -146,7 +154,7 @@ const StreamCard = ({ stream, onPress, index, isLoading, statusMessage, theme }:
</TouchableOpacity>
</Animated.View>
);
};
});
const QualityTag = React.memo(({ text, color, theme }: { text: string; color: string; theme: any }) => {
const styles = React.useMemo(() => createStyles(theme.colors), [theme.colors]);
@ -1173,9 +1181,9 @@ export const StreamsScreen = () => {
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
stickySectionHeadersEnabled={false}
initialNumToRender={8}
maxToRenderPerBatch={4}
windowSize={5}
initialNumToRender={6}
maxToRenderPerBatch={3}
windowSize={4}
removeClippedSubviews={false}
contentContainerStyle={styles.streamsContainer}
style={styles.streamsContent}