mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
glassview init
This commit is contained in:
parent
13cba764cc
commit
6a6a93aec4
15 changed files with 466 additions and 117 deletions
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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
13
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 }]} />
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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={[
|
||||
|
|
|
|||
|
|
@ -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} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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={[
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 }]} />
|
||||
|
|
|
|||
|
|
@ -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}>
|
||||
|
|
|
|||
|
|
@ -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)}>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue