CP, calender changes

This commit is contained in:
tapframe 2025-07-07 18:41:13 +05:30
parent 93e80d9720
commit fe8489fa18
4 changed files with 192 additions and 31 deletions

View file

@ -14,6 +14,7 @@ import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { MaterialIcons } from '@expo/vector-icons';
import { useTheme } from '../../contexts/ThemeContext';
import { useTraktContext } from '../../contexts/TraktContext';
import { stremioService } from '../../services/stremioService';
import { tmdbService } from '../../services/tmdbService';
import { useLibrary } from '../../hooks/useLibrary';
@ -44,23 +45,75 @@ interface ThisWeekEpisode {
export const ThisWeekSection = React.memo(() => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
const { libraryItems, loading: libraryLoading } = useLibrary();
const {
isAuthenticated: traktAuthenticated,
isLoading: traktLoading,
watchedShows,
watchlistShows,
continueWatching,
loadAllCollections
} = useTraktContext();
const [episodes, setEpisodes] = useState<ThisWeekEpisode[]>([]);
const [loading, setLoading] = useState(true);
const { currentTheme } = useTheme();
const fetchThisWeekEpisodes = useCallback(async () => {
if (libraryItems.length === 0) {
setLoading(false);
return;
}
setLoading(true);
try {
const seriesItems = libraryItems.filter(item => item.type === 'series');
// Combine library series with Trakt series
const librarySeries = libraryItems.filter(item => item.type === 'series');
let allSeries = [...librarySeries];
// Add Trakt watchlist and continue watching shows if authenticated
if (traktAuthenticated) {
const traktSeriesIds = new Set();
// Add watchlist shows
if (watchlistShows) {
for (const item of watchlistShows) {
if (item.show && item.show.ids.imdb) {
const imdbId = item.show.ids.imdb;
if (!librarySeries.some(s => s.id === imdbId)) {
traktSeriesIds.add(imdbId);
allSeries.push({
id: imdbId,
name: item.show.title,
type: 'series',
poster: '', // Will try to fetch from TMDB
year: item.show.year,
traktSource: 'watchlist'
});
}
}
}
}
// Add continue watching shows
if (continueWatching) {
for (const item of continueWatching) {
if (item.type === 'episode' && item.show && item.show.ids.imdb) {
const imdbId = item.show.ids.imdb;
if (!librarySeries.some(s => s.id === imdbId) && !traktSeriesIds.has(imdbId)) {
traktSeriesIds.add(imdbId);
allSeries.push({
id: imdbId,
name: item.show.title,
type: 'series',
poster: '', // Will try to fetch from TMDB
year: item.show.year,
traktSource: 'continue-watching'
});
}
}
}
}
}
console.log(`[ThisWeekSection] Checking ${allSeries.length} series (Library: ${librarySeries.length}, Trakt: ${allSeries.length - librarySeries.length})`);
let allEpisodes: ThisWeekEpisode[] = [];
for (const series of seriesItems) {
for (const series of allSeries) {
try {
const metadata = await stremioService.getMetaDetails(series.type, series.id);
@ -125,15 +178,23 @@ export const ThisWeekSection = React.memo(() => {
} finally {
setLoading(false);
}
}, [libraryItems]);
}, [libraryItems, traktAuthenticated, watchlistShows, continueWatching]);
// Load episodes when library items change
// Load episodes when library items or Trakt data changes
useEffect(() => {
if (!libraryLoading) {
console.log('[ThisWeekSection] Library items changed, refreshing episodes. Items count:', libraryItems.length);
if (!libraryLoading && !traktLoading) {
if (traktAuthenticated && (!watchlistShows || !continueWatching)) {
console.log('[ThisWeekSection] Loading Trakt collections for this week data');
loadAllCollections();
} else {
console.log('[ThisWeekSection] Data ready, refreshing episodes. Library items:', libraryItems.length);
fetchThisWeekEpisodes();
}
} else if (!libraryLoading && !traktAuthenticated) {
console.log('[ThisWeekSection] Not authenticated with Trakt, using library only. Items count:', libraryItems.length);
fetchThisWeekEpisodes();
}
}, [libraryLoading, libraryItems, fetchThisWeekEpisodes]);
}, [libraryLoading, traktLoading, traktAuthenticated, libraryItems, watchlistShows, continueWatching, fetchThisWeekEpisodes, loadAllCollections]);
const handleEpisodePress = (episode: ThisWeekEpisode) => {
// For upcoming episodes, go to the metadata screen

View file

@ -22,6 +22,7 @@ import { useTheme } from '../contexts/ThemeContext';
import { RootStackParamList } from '../navigation/AppNavigator';
import { stremioService } from '../services/stremioService';
import { useLibrary } from '../hooks/useLibrary';
import { useTraktContext } from '../contexts/TraktContext';
import { format, parseISO, isThisWeek, isAfter, startOfToday, addWeeks, isBefore, isSameDay } from 'date-fns';
import Animated, { FadeIn } from 'react-native-reanimated';
import { CalendarSection } from '../components/calendar/CalendarSection';
@ -55,6 +56,15 @@ const CalendarScreen = () => {
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
const { libraryItems, loading: libraryLoading } = useLibrary();
const { currentTheme } = useTheme();
const {
isAuthenticated: traktAuthenticated,
isLoading: traktLoading,
watchedShows,
watchlistShows,
continueWatching,
loadAllCollections
} = useTraktContext();
logger.log(`[Calendar] Initial load - Library has ${libraryItems?.length || 0} items, loading: ${libraryLoading}`);
const [calendarData, setCalendarData] = useState<CalendarSection[]>([]);
const [loading, setLoading] = useState(true);
@ -67,15 +77,83 @@ const CalendarScreen = () => {
setLoading(true);
try {
// Filter for only series in library
const seriesItems = libraryItems.filter(item => item.type === 'series');
logger.log(`[Calendar] Library items: ${libraryItems.length}, Series items: ${seriesItems.length}`);
// Combine library series with Trakt series
const librarySeries = libraryItems.filter(item => item.type === 'series');
let allSeries = [...librarySeries];
// Add Trakt watchlist and watched shows if authenticated
if (traktAuthenticated) {
const traktSeriesIds = new Set();
// Add watchlist shows
if (watchlistShows) {
for (const item of watchlistShows) {
if (item.show && item.show.ids.imdb) {
const imdbId = item.show.ids.imdb;
if (!librarySeries.some(s => s.id === imdbId)) {
traktSeriesIds.add(imdbId);
allSeries.push({
id: imdbId,
name: item.show.title,
type: 'series',
poster: '', // Will try to fetch from TMDB
year: item.show.year,
traktSource: 'watchlist'
});
}
}
}
}
// Add continue watching shows
if (continueWatching) {
for (const item of continueWatching) {
if (item.type === 'episode' && item.show && item.show.ids.imdb) {
const imdbId = item.show.ids.imdb;
if (!librarySeries.some(s => s.id === imdbId) && !traktSeriesIds.has(imdbId)) {
traktSeriesIds.add(imdbId);
allSeries.push({
id: imdbId,
name: item.show.title,
type: 'series',
poster: '', // Will try to fetch from TMDB
year: item.show.year,
traktSource: 'continue-watching'
});
}
}
}
}
// Add watched shows (only recent ones to avoid too much data)
if (watchedShows) {
const recentWatched = watchedShows.slice(0, 20); // Limit to recent 20
for (const item of recentWatched) {
if (item.show && item.show.ids.imdb) {
const imdbId = item.show.ids.imdb;
if (!librarySeries.some(s => s.id === imdbId) && !traktSeriesIds.has(imdbId)) {
traktSeriesIds.add(imdbId);
allSeries.push({
id: imdbId,
name: item.show.title,
type: 'series',
poster: '', // Will try to fetch from TMDB
year: item.show.year,
traktSource: 'watched'
});
}
}
}
}
}
logger.log(`[Calendar] Total series to check: ${allSeries.length} (Library: ${librarySeries.length}, Trakt: ${allSeries.length - librarySeries.length})`);
let allEpisodes: CalendarEpisode[] = [];
let seriesWithoutEpisodes: CalendarEpisode[] = [];
// For each series, fetch upcoming episodes
for (const series of seriesItems) {
for (const series of allSeries) {
try {
logger.log(`[Calendar] Fetching episodes for series: ${series.name} (${series.id})`);
const metadata = await stremioService.getMetaDetails(series.type, series.id);
@ -215,17 +293,22 @@ const CalendarScreen = () => {
setLoading(false);
setRefreshing(false);
}
}, [libraryItems]);
}, [libraryItems, traktAuthenticated, watchlistShows, continueWatching, watchedShows]);
useEffect(() => {
if (libraryItems.length > 0 && !libraryLoading) {
logger.log(`[Calendar] Library loaded with ${libraryItems.length} items, fetching calendar data`);
if (!libraryLoading && !traktLoading) {
if (traktAuthenticated && (!watchlistShows || !continueWatching || !watchedShows)) {
logger.log(`[Calendar] Loading Trakt collections for calendar data`);
loadAllCollections();
} else {
logger.log(`[Calendar] Data ready, fetching calendar data - Library: ${libraryItems.length} items`);
fetchCalendarData();
}
} else if (!libraryLoading && !traktAuthenticated) {
logger.log(`[Calendar] Not authenticated with Trakt, using library only (${libraryItems.length} items)`);
fetchCalendarData();
} else if (!libraryLoading) {
logger.log(`[Calendar] Library loaded but empty (${libraryItems.length} items)`);
setLoading(false);
}
}, [libraryItems, libraryLoading, fetchCalendarData]);
}, [libraryItems, libraryLoading, traktLoading, traktAuthenticated, watchlistShows, continueWatching, watchedShows, fetchCalendarData, loadAllCollections]);
const onRefresh = useCallback(() => {
setRefreshing(true);

View file

@ -913,7 +913,20 @@ const LibraryScreen = () => {
<View style={styles.headerSpacer} />
</>
) : (
<Text style={[styles.headerTitle, { color: currentTheme.colors.white }]}>Library</Text>
<>
<Text style={[styles.headerTitle, { color: currentTheme.colors.white }]}>Library</Text>
<TouchableOpacity
style={[styles.calendarButton, { backgroundColor: currentTheme.colors.primary }]}
onPress={() => navigation.navigate('Calendar')}
activeOpacity={0.7}
>
<MaterialIcons
name="event"
size={24}
color={currentTheme.colors.white}
/>
</TouchableOpacity>
</>
)}
</View>
</View>
@ -1224,6 +1237,17 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
paddingHorizontal: 16,
},
calendarButton: {
width: 44,
height: 44,
borderRadius: 22,
justifyContent: 'center',
alignItems: 'center',
elevation: 3,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
},
});
export default LibraryScreen;

View file

@ -401,13 +401,6 @@ const SettingsScreen: React.FC = () => {
renderControl={ChevronRight}
onPress={() => navigation.navigate('PlayerSettings')}
/>
<SettingItem
title="Calendar"
description="Episode tracking"
icon="event"
renderControl={ChevronRight}
onPress={() => navigation.navigate('Calendar')}
/>
<SettingItem
title="Notifications"
description="Episode reminders"