metasceen update

This commit is contained in:
tapframe 2025-10-26 00:20:38 +05:30
parent c54ea1d591
commit be2435db27
4 changed files with 88 additions and 25 deletions

View file

@ -208,8 +208,8 @@ const TabletStreamsLayout: React.FC<TabletStreamsLayoutProps> = ({
duration: 600,
easing: Easing.out(Easing.cubic)
}));
} else if (!backdropSource?.uri) {
// No backdrop available, animate content panels immediately
} else if (!backdropSource?.uri || backdropError) {
// No backdrop available OR backdrop failed to load - animate content panels immediately
leftPanelOpacity.value = withTiming(1, {
duration: 600,
easing: Easing.out(Easing.cubic)
@ -228,7 +228,7 @@ const TabletStreamsLayout: React.FC<TabletStreamsLayoutProps> = ({
easing: Easing.out(Easing.cubic)
}));
}
}, [backdropSource?.uri, backdropLoaded]);
}, [backdropSource?.uri, backdropLoaded, backdropError]);
// Reset animation when episode changes
useEffect(() => {

View file

@ -275,8 +275,14 @@ const LibraryScreen = () => {
try {
const items = await catalogService.getLibraryItems();
logger.log(`[LibraryScreen] Loaded ${items.length} library items`);
if (items.length === 0) {
logger.warn('[LibraryScreen] Library is empty - this might indicate a loading issue');
}
// Sort by date added (most recent first)
const sortedItems = items.sort((a, b) => {
const sortedItems = [...items].sort((a, b) => {
const timeA = (a as any).addedToLibraryAt || 0;
const timeB = (b as any).addedToLibraryAt || 0;
return timeB - timeA; // Descending order (newest first)
@ -309,8 +315,10 @@ const LibraryScreen = () => {
// Subscribe to library updates
const unsubscribe = catalogService.subscribeToLibraryUpdates(async (items) => {
logger.log(`[LibraryScreen] Library update received with ${items.length} items`);
// Sort by date added (most recent first)
const sortedItems = items.sort((a, b) => {
const sortedItems = [...items].sort((a, b) => {
const timeA = (a as any).addedToLibraryAt || 0;
const timeB = (b as any).addedToLibraryAt || 0;
return timeB - timeA; // Descending order (newest first)
@ -728,7 +736,7 @@ const LibraryScreen = () => {
}
// Sort by last watched/added date (most recent first) using raw timestamps
return items.sort((a, b) => {
return [...items].sort((a, b) => {
const dateA = a.lastWatched ? new Date(a.lastWatched).getTime() : 0;
const dateB = b.lastWatched ? new Date(b.lastWatched).getTime() : 0;
return dateB - dateA;

View file

@ -1632,6 +1632,41 @@ export const StreamsScreen = () => {
// Helper to create gradient colors from dominant color
const createGradientColors = useCallback((baseColor: string | null): [string, string, string, string, string] => {
// Always use black gradient when backdrop is enabled
if (settings.enableStreamsBackdrop) {
return ['rgba(0,0,0,0)', 'rgba(0,0,0,0.3)', 'rgba(0,0,0,0.6)', 'rgba(0,0,0,0.85)', 'rgba(0,0,0,0.95)'];
}
// When backdrop is disabled, use theme background gradient
const themeBg = colors.darkBackground;
// Handle hex color format (e.g., #1a1a1a)
if (themeBg.startsWith('#')) {
const r = parseInt(themeBg.substr(1, 2), 16);
const g = parseInt(themeBg.substr(3, 2), 16);
const b = parseInt(themeBg.substr(5, 2), 16);
return [
`rgba(${r},${g},${b},0)`,
`rgba(${r},${g},${b},0.3)`,
`rgba(${r},${g},${b},0.6)`,
`rgba(${r},${g},${b},0.85)`,
`rgba(${r},${g},${b},0.95)`,
];
}
// Handle rgb color format (e.g., rgb(26, 26, 26))
const rgbMatch = themeBg.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
if (rgbMatch) {
const [, r, g, b] = rgbMatch;
return [
`rgba(${r},${g},${b},0)`,
`rgba(${r},${g},${b},0.3)`,
`rgba(${r},${g},${b},0.6)`,
`rgba(${r},${g},${b},0.85)`,
`rgba(${r},${g},${b},0.95)`,
];
}
if (!baseColor || baseColor === '#1a1a1a') {
// Fallback to black gradient with stronger bottom edge
return ['rgba(0,0,0,0)', 'rgba(0,0,0,0.3)', 'rgba(0,0,0,0.6)', 'rgba(0,0,0,0.85)', 'rgba(0,0,0,0.95)'];
@ -1650,7 +1685,7 @@ export const StreamsScreen = () => {
`rgba(${r},${g},${b},0.85)`,
`rgba(${r},${g},${b},0.95)`,
];
}, []);
}, [settings.enableStreamsBackdrop, colors.darkBackground]);
const gradientColors = useMemo(() =>
createGradientColors(dominantColor),
@ -1805,7 +1840,7 @@ export const StreamsScreen = () => {
<AndroidBlurView
blurAmount={15}
blurRadius={8}
overlayColor={"rgba(0,0,0,0.8)"}
overlayColor={"rgba(0,0,0,0.85)"}
style={StyleSheet.absoluteFill}
/>
) : (
@ -1819,10 +1854,7 @@ export const StreamsScreen = () => {
{Platform.OS === 'ios' && (
<View style={[
StyleSheet.absoluteFill,
{ backgroundColor: dominantColor && dominantColor !== '#1a1a1a'
? `${dominantColor}CC` // Add 80% opacity (CC in hex)
: 'rgba(0,0,0,0.8)'
}
{ backgroundColor: 'rgba(0,0,0,0.8)' }
]} />
)}
</View>
@ -1923,19 +1955,19 @@ export const StreamsScreen = () => {
)}
{/* Gradient overlay to blend hero section with streams container */}
{metadata?.videos && metadata.videos.length > 1 && selectedEpisode && settings.enableStreamsBackdrop && (
{metadata?.videos && metadata.videos.length > 1 && selectedEpisode && (
<View style={styles.heroBlendOverlay}>
<LinearGradient
colors={[
dominantColor && dominantColor !== '#1a1a1a'
? `rgba(${parseInt(dominantColor.substr(1, 2), 16)},${parseInt(dominantColor.substr(3, 2), 16)},${parseInt(dominantColor.substr(5, 2), 16)},0.95)`
: 'rgba(0,0,0,0.95)',
dominantColor && dominantColor !== '#1a1a1a'
? `rgba(${parseInt(dominantColor.substr(1, 2), 16)},${parseInt(dominantColor.substr(3, 2), 16)},${parseInt(dominantColor.substr(5, 2), 16)},0.7)`
: 'rgba(0,0,0,0.7)',
colors={settings.enableStreamsBackdrop ? [
'rgba(0,0,0,0.98)',
'rgba(0,0,0,0.85)',
'transparent'
] : [
colors.darkBackground,
colors.darkBackground,
'transparent'
]}
locations={[0, 0.5, 1]}
locations={[0, 0.4, 1]}
style={StyleSheet.absoluteFill}
/>
</View>
@ -2388,6 +2420,7 @@ const createStyles = (colors: any) => StyleSheet.create({
position: 'relative',
backgroundColor: 'transparent',
pointerEvents: 'box-none',
zIndex: 1,
},
streamsHeroBackground: {
width: '100%',
@ -2728,10 +2761,10 @@ const createStyles = (colors: any) => StyleSheet.create({
},
heroBlendOverlay: {
position: 'absolute',
top: 220, // Height of hero container
top: 140, // Start at ~64% of hero section, giving 80px of blend within hero
left: 0,
right: 0,
height: 60, // Extend gradient 60px into streams area
height: Platform.OS === 'android' ? 150 : 180, // Reduce gradient area on Android
zIndex: 0,
pointerEvents: 'none',
},

View file

@ -157,10 +157,23 @@ class CatalogService {
private libraryRemoveListeners: ((type: string, id: string) => void)[] = [];
private constructor() {
this.initializeScope();
this.loadLibrary();
this.loadRecentContent();
}
private async initializeScope(): Promise<void> {
try {
const currentScope = await AsyncStorage.getItem('@user:current');
if (!currentScope) {
await AsyncStorage.setItem('@user:current', 'local');
logger.log('[CatalogService] Initialized @user:current scope to "local"');
}
} catch (error) {
logger.error('[CatalogService] Failed to initialize scope:', error);
}
}
static getInstance(): CatalogService {
if (!CatalogService.instance) {
CatalogService.instance = new CatalogService();
@ -182,9 +195,16 @@ class CatalogService {
}
if (storedLibrary) {
this.library = JSON.parse(storedLibrary);
logger.log(`[CatalogService] Library loaded successfully with ${Object.keys(this.library).length} items from scope: ${scope}`);
} else {
logger.log(`[CatalogService] No library data found for scope: ${scope}`);
this.library = {};
}
// Ensure @user:current is set to prevent future scope issues
await AsyncStorage.setItem('@user:current', scope);
} catch (error: any) {
logger.error('Failed to load library:', error);
this.library = {};
}
}
@ -192,8 +212,10 @@ class CatalogService {
try {
const scope = (await AsyncStorage.getItem('@user:current')) || 'local';
const scopedKey = `@user:${scope}:stremio-library`;
await AsyncStorage.setItem(scopedKey, JSON.stringify(this.library));
await AsyncStorage.setItem(this.LEGACY_LIBRARY_KEY, JSON.stringify(this.library));
const libraryData = JSON.stringify(this.library);
await AsyncStorage.setItem(scopedKey, libraryData);
await AsyncStorage.setItem(this.LEGACY_LIBRARY_KEY, libraryData);
logger.log(`[CatalogService] Library saved successfully with ${Object.keys(this.library).length} items to scope: ${scope}`);
} catch (error: any) {
logger.error('Failed to save library:', error);
}