glassview init

This commit is contained in:
tapframe 2025-10-15 16:12:55 +05:30
parent 13cba764cc
commit 6a6a93aec4
15 changed files with 466 additions and 117 deletions

View file

@ -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";

View file

@ -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

13
package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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<RootStackParamList>;
export const NuvioHeader = () => {
@ -26,7 +41,11 @@ export const NuvioHeader = () => {
Platform.OS === 'android' && { backgroundColor: currentTheme.colors.darkBackground }
]}>
{Platform.OS === 'ios' ? (
<ExpoBlurView intensity={60} style={styles.blurOverlay} tint="dark" />
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp style={styles.blurOverlay} glassEffectStyle="regular" />
) : (
<ExpoBlurView intensity={60} style={styles.blurOverlay} tint="dark" />
)
) : (
// Android: solid themed background instead of blur/transparent overlay
<View style={[styles.androidBlurContainer, { backgroundColor: currentTheme.colors.darkBackground }]} />

View file

@ -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<HeroCarouselProps> = ({ items, loading = false }) =
style={styles.backgroundImage as any}
resizeMode={FastImage.resizeMode.cover}
/>
<BlurView
style={styles.backgroundImage as any}
intensity={30}
tint="dark"
/>
{Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={styles.backgroundImage as any}
glassEffectStyle="regular"
/>
) : (
<BlurView
style={styles.backgroundImage as any}
intensity={30}
tint="dark"
/>
)}
</>
)}
<LinearGradient

View file

@ -11,6 +11,21 @@ import {
import { MaterialIcons } from '@expo/vector-icons';
import { BlurView } from 'expo-blur';
import FastImage from '@d11/react-native-fast-image';
// Optional iOS Glass effect (expo-glass-effect) with safe fallback for CastDetailsModal
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 Animated, {
FadeIn,
FadeOut,
@ -189,17 +204,30 @@ export const CastDetailsModal: React.FC<CastDetailsModalProps> = ({
]}
>
{Platform.OS === 'ios' ? (
<BlurView
intensity={100}
tint="dark"
style={{
width: '100%',
height: '100%',
backgroundColor: 'rgba(20, 20, 20, 0.8)',
}}
>
{renderContent()}
</BlurView>
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={{
width: '100%',
height: '100%',
backgroundColor: 'rgba(20, 20, 20, 0.8)',
}}
glassEffectStyle="regular"
>
{renderContent()}
</GlassViewComp>
) : (
<BlurView
intensity={100}
tint="dark"
style={{
width: '100%',
height: '100%',
backgroundColor: 'rgba(20, 20, 20, 0.8)',
}}
>
{renderContent()}
</BlurView>
)
) : (
renderContent()
)}

View file

@ -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<FloatingHeaderProps> = ({
return (
<Animated.View style={[styles.floatingHeader, headerAnimatedStyle]} pointerEvents={isHeaderInteractive ? 'auto' : 'none'}>
{Platform.OS === 'ios' ? (
<ExpoBlurView
intensity={50}
tint="dark"
style={[styles.blurContainer, { paddingTop: Math.max(safeAreaTop * 0.8, safeAreaTop - 6) }]}
>
<Animated.View style={[styles.floatingHeaderContent, headerElementsStyle]}>
<TouchableOpacity
style={styles.backButton}
onPress={handleBack}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<MaterialIcons
name="arrow-back"
size={24}
color={currentTheme.colors.highEmphasis}
/>
</TouchableOpacity>
<View style={styles.headerTitleContainer}>
{metadata.logo && !logoLoadError ? (
<FastImage
source={{ uri: metadata.logo }}
style={styles.floatingHeaderLogo}
resizeMode={FastImage.resizeMode.contain}
onError={() => {
logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`);
setLogoLoadError(true);
}}
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={[styles.blurContainer, { paddingTop: Math.max(safeAreaTop * 0.8, safeAreaTop - 6) }]}
glassEffectStyle="regular"
>
<Animated.View style={[styles.floatingHeaderContent, headerElementsStyle]}>
<TouchableOpacity
style={styles.backButton}
onPress={handleBack}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<MaterialIcons
name="arrow-back"
size={24}
color={currentTheme.colors.highEmphasis}
/>
) : (
<Text style={[styles.floatingHeaderTitle, { color: currentTheme.colors.highEmphasis }]} numberOfLines={1}>{metadata.name}</Text>
)}
</View>
<TouchableOpacity
style={styles.headerActionButton}
onPress={handleToggleLibrary}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<Feather name="bookmark" size={22} color={currentTheme.colors.highEmphasis} />
</TouchableOpacity>
</Animated.View>
</ExpoBlurView>
</TouchableOpacity>
<View style={styles.headerTitleContainer}>
{metadata.logo && !logoLoadError ? (
<FastImage
source={{ uri: metadata.logo }}
style={styles.floatingHeaderLogo}
resizeMode={FastImage.resizeMode.contain}
onError={() => {
logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`);
setLogoLoadError(true);
}}
/>
) : (
<Text style={[styles.floatingHeaderTitle, { color: currentTheme.colors.highEmphasis }]} numberOfLines={1}>{metadata.name}</Text>
)}
</View>
<TouchableOpacity
style={styles.headerActionButton}
onPress={handleToggleLibrary}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<Feather name="bookmark" size={22} color={currentTheme.colors.highEmphasis} />
</TouchableOpacity>
</Animated.View>
</GlassViewComp>
) : (
<ExpoBlurView
intensity={50}
tint="dark"
style={[styles.blurContainer, { paddingTop: Math.max(safeAreaTop * 0.8, safeAreaTop - 6) }]}
>
<Animated.View style={[styles.floatingHeaderContent, headerElementsStyle]}>
<TouchableOpacity
style={styles.backButton}
onPress={handleBack}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<MaterialIcons
name="arrow-back"
size={24}
color={currentTheme.colors.highEmphasis}
/>
</TouchableOpacity>
<View style={styles.headerTitleContainer}>
{metadata.logo && !logoLoadError ? (
<FastImage
source={{ uri: metadata.logo }}
style={styles.floatingHeaderLogo}
resizeMode={FastImage.resizeMode.contain}
onError={() => {
logger.warn(`[FloatingHeader] Logo failed to load: ${metadata.logo}`);
setLogoLoadError(true);
}}
/>
) : (
<Text style={[styles.floatingHeaderTitle, { color: currentTheme.colors.highEmphasis }]} numberOfLines={1}>{metadata.name}</Text>
)}
</View>
<TouchableOpacity
style={styles.headerActionButton}
onPress={handleToggleLibrary}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
<Feather name="bookmark" size={22} color={currentTheme.colors.highEmphasis} />
</TouchableOpacity>
</Animated.View>
</ExpoBlurView>
)
) : (
<View
style={[

View file

@ -17,6 +17,21 @@ import { LinearGradient } from 'expo-linear-gradient';
// Replaced FastImage with standard Image for logos
import { BlurView as ExpoBlurView } from 'expo-blur';
import { BlurView as CommunityBlurView } from '@react-native-community/blur';
// Optional iOS Glass effect (expo-glass-effect) with safe fallback for HeroSection
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 Constants, { ExecutionEnvironment } from 'expo-constants';
import Animated, {
useAnimatedStyle,
@ -282,7 +297,14 @@ const ActionButtons = memo(({
activeOpacity={0.85}
>
{Platform.OS === 'ios' ? (
<ExpoBlurView intensity={80} style={styles.blurBackground} tint="dark" />
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={styles.blurBackground}
glassEffectStyle="regular"
/>
) : (
<ExpoBlurView intensity={80} style={styles.blurBackground} tint="dark" />
)
) : (
<View style={styles.androidFallbackBlur} />
)}
@ -325,7 +347,14 @@ const ActionButtons = memo(({
activeOpacity={0.85}
>
{Platform.OS === 'ios' ? (
<ExpoBlurView intensity={80} style={styles.blurBackgroundRound} tint="dark" />
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={styles.blurBackgroundRound}
glassEffectStyle="regular"
/>
) : (
<ExpoBlurView intensity={80} style={styles.blurBackgroundRound} tint="dark" />
)
) : (
<View style={styles.androidFallbackBlurRound} />
)}
@ -344,7 +373,14 @@ const ActionButtons = memo(({
activeOpacity={0.85}
>
{Platform.OS === 'ios' ? (
<ExpoBlurView intensity={80} style={styles.blurBackgroundRound} tint="dark" />
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={styles.blurBackgroundRound}
glassEffectStyle="regular"
/>
) : (
<ExpoBlurView intensity={80} style={styles.blurBackgroundRound} tint="dark" />
)
) : (
<View style={styles.androidFallbackBlurRound} />
)}
@ -605,7 +641,14 @@ const WatchProgressDisplay = memo(({
{/* Glass morphism background with entrance animation */}
<Animated.View style={[isTablet ? styles.tabletProgressGlassBackground : styles.progressGlassBackground, progressBoxAnimatedStyle]}>
{Platform.OS === 'ios' ? (
<ExpoBlurView intensity={20} style={styles.blurBackground} tint="dark" />
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={styles.blurBackground}
glassEffectStyle="regular"
/>
) : (
<ExpoBlurView intensity={20} style={styles.blurBackground} tint="dark" />
)
) : (
<View style={styles.androidProgressBlur} />
)}

View file

@ -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 && (
<BlurView
tint="dark"
intensity={75}
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 28,
}}
/>
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 28,
}}
glassEffectStyle="clear"
/>
) : (
<BlurView
tint="dark"
intensity={75}
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 28,
}}
/>
)
)}
{props.state.routes.map((route, index) => {
const { options } = props.descriptors[route.key];
@ -648,21 +677,32 @@ const MainTabs = () => {
overflow: 'hidden',
}}>
{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,
}}
/>
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={{
position: 'absolute',
height: '100%',
width: '100%',
}}
glassEffectStyle="clear"
/>
) : (
<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={[

View file

@ -30,6 +30,21 @@ if (Platform.OS === 'android') {
AndroidBlurView = null;
}
}
// Optional iOS Glass effect (expo-glass-effect) with safe fallback for AIChatScreen
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 { useSafeAreaInsets, SafeAreaView } from 'react-native-safe-area-context';
import { aiService, ChatMessage, ContentContext, createMovieContext, createEpisodeContext, createSeriesContext, generateConversationStarters } from '../services/aiService';
import { tmdbService } from '../services/tmdbService';
@ -124,6 +139,8 @@ const ChatBubble: React.FC<ChatBubbleProps> = React.memo(({ message, isLast }) =
<View style={styles.assistantBlurBackdrop} pointerEvents="none">
{Platform.OS === 'android' && AndroidBlurView
? <AndroidBlurView blurAmount={16} blurRadius={8} style={StyleSheet.absoluteFill} />
: Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable
? <GlassViewComp style={StyleSheet.absoluteFill} glassEffectStyle="regular" />
: <ExpoBlurView intensity={70} tint="dark" style={StyleSheet.absoluteFill} />}
<View style={[StyleSheet.absoluteFill, { backgroundColor: 'rgba(0,0,0,0.50)' }]} />
</View>
@ -649,6 +666,8 @@ const AIChatScreen: React.FC = () => {
/>
{Platform.OS === 'android' && AndroidBlurView
? <AndroidBlurView blurAmount={12} blurRadius={6} style={StyleSheet.absoluteFill} />
: Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable
? <GlassViewComp style={StyleSheet.absoluteFill} glassEffectStyle="regular" />
: <ExpoBlurView intensity={60} tint="dark" style={StyleSheet.absoluteFill} />}
<View style={[StyleSheet.absoluteFill, { backgroundColor: Platform.OS === 'android' ? 'rgba(0,0,0,0.28)' : 'rgba(0,0,0,0.45)' }]} />
</View>
@ -780,6 +799,8 @@ const AIChatScreen: React.FC = () => {
<View style={styles.inputBlurBackdrop} pointerEvents="none">
{Platform.OS === 'android' && AndroidBlurView
? <AndroidBlurView blurAmount={10} blurRadius={4} style={StyleSheet.absoluteFill} />
: Platform.OS === 'ios' && GlassViewComp && liquidGlassAvailable
? <GlassViewComp style={StyleSheet.absoluteFill} glassEffectStyle="regular" />
: <ExpoBlurView intensity={50} tint="dark" style={StyleSheet.absoluteFill} />}
<View style={[StyleSheet.absoluteFill, { backgroundColor: Platform.OS === 'android' ? 'rgba(0,0,0,0.15)' : 'rgba(0,0,0,0.25)' }]} />
</View>

View file

@ -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 = () => {
>
<View style={styles.modalContainer}>
{Platform.OS === 'ios' ? (
<ExpoBlurView intensity={80} style={styles.blurOverlay} tint="dark" />
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp style={styles.blurOverlay} glassEffectStyle="regular" />
) : (
<ExpoBlurView intensity={80} style={styles.blurOverlay} tint="dark" />
)
) : (
// Android: use solid themed background instead of semi-transparent overlay
<View style={[styles.androidBlurContainer, { backgroundColor: colors.darkBackground }]} />

View file

@ -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<CatalogScreenProps> = ({ route, navigation }) => {
{type === 'movie' && nowPlayingMovies.has(item.id) && (
Platform.OS === 'ios' ? (
<View style={styles.badgeBlur}>
<BlurView intensity={40} tint={isDarkMode ? 'dark' : 'light'} style={{ borderRadius: 10 }}>
<View style={styles.badgeContent}>
<MaterialIcons
name="theaters"
size={12}
color={colors.white}
style={{ marginRight: 4 }}
/>
<Text style={styles.badgeText}>In Theaters</Text>
</View>
</BlurView>
{GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp style={{ borderRadius: 10 }} glassEffectStyle="regular">
<View style={styles.badgeContent}>
<MaterialIcons
name="theaters"
size={12}
color={colors.white}
style={{ marginRight: 4 }}
/>
<Text style={styles.badgeText}>In Theaters</Text>
</View>
</GlassViewComp>
) : (
<BlurView intensity={40} tint={isDarkMode ? 'dark' : 'light'} style={{ borderRadius: 10 }}>
<View style={styles.badgeContent}>
<MaterialIcons
name="theaters"
size={12}
color={colors.white}
style={{ marginRight: 4 }}
/>
<Text style={styles.badgeText}>In Theaters</Text>
</View>
</BlurView>
)}
</View>
) : (
<View style={styles.badgeContainer}>

View file

@ -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' ? (
<Pressable style={styles.modalOverlay} onPress={() => setIsRenameModalVisible(false)}>
<BlurView
style={styles.modalContent}
intensity={90}
tint="default"
>
{GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={styles.modalContent}
glassEffectStyle="regular"
>
) : (
<BlurView
style={styles.modalContent}
intensity={90}
tint="default"
>
)}
<Pressable onPress={(e) => e.stopPropagation()}>
<Text style={styles.modalTitle}>Rename Catalog</Text>
<TextInput
@ -672,7 +694,11 @@ const CatalogSettingsScreen = () => {
<Button title="Save" onPress={handleSaveRename} color={colors.primary} />
</View>
</Pressable>
</BlurView>
{GlassViewComp && liquidGlassAvailable ? (
</GlassViewComp>
) : (
</BlurView>
)}
</Pressable>
) : (
<Pressable style={styles.modalOverlay} onPress={() => setIsRenameModalVisible(false)}>

View file

@ -13,6 +13,21 @@ import {
import FastImage from '@d11/react-native-fast-image';
import { BlurView } from 'expo-blur';
import { useTheme } from '../contexts/ThemeContext';
// Optional iOS Glass effect (expo-glass-effect) with safe fallback for ShowRatingsScreen
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 { TMDBService, TMDBShow as Show, TMDBSeason, TMDBEpisode } from '../services/tmdbService';
import { RouteProp } from '@react-navigation/native';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
@ -367,11 +382,18 @@ const ShowRatingsScreen = ({ route }: Props) => {
return (
<View style={[styles.container, { backgroundColor: Platform.OS === 'ios' ? 'transparent' : colors.black }]}>
{Platform.OS === 'ios' && (
<BlurView
style={StyleSheet.absoluteFill}
tint="dark"
intensity={60}
/>
GlassViewComp && liquidGlassAvailable ? (
<GlassViewComp
style={StyleSheet.absoluteFill}
glassEffectStyle="regular"
/>
) : (
<BlurView
style={StyleSheet.absoluteFill}
tint="dark"
intensity={60}
/>
)
)}
<StatusBar
translucent