Refactor useMetadataAnimations for Android compatibility and optimize animation values

This update modifies the entrance animations in the useMetadataAnimations hook to start with visible values for better compatibility on Android devices. The opacity and scale values for various animations have been adjusted to enhance performance and visual consistency. Additionally, the progress animation logic has been simplified for improved efficiency.
This commit is contained in:
tapframe 2025-06-18 18:21:04 +05:30
parent 3f2e6b08fc
commit 7ae46313a5
4 changed files with 34 additions and 50 deletions

View file

@ -32,18 +32,18 @@ const easings = {
};
export const useMetadataAnimations = (safeAreaTop: number, watchProgress: any) => {
// Consolidated entrance animations - fewer shared values
const screenOpacity = useSharedValue(0);
const contentOpacity = useSharedValue(0);
// Consolidated entrance animations - start with visible values for Android compatibility
const screenOpacity = useSharedValue(1);
const contentOpacity = useSharedValue(1);
// Combined hero animations
const heroOpacity = useSharedValue(0);
const heroScale = useSharedValue(0.95); // Combined scale for micro-animation
const heroOpacity = useSharedValue(1);
const heroScale = useSharedValue(1); // Start at 1 for Android compatibility
const heroHeightValue = useSharedValue(height * 0.5);
// Combined UI element animations
const uiElementsOpacity = useSharedValue(0);
const uiElementsTranslateY = useSharedValue(10);
const uiElementsOpacity = useSharedValue(1);
const uiElementsTranslateY = useSharedValue(0);
// Progress animation - simplified to single value
const progressOpacity = useSharedValue(0);
@ -57,10 +57,11 @@ export const useMetadataAnimations = (safeAreaTop: number, watchProgress: any) =
// Ultra-fast entrance sequence - batch animations for better performance
useEffect(() => {
'worklet';
// Batch all entrance animations to run simultaneously
const enterAnimations = () => {
'worklet';
// Start with slightly reduced values and animate to full visibility
screenOpacity.value = withTiming(1, {
duration: 250,
easing: easings.fast
@ -92,14 +93,17 @@ export const useMetadataAnimations = (safeAreaTop: number, watchProgress: any) =
// Optimized watch progress animation
useEffect(() => {
'worklet';
const hasProgress = watchProgress && watchProgress.duration > 0;
progressOpacity.value = withTiming(hasProgress ? 1 : 0, {
duration: hasProgress ? 200 : 150,
easing: easings.fast
});
const updateProgress = () => {
'worklet';
progressOpacity.value = withTiming(hasProgress ? 1 : 0, {
duration: hasProgress ? 200 : 150,
easing: easings.fast
});
};
runOnUI(updateProgress)();
}, [watchProgress]);
// Ultra-optimized scroll handler with minimal calculations

View file

@ -540,7 +540,7 @@ const MDBListSettingsScreen = () => {
const openMDBListWebsite = () => {
logger.log('[MDBListSettingsScreen] Opening MDBList website');
Linking.openURL('https://mdblist.com/settings').catch(error => {
Linking.openURL('https://mdblist.com/preferences').catch(error => {
logger.error('[MDBListSettingsScreen] Error opening website:', error);
});
};

View file

@ -697,19 +697,20 @@ const styles = StyleSheet.create({
borderRadius: 8,
overflow: 'hidden',
height: 36,
width: 160,
width: 180,
marginRight: 8,
},
selectorButton: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 12,
paddingHorizontal: 8,
backgroundColor: 'rgba(255,255,255,0.08)',
},
selectorText: {
fontSize: 14,
fontSize: 13,
fontWeight: '500',
textAlign: 'center',
},
profileLockContainer: {
padding: 16,

View file

@ -679,39 +679,18 @@ export const StreamsScreen = () => {
navigateToPlayer(stream);
});
} else {
// For direct video URLs, use the S.Browser.ACTION_VIEW approach
// This is a more reliable way to force Android to show all video apps
// For direct video URLs, use the VideoPlayerService to show the Android app chooser
const success = await VideoPlayerService.playVideo(stream.url, {
useExternalPlayer: true,
title: metadata?.name || 'Video',
episodeTitle: type === 'series' ? currentEpisode?.name : undefined,
episodeNumber: type === 'series' && currentEpisode ? `S${currentEpisode.season_number}E${currentEpisode.episode_number}` : undefined,
});
// Strip query parameters if they exist as they can cause issues with some apps
let cleanUrl = stream.url;
if (cleanUrl.includes('?')) {
cleanUrl = cleanUrl.split('?')[0];
if (!success) {
console.log('VideoPlayerService failed, falling back to built-in player');
navigateToPlayer(stream);
}
// Create an Android intent URL that forces the chooser
// Set component=null to ensure chooser is shown
// Set action=android.intent.action.VIEW to open the content
const intentUrl = `intent:${cleanUrl}#Intent;action=android.intent.action.VIEW;category=android.intent.category.DEFAULT;component=;type=video/*;launchFlags=0x10000000;end`;
console.log(`Using intent URL: ${intentUrl}`);
Linking.openURL(intentUrl)
.then(() => console.log('Successfully opened with intent URL'))
.catch(err => {
console.error('Failed to open with intent URL:', err);
// First fallback: Try direct URL with regular Linking API
console.log('Trying plain URL as fallback');
Linking.openURL(stream.url)
.then(() => console.log('Opened with direct URL'))
.catch(directErr => {
console.error('Failed to open direct URL:', directErr);
// Final fallback: Use built-in player
console.log('All external player attempts failed, using built-in player');
navigateToPlayer(stream);
});
});
}
} catch (error) {
console.error('Error with external player:', error);