From 6a6a93aec45b8c59337881d535b1c6b3cb727b9e Mon Sep 17 00:00:00 2001 From: tapframe Date: Wed, 15 Oct 2025 16:12:55 +0530 Subject: [PATCH] glassview init --- ios/Nuvio.xcodeproj/project.pbxproj | 8 +- ios/Podfile.lock | 6 + package-lock.json | 13 ++ package.json | 1 + src/components/NuvioHeader.tsx | 21 ++- src/components/home/HeroCarousel.tsx | 32 ++++- src/components/metadata/CastDetailsModal.tsx | 50 +++++-- src/components/metadata/FloatingHeader.tsx | 144 +++++++++++++------ src/components/metadata/HeroSection.tsx | 51 ++++++- src/navigation/AppNavigator.tsx | 94 ++++++++---- src/screens/AIChatScreen.tsx | 21 +++ src/screens/AddonsScreen.tsx | 21 ++- src/screens/CatalogScreen.tsx | 51 +++++-- src/screens/CatalogSettingsScreen.tsx | 38 ++++- src/screens/ShowRatingsScreen.tsx | 32 ++++- 15 files changed, 466 insertions(+), 117 deletions(-) diff --git a/ios/Nuvio.xcodeproj/project.pbxproj b/ios/Nuvio.xcodeproj/project.pbxproj index b562e96..084418f 100644 --- a/ios/Nuvio.xcodeproj/project.pbxproj +++ b/ios/Nuvio.xcodeproj/project.pbxproj @@ -460,8 +460,8 @@ "-lc++", ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; - PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app"; - PRODUCT_NAME = "Nuvio"; + PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app; + PRODUCT_NAME = Nuvio; SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -492,8 +492,8 @@ "-lc++", ); OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; - PRODUCT_BUNDLE_IDENTIFIER = "com.nuvio.app"; - PRODUCT_NAME = "Nuvio"; + PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app; + PRODUCT_NAME = Nuvio; SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4e82b52..b90feb2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -223,6 +223,8 @@ PODS: - ExpoModulesCore - ExpoFont (14.0.9): - ExpoModulesCore + - ExpoGlassEffect (0.1.4): + - ExpoModulesCore - ExpoHaptics (15.0.7): - ExpoModulesCore - ExpoKeepAwake (15.0.7): @@ -2652,6 +2654,7 @@ DEPENDENCIES: - ExpoDocumentPicker (from `../node_modules/expo-document-picker/ios`) - ExpoFileSystem (from `../node_modules/expo-file-system/ios`) - ExpoFont (from `../node_modules/expo-font/ios`) + - ExpoGlassEffect (from `../node_modules/expo-glass-effect/ios`) - ExpoHaptics (from `../node_modules/expo-haptics/ios`) - ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`) - ExpoLibVlcPlayer (from `../node_modules/expo-libvlc-player/ios`) @@ -2813,6 +2816,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-file-system/ios" ExpoFont: :path: "../node_modules/expo-font/ios" + ExpoGlassEffect: + :path: "../node_modules/expo-glass-effect/ios" ExpoHaptics: :path: "../node_modules/expo-haptics/ios" ExpoKeepAwake: @@ -3061,6 +3066,7 @@ SPEC CHECKSUMS: ExpoDocumentPicker: 2200eefc2817f19315fa18f0147e0b80ece86926 ExpoFileSystem: b79eadbda7b7f285f378f95f959cc9313a1c9c61 ExpoFont: cf9d90ec1d3b97c4f513211905724c8171f82961 + ExpoGlassEffect: 744bf0c58c26a1b0212dff92856be07b98d01d8c ExpoHaptics: 807476b0c39e9d82b7270349d6487928ce32df84 ExpoKeepAwake: 1a2e820692e933c94a565ec3fbbe38ac31658ffe ExpoLibVlcPlayer: dce3d0b5847838cd5f8c5f3c3aa1bc55c92e911d diff --git a/package-lock.json b/package-lock.json index 4725d60..4493746 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "nuvio", "version": "0.6.0-beta.6", + "hasInstallScript": true, "dependencies": { "@adrianso/react-native-device-brightness": "^1.2.7", "@backpackapp-io/react-native-toast": "^0.14.0", @@ -46,6 +47,7 @@ "expo-device": "~8.0.9", "expo-document-picker": "~14.0.7", "expo-file-system": "~19.0.17", + "expo-glass-effect": "~0.1.4", "expo-haptics": "~15.0.7", "expo-intent-launcher": "~13.0.7", "expo-libvlc-player": "^2.1.7", @@ -6601,6 +6603,17 @@ "react-native": "*" } }, + "node_modules/expo-glass-effect": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/expo-glass-effect/-/expo-glass-effect-0.1.4.tgz", + "integrity": "sha512-RW7lf2SWNVSvpJqBxQUlC/VVzeeHFrJeoKoIlNIFfKTFj3HyF7xQKq6/h/bpO8M0ssy0v5KEKw4GggkjTwx7Fw==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-haptics": { "version": "15.0.7", "resolved": "https://registry.npmjs.org/expo-haptics/-/expo-haptics-15.0.7.tgz", diff --git a/package.json b/package.json index 0d0eba2..2662e1b 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "expo-device": "~8.0.9", "expo-document-picker": "~14.0.7", "expo-file-system": "~19.0.17", + "expo-glass-effect": "~0.1.4", "expo-haptics": "~15.0.7", "expo-intent-launcher": "~13.0.7", "expo-libvlc-player": "^2.1.7", diff --git a/src/components/NuvioHeader.tsx b/src/components/NuvioHeader.tsx index fd2596f..5f813fb 100644 --- a/src/components/NuvioHeader.tsx +++ b/src/components/NuvioHeader.tsx @@ -7,6 +7,21 @@ import type { RootStackParamList } from '../navigation/AppNavigator'; import { BlurView as ExpoBlurView } from 'expo-blur'; import { useTheme } from '../contexts/ThemeContext'; +// Optional iOS Glass effect (expo-glass-effect) with safe fallback for NuvioHeader +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} + type NavigationProp = NativeStackNavigationProp; export const NuvioHeader = () => { @@ -26,7 +41,11 @@ export const NuvioHeader = () => { Platform.OS === 'android' && { backgroundColor: currentTheme.colors.darkBackground } ]}> {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( // Android: solid themed background instead of blur/transparent overlay diff --git a/src/components/home/HeroCarousel.tsx b/src/components/home/HeroCarousel.tsx index 18f809a..fb7e20c 100644 --- a/src/components/home/HeroCarousel.tsx +++ b/src/components/home/HeroCarousel.tsx @@ -4,6 +4,21 @@ import Animated, { FadeIn, FadeOut, Easing, useSharedValue, withTiming, useAnima import { LinearGradient } from 'expo-linear-gradient'; import { BlurView } from 'expo-blur'; import FastImage from '@d11/react-native-fast-image'; + +// Optional iOS Glass effect (expo-glass-effect) with safe fallback for HeroCarousel +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} import { MaterialIcons } from '@expo/vector-icons'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; @@ -179,11 +194,18 @@ const HeroCarousel: React.FC = ({ items, loading = false }) = style={styles.backgroundImage as any} resizeMode={FastImage.resizeMode.cover} /> - + {Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + )} )} = ({ ]} > {Platform.OS === 'ios' ? ( - - {renderContent()} - + GlassViewComp && liquidGlassAvailable ? ( + + {renderContent()} + + ) : ( + + {renderContent()} + + ) ) : ( renderContent() )} diff --git a/src/components/metadata/FloatingHeader.tsx b/src/components/metadata/FloatingHeader.tsx index 5e3a6ed..ead8704 100644 --- a/src/components/metadata/FloatingHeader.tsx +++ b/src/components/metadata/FloatingHeader.tsx @@ -9,6 +9,21 @@ import { } from 'react-native'; import { BlurView as ExpoBlurView } from 'expo-blur'; import { MaterialIcons, Feather } from '@expo/vector-icons'; + +// Optional iOS Glass effect (expo-glass-effect) with safe fallback for FloatingHeader +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} import FastImage from '@d11/react-native-fast-image'; import Animated, { useAnimatedStyle, @@ -77,49 +92,94 @@ const FloatingHeader: React.FC = ({ return ( {Platform.OS === 'ios' ? ( - - - - - - - - {metadata.logo && !logoLoadError ? ( - { - logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`); - setLogoLoadError(true); - }} + GlassViewComp && liquidGlassAvailable ? ( + + + + - ) : ( - {metadata.name} - )} - - - - - - - + + + + {metadata.logo && !logoLoadError ? ( + { + logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`); + setLogoLoadError(true); + }} + /> + ) : ( + {metadata.name} + )} + + + + + + + + ) : ( + + + + + + + + {metadata.logo && !logoLoadError ? ( + { + logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`); + setLogoLoadError(true); + }} + /> + ) : ( + {metadata.name} + )} + + + + + + + + ) ) : ( {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( )} @@ -325,7 +347,14 @@ const ActionButtons = memo(({ activeOpacity={0.85} > {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( )} @@ -344,7 +373,14 @@ const ActionButtons = memo(({ activeOpacity={0.85} > {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( )} @@ -605,7 +641,14 @@ const WatchProgressDisplay = memo(({ {/* Glass morphism background with entrance animation */} {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( )} diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index 72eb7c3..69fb54e 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -18,6 +18,21 @@ import { useTheme } from '../contexts/ThemeContext'; import ToastManager from 'toastify-react-native'; import { PostHogProvider } from 'posthog-react-native'; +// Optional iOS Glass effect (expo-glass-effect) with safe fallback +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} + // Import screens with their proper types import HomeScreen from '../screens/HomeScreen'; import LibraryScreen from '../screens/LibraryScreen'; @@ -572,18 +587,32 @@ const MainTabs = () => { backgroundColor: isIosTablet ? 'transparent' : 'rgba(0,0,0,0.7)' }}> {isIosTablet && ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) )} {props.state.routes.map((route, index) => { const { options } = props.descriptors[route.key]; @@ -648,21 +677,32 @@ const MainTabs = () => { overflow: 'hidden', }}> {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( = React.memo(({ message, isLast }) = {Platform.OS === 'android' && AndroidBlurView ? + : Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable + ? : } @@ -649,6 +666,8 @@ const AIChatScreen: React.FC = () => { /> {Platform.OS === 'android' && AndroidBlurView ? + : Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable + ? : } @@ -780,6 +799,8 @@ const AIChatScreen: React.FC = () => { {Platform.OS === 'android' && AndroidBlurView ? + : Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable + ? : } diff --git a/src/screens/AddonsScreen.tsx b/src/screens/AddonsScreen.tsx index fa0d1d9..3a4c7e5 100644 --- a/src/screens/AddonsScreen.tsx +++ b/src/screens/AddonsScreen.tsx @@ -30,6 +30,21 @@ import { logger } from '../utils/logger'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { BlurView as ExpoBlurView } from 'expo-blur'; import CustomAlert from '../components/CustomAlert'; + +// Optional iOS Glass effect (expo-glass-effect) with safe fallback for AddonsScreen +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} // Removed community blur and expo-constants for Android overlay import axios from 'axios'; import { useTheme } from '../contexts/ThemeContext'; @@ -1391,7 +1406,11 @@ const AddonsScreen = () => { > {Platform.OS === 'ios' ? ( - + GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + ) ) : ( // Android: use solid themed background instead of semi-transparent overlay diff --git a/src/screens/CatalogScreen.tsx b/src/screens/CatalogScreen.tsx index 6293bed..00c6da8 100644 --- a/src/screens/CatalogScreen.tsx +++ b/src/screens/CatalogScreen.tsx @@ -21,6 +21,21 @@ import { useTheme } from '../contexts/ThemeContext'; import FastImage from '@d11/react-native-fast-image'; import { BlurView } from 'expo-blur'; import { MaterialIcons } from '@expo/vector-icons'; + +// Optional iOS Glass effect (expo-glass-effect) with safe fallback for CatalogScreen +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} import { logger } from '../utils/logger'; import { useCustomCatalogNames } from '../hooks/useCustomCatalogNames'; import AsyncStorage from '@react-native-async-storage/async-storage'; @@ -629,17 +644,31 @@ const CatalogScreen: React.FC = ({ route, navigation }) => { {type === 'movie' && nowPlayingMovies.has(item.id) && ( Platform.OS === 'ios' ? ( - - - - In Theaters - - + {GlassViewComp && liquidGlassAvailable ? ( + + + + In Theaters + + + ) : ( + + + + In Theaters + + + )} ) : ( diff --git a/src/screens/CatalogSettingsScreen.tsx b/src/screens/CatalogSettingsScreen.tsx index 28d8052..cf6a20d 100644 --- a/src/screens/CatalogSettingsScreen.tsx +++ b/src/screens/CatalogSettingsScreen.tsx @@ -26,6 +26,21 @@ import { clearCustomNameCache } from '../utils/catalogNameUtils'; import { BlurView } from 'expo-blur'; import CustomAlert from '../components/CustomAlert'; +// Optional iOS Glass effect (expo-glass-effect) with safe fallback for CatalogSettingsScreen +let GlassViewComp: any = null; +let liquidGlassAvailable = false; +if (Platform.OS === 'ios') { + try { + // Dynamically require so app still runs if the package isn't installed yet + const glass = require('expo-glass-effect'); + GlassViewComp = glass.GlassView; + liquidGlassAvailable = typeof glass.isLiquidGlassAvailable === 'function' ? glass.isLiquidGlassAvailable() : false; + } catch { + GlassViewComp = null; + liquidGlassAvailable = false; + } +} + interface CatalogSetting { addonId: string; catalogId: string; @@ -652,11 +667,18 @@ const CatalogSettingsScreen = () => { > {Platform.OS === 'ios' ? ( setIsRenameModalVisible(false)}> - + {GlassViewComp && liquidGlassAvailable ? ( + + ) : ( + + )} e.stopPropagation()}> Rename Catalog {