mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
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:
parent
01d86198ba
commit
c4f5c9e374
5 changed files with 59 additions and 119 deletions
2
app.json
2
app.json
|
|
@ -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 |
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Reference in a new issue