import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, Switch, TouchableOpacity, Alert, SafeAreaView, StatusBar, Platform, } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; import { useTheme } from '../contexts/ThemeContext'; import { notificationService, NotificationSettings } from '../services/notificationService'; import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'; import { useNavigation } from '@react-navigation/native'; import { logger } from '../utils/logger'; const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0; const NotificationSettingsScreen = () => { const navigation = useNavigation(); const { currentTheme } = useTheme(); const [settings, setSettings] = useState({ enabled: true, newEpisodeNotifications: true, reminderNotifications: true, upcomingShowsNotifications: true, timeBeforeAiring: 24, }); const [loading, setLoading] = useState(true); const [countdown, setCountdown] = useState(null); const [testNotificationId, setTestNotificationId] = useState(null); const [isSyncing, setIsSyncing] = useState(false); const [notificationStats, setNotificationStats] = useState({ total: 0, upcoming: 0, thisWeek: 0 }); // Load settings and stats on mount useEffect(() => { const loadSettings = async () => { try { const savedSettings = await notificationService.getSettings(); setSettings(savedSettings); // Load notification stats const stats = notificationService.getNotificationStats(); setNotificationStats(stats); } catch (error) { logger.error('Error loading notification settings:', error); } finally { setLoading(false); } }; loadSettings(); }, []); // Refresh stats when settings change useEffect(() => { if (!loading) { const stats = notificationService.getNotificationStats(); setNotificationStats(stats); } }, [settings, loading]); // Add countdown effect useEffect(() => { let intervalId: NodeJS.Timeout; if (countdown !== null && countdown > 0) { intervalId = setInterval(() => { setCountdown(prev => prev !== null ? prev - 1 : null); }, 1000); } else if (countdown === 0) { setCountdown(null); setTestNotificationId(null); } return () => { if (intervalId) { clearInterval(intervalId); } }; }, [countdown]); // Update a setting const updateSetting = async (key: keyof NotificationSettings, value: boolean | number) => { try { const updatedSettings = { ...settings, [key]: value, }; // Special case: if enabling notifications, make sure permissions are granted if (key === 'enabled' && value === true) { // Permissions are handled in the service } // Update settings in the service await notificationService.updateSettings({ [key]: value }); // Update local state setSettings(updatedSettings); } catch (error) { logger.error('Error updating notification settings:', error); Alert.alert('Error', 'Failed to update notification settings'); } }; // Set time before airing const setTimeBeforeAiring = (hours: number) => { updateSetting('timeBeforeAiring', hours); }; const resetAllNotifications = async () => { Alert.alert( 'Reset Notifications', 'This will cancel all scheduled notifications. Are you sure?', [ { text: 'Cancel', style: 'cancel', }, { text: 'Reset', style: 'destructive', onPress: async () => { try { await notificationService.cancelAllNotifications(); Alert.alert('Success', 'All notifications have been reset'); } catch (error) { logger.error('Error resetting notifications:', error); Alert.alert('Error', 'Failed to reset notifications'); } }, }, ] ); }; const handleSyncNotifications = async () => { if (isSyncing) return; setIsSyncing(true); try { await notificationService.syncAllNotifications(); // Refresh stats after sync const stats = notificationService.getNotificationStats(); setNotificationStats(stats); Alert.alert( 'Sync Complete', `Successfully synced notifications for your library and Trakt items.\n\nScheduled: ${stats.upcoming} upcoming episodes\nThis week: ${stats.thisWeek} episodes` ); } catch (error) { logger.error('Error syncing notifications:', error); Alert.alert('Error', 'Failed to sync notifications. Please try again.'); } finally { setIsSyncing(false); } }; const handleTestNotification = async () => { try { // Cancel previous test notification if exists if (testNotificationId) { await notificationService.cancelNotification(testNotificationId); } const testNotification = { id: 'test-notification-' + Date.now(), seriesId: 'test-series', seriesName: 'Test Show', episodeTitle: 'Test Episode', season: 1, episode: 1, releaseDate: new Date(Date.now() + 60000).toISOString(), // 1 minute from now notified: false }; const notificationId = await notificationService.scheduleEpisodeNotification(testNotification); if (notificationId) { setTestNotificationId(notificationId); setCountdown(60); // Start 60 second countdown Alert.alert('Success', 'Test notification scheduled for 1 minute from now'); } else { Alert.alert('Error', 'Failed to schedule test notification. Make sure notifications are enabled.'); } } catch (error) { logger.error('Error scheduling test notification:', error); Alert.alert('Error', 'Failed to schedule test notification'); } }; if (loading) { return ( navigation.goBack()} > Notification Settings Loading settings... ); } return ( navigation.goBack()} > Notification Settings General Enable Notifications updateSetting('enabled', value)} trackColor={{ false: currentTheme.colors.border, true: currentTheme.colors.primary + '80' }} thumbColor={settings.enabled ? currentTheme.colors.primary : currentTheme.colors.lightGray} /> {settings.enabled && ( <> Notification Types New Episodes updateSetting('newEpisodeNotifications', value)} trackColor={{ false: currentTheme.colors.border, true: currentTheme.colors.primary + '80' }} thumbColor={settings.newEpisodeNotifications ? currentTheme.colors.primary : currentTheme.colors.lightGray} /> Upcoming Shows updateSetting('upcomingShowsNotifications', value)} trackColor={{ false: currentTheme.colors.border, true: currentTheme.colors.primary + '80' }} thumbColor={settings.upcomingShowsNotifications ? currentTheme.colors.primary : currentTheme.colors.lightGray} /> Reminders updateSetting('reminderNotifications', value)} trackColor={{ false: currentTheme.colors.border, true: currentTheme.colors.primary + '80' }} thumbColor={settings.reminderNotifications ? currentTheme.colors.primary : currentTheme.colors.lightGray} /> Notification Timing When should you be notified before an episode airs? {[1, 6, 12, 24].map((hours) => ( setTimeBeforeAiring(hours)} > {hours === 1 ? '1 hour' : `${hours} hours`} ))} Notification Status Upcoming {notificationStats.upcoming} This Week {notificationStats.thisWeek} Total {notificationStats.total} {isSyncing ? 'Syncing...' : 'Sync Library & Trakt'} Automatically syncs notifications for all shows in your library and Trakt watchlist/collection. Advanced Reset All Notifications {countdown !== null ? `Notification in ${countdown}s...` : 'Test Notification (1min)'} {countdown !== null && ( Notification will appear in {countdown} seconds )} This will cancel all scheduled notifications. You'll need to re-enable them manually. )} ); }; const styles = StyleSheet.create({ container: { flex: 1, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 16, paddingVertical: 12, paddingTop: Platform.OS === 'android' ? ANDROID_STATUSBAR_HEIGHT + 12 : 12, borderBottomWidth: 1, }, backButton: { padding: 8, }, headerTitle: { fontSize: 18, fontWeight: 'bold', }, content: { flex: 1, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, loadingText: { fontSize: 16, }, section: { padding: 16, borderBottomWidth: 1, }, sectionTitle: { fontSize: 16, fontWeight: 'bold', marginBottom: 16, }, settingItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 12, borderBottomWidth: 1, }, settingInfo: { flexDirection: 'row', alignItems: 'center', }, settingText: { fontSize: 16, marginLeft: 12, }, settingDescription: { fontSize: 14, marginBottom: 16, }, timingOptions: { flexDirection: 'row', justifyContent: 'space-between', flexWrap: 'wrap', marginTop: 8, }, timingOption: { paddingVertical: 10, paddingHorizontal: 16, borderRadius: 8, borderWidth: 1, marginBottom: 8, width: '48%', alignItems: 'center', }, timingText: { fontSize: 14, }, resetButton: { flexDirection: 'row', alignItems: 'center', padding: 12, borderRadius: 8, borderWidth: 1, marginBottom: 8, }, resetButtonText: { fontSize: 16, fontWeight: 'bold', marginLeft: 8, }, resetDescription: { fontSize: 12, fontStyle: 'italic', }, countdownContainer: { flexDirection: 'row', alignItems: 'center', marginTop: 8, padding: 8, backgroundColor: 'rgba(0, 0, 0, 0.1)', borderRadius: 4, }, countdownIcon: { marginRight: 8, }, countdownText: { fontSize: 14, }, statsContainer: { flexDirection: 'row', justifyContent: 'space-around', padding: 16, borderRadius: 8, marginBottom: 16, }, statItem: { alignItems: 'center', flex: 1, }, statLabel: { fontSize: 12, marginTop: 4, textAlign: 'center', }, statValue: { fontSize: 18, fontWeight: 'bold', marginTop: 2, }, }); export default NotificationSettingsScreen;