ui changes

This commit is contained in:
tapframe 2025-09-11 17:27:51 +05:30
parent 9ba14f2f33
commit 0290b9318e
3 changed files with 122 additions and 18 deletions

View file

@ -1254,11 +1254,11 @@ const InnerNavigator = ({ initialRouteName }: { initialRouteName?: keyof RootSta
name="AIChat"
component={AIChatScreen}
options={{
animation: Platform.OS === 'android' ? 'slide_from_bottom' : 'slide_from_bottom',
animationDuration: Platform.OS === 'android' ? 250 : 300,
animation: Platform.OS === 'android' ? 'none' : 'slide_from_bottom',
animationDuration: Platform.OS === 'android' ? 220 : 300,
presentation: 'modal',
gestureEnabled: true,
gestureDirection: 'vertical',
gestureDirection: Platform.OS === 'android' ? 'vertical' : 'vertical',
headerShown: false,
contentStyle: {
backgroundColor: currentTheme.colors.darkBackground,

View file

@ -14,9 +14,12 @@ import {
ActivityIndicator,
Alert,
} from 'react-native';
import { useRoute, useNavigation, RouteProp } from '@react-navigation/native';
import { useRoute, useNavigation, RouteProp, useFocusEffect } from '@react-navigation/native';
import { MaterialIcons } from '@expo/vector-icons';
import { useTheme } from '../contexts/ThemeContext';
import { Image } from 'expo-image';
import { BlurView as ExpoBlurView } from 'expo-blur';
import { BlurView as CommunityBlurView } from '@react-native-community/blur';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { aiService, ChatMessage, ContentContext, createMovieContext, createEpisodeContext, generateConversationStarters } from '../services/aiService';
import { tmdbService } from '../services/tmdbService';
@ -27,7 +30,8 @@ import Animated, {
withSpring,
withTiming,
interpolate,
Extrapolate
Extrapolate,
runOnJS
} from 'react-native-reanimated';
const { width, height } = Dimensions.get('window');
@ -102,10 +106,18 @@ const ChatBubble: React.FC<ChatBubbleProps> = ({ message, isLast }) => {
styles.userBubble,
{ backgroundColor: currentTheme.colors.primary }
] : [
styles.assistantBubble,
{ backgroundColor: currentTheme.colors.elevation2 }
styles.assistantBubble,
{ backgroundColor: 'transparent' }
]
]}>
{!isUser && (
<View style={styles.assistantBlurBackdrop} pointerEvents="none">
{Platform.OS === 'ios'
? <ExpoBlurView intensity={70} tint="dark" style={StyleSheet.absoluteFill} />
: <CommunityBlurView blurAmount={16} blurRadius={8} style={StyleSheet.absoluteFill} />}
<View style={[StyleSheet.absoluteFill, { backgroundColor: 'rgba(0,0,0,0.50)' }]} />
</View>
)}
{isUser ? (
<Text style={[styles.messageText, { color: 'white' }]}>
{message.content}
@ -281,6 +293,18 @@ const AIChatScreen: React.FC = () => {
const [context, setContext] = useState<ContentContext | null>(null);
const [isLoadingContext, setIsLoadingContext] = useState(true);
const [suggestions, setSuggestions] = useState<string[]>([]);
const [backdropUrl, setBackdropUrl] = useState<string | null>(null);
// Ensure Android cleans up heavy image resources when leaving the screen to avoid flash on back
useFocusEffect(
React.useCallback(() => {
return () => {
if (Platform.OS === 'android') {
setBackdropUrl(null);
}
};
}, [])
);
const scrollViewRef = useRef<ScrollView>(null);
const inputRef = useRef<TextInput>(null);
@ -288,11 +312,21 @@ const AIChatScreen: React.FC = () => {
// Animation values
const headerOpacity = useSharedValue(1);
const inputContainerY = useSharedValue(0);
// Android full-screen modal fade
const modalOpacity = useSharedValue(Platform.OS === 'android' ? 0 : 1);
useEffect(() => {
loadContext();
}, []);
// Animate in on Android for full-screen modal feel
useEffect(() => {
if (Platform.OS === 'android') {
// Use spring to avoid jank on some devices
modalOpacity.value = withSpring(1, { damping: 20, stiffness: 140 });
}
}, [modalOpacity]);
useEffect(() => {
if (context && messages.length === 0) {
// Generate conversation starters
@ -320,6 +354,10 @@ const AIChatScreen: React.FC = () => {
const movieContext = createMovieContext(movieData);
setContext(movieContext);
try {
const path = movieData.backdrop_path || movieData.poster_path || null;
if (path) setBackdropUrl(`https://image.tmdb.org/t/p/w780${path}`);
} catch {}
} else {
// Series: resolve TMDB numeric id first (contentId may be IMDb/stremio id)
let tmdbNumericId: number | null = null;
@ -343,6 +381,10 @@ const AIChatScreen: React.FC = () => {
]);
if (!showData) throw new Error('Unable to load TV show details');
try {
const path = showData.backdrop_path || showData.poster_path || null;
if (path) setBackdropUrl(`https://image.tmdb.org/t/p/w780${path}`);
} catch {}
if (episodeData && seasonNumber && episodeNumber) {
const episodeContext = createEpisodeContext(
@ -533,21 +575,44 @@ const AIChatScreen: React.FC = () => {
}
return (
<Animated.View style={{ flex: 1, opacity: modalOpacity }}>
<SafeAreaView style={[styles.container, { backgroundColor: currentTheme.colors.darkBackground }]}>
{backdropUrl && (
<View style={StyleSheet.absoluteFill} pointerEvents="none">
<Image
source={{ uri: backdropUrl }}
style={StyleSheet.absoluteFill}
contentFit="cover"
recyclingKey={backdropUrl || undefined}
/>
{Platform.OS === 'ios'
? <ExpoBlurView intensity={60} tint="dark" style={StyleSheet.absoluteFill} />
: <CommunityBlurView blurAmount={12} blurRadius={6} style={StyleSheet.absoluteFill} />}
<View style={[StyleSheet.absoluteFill, { backgroundColor: Platform.OS === 'android' ? 'rgba(0,0,0,0.28)' : 'rgba(0,0,0,0.45)' }]} />
</View>
)}
<StatusBar barStyle="light-content" />
{/* Header */}
<Animated.View style={[
styles.header,
{
backgroundColor: currentTheme.colors.darkBackground,
paddingTop: insets.top
backgroundColor: 'transparent',
paddingTop: Platform.OS === 'ios' ? 8 : insets.top
},
headerAnimatedStyle
]}>
<View style={styles.headerContent}>
<TouchableOpacity
onPress={() => navigation.goBack()}
onPress={() => {
if (Platform.OS === 'android') {
modalOpacity.value = withSpring(0, { damping: 18, stiffness: 160 }, (finished) => {
if (finished) runOnJS(navigation.goBack)();
});
} else {
navigation.goBack();
}
}}
style={styles.backButton}
>
<MaterialIcons name="arrow-back" size={24} color={currentTheme.colors.text} />
@ -571,13 +636,16 @@ const AIChatScreen: React.FC = () => {
{/* Chat Messages */}
<KeyboardAvoidingView
style={styles.chatContainer}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={insets.top + 60}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
keyboardVerticalOffset={Platform.OS === 'ios' ? insets.top + 60 : 0}
>
<ScrollView
ref={scrollViewRef}
style={styles.messagesContainer}
contentContainerStyle={styles.messagesContent}
contentContainerStyle={[
styles.messagesContent,
{ paddingBottom: 120 + insets.bottom }
]}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
>
@ -637,10 +705,19 @@ const AIChatScreen: React.FC = () => {
{/* Input Container */}
<Animated.View style={[
styles.inputContainer,
{ backgroundColor: currentTheme.colors.darkBackground },
{
backgroundColor: 'transparent',
paddingBottom: 12 + insets.bottom
},
inputAnimatedStyle
]}>
<View style={[styles.inputWrapper, { backgroundColor: currentTheme.colors.elevation1 }]}>
<View style={[styles.inputWrapper, { backgroundColor: 'transparent' }]}>
<View style={styles.inputBlurBackdrop} pointerEvents="none">
{Platform.OS === 'ios'
? <ExpoBlurView intensity={50} tint="dark" style={StyleSheet.absoluteFill} />
: <CommunityBlurView blurAmount={10} blurRadius={4} style={StyleSheet.absoluteFill} />}
<View style={[StyleSheet.absoluteFill, { backgroundColor: Platform.OS === 'android' ? 'rgba(0,0,0,0.15)' : 'rgba(0,0,0,0.25)' }]} />
</View>
<TextInput
ref={inputRef}
style={[
@ -679,6 +756,7 @@ const AIChatScreen: React.FC = () => {
</Animated.View>
</KeyboardAvoidingView>
</SafeAreaView>
</Animated.View>
);
};
@ -827,12 +905,17 @@ const styles = StyleSheet.create({
paddingHorizontal: 16,
paddingVertical: 12,
borderRadius: 20,
overflow: 'hidden',
},
userBubble: {
borderBottomRightRadius: 4,
borderBottomRightRadius: 20,
},
assistantBubble: {
borderBottomLeftRadius: 4,
borderBottomLeftRadius: 20,
},
assistantBlurBackdrop: {
...StyleSheet.absoluteFillObject,
borderRadius: 20,
},
messageText: {
fontSize: 16,
@ -876,6 +959,11 @@ const styles = StyleSheet.create({
paddingHorizontal: 16,
paddingVertical: 8,
gap: 12,
overflow: 'hidden'
},
inputBlurBackdrop: {
...StyleSheet.absoluteFillObject,
borderRadius: 24,
},
textInput: {
flex: 1,

View file

@ -132,7 +132,16 @@ CRITICAL INSTRUCTIONS:
3. If Release Status shows "RELEASED AND AVAILABLE FOR VIEWING", the content IS AVAILABLE. Do not say it's "upcoming" or "unreleased".
4. Compare air dates to today's date (${currentDate}) to determine if something has already aired.
5. Base ALL responses on the verified information above, NOT on your training knowledge.
6. If asked about release dates or availability, refer ONLY to the database information provided.`;
6. If asked about release dates or availability, refer ONLY to the database information provided.
FORMATTING RULES (use Markdown):
- Use short paragraphs separated by blank lines.
- Use clear headings (## or ###) when helpful.
- Use bullet lists for points, character lists, and steps.
- Add a blank line before and after lists and headings.
- Keep lines concise; avoid giant unbroken blocks of text.
- Wrap inline code/terms with backticks only when appropriate.
`;
} else {
const movie = context as MovieContext;
const currentDate = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
@ -164,6 +173,13 @@ CRITICAL INSTRUCTIONS:
5. If asked about release dates or availability, refer ONLY to the database information provided.
6. You can discuss themes, production, performances, and high-level plot setup without revealing twists, surprises, or outcomes.
FORMATTING RULES (use Markdown):
- Use short paragraphs separated by blank lines.
- Use clear headings (## or ###) when helpful.
- Use bullet lists for points and steps.
- Add a blank line before and after lists and headings.
- Keep lines concise; avoid giant unbroken blocks of text.
Answer questions about this movie using only the verified database information above, including plot analysis, character development, themes, cinematography, production notes, and trivia. Provide detailed, informative responses while remaining spoiler-safe.`;
}
}