import { useState, useCallback, useEffect } from 'react' import { AppState, Linking, View, Text, StyleSheet, Pressable, Switch } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { useRouter, useFocusEffect } from 'expo-router' import { ChevronLeft } from 'lucide-react-native' import { colors, spacing, typography } from '../src/theme/mobile-theme' import { loadPushNotificationsEnabled, savePushNotificationsEnabled } from '../src/storage/preferences' import { ensureNotificationPermissions, getNotificationPermissionState, type NotificationPermissionState } from '../src/notifications/mobile-notifications' const DEFAULT_PERMISSION_STATE: NotificationPermissionState = { granted: false, status: 'undetermined', canAskAgain: true } export default function NotificationsScreen() { const router = useRouter() const insets = useSafeAreaInsets() const [pushEnabled, setPushEnabled] = useState(false) const [permissionState, setPermissionState] = useState(DEFAULT_PERMISSION_STATE) const refreshSettings = useCallback(async () => { const [enabled, permission] = await Promise.all([ loadPushNotificationsEnabled(), getNotificationPermissionState() ]) setPushEnabled(enabled) setPermissionState(permission) }, []) useFocusEffect( useCallback(() => { void refreshSettings() }, [refreshSettings]) ) useEffect(() => { const subscription = AppState.addEventListener('change', (state) => { if (state === 'active') { void refreshSettings() } }) return () => subscription.remove() }, [refreshSettings]) const togglePush = async (value: boolean) => { if (value) { const granted = await ensureNotificationPermissions() const permission = await getNotificationPermissionState() setPermissionState(permission) if (!granted) { setPushEnabled(false) await savePushNotificationsEnabled(false) return } } setPushEnabled(value) await savePushNotificationsEnabled(value) } const switchEnabled = pushEnabled && permissionState.granted const notificationsBlocked = permissionState.status === 'denied' const hint = notificationsBlocked ? 'Notifications are disabled in system settings.' : 'Receive notifications when an agent task completes on your desktop.' return ( router.back()}> Notifications Push Notifications void togglePush(v)} trackColor={{ false: colors.bgRaised, true: colors.textSecondary }} thumbColor={colors.textPrimary} /> {hint} {notificationsBlocked && ( [ styles.settingsButton, pressed && styles.settingsButtonPressed ]} onPress={() => void Linking.openSettings()} > Open Settings )} ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.bgBase, padding: spacing.lg }, topRow: { flexDirection: 'row', alignItems: 'center', marginBottom: spacing.xl }, backButton: { width: 36, height: 36, borderRadius: 18, alignItems: 'center', justifyContent: 'center', marginRight: spacing.sm }, heading: { fontSize: 20, fontWeight: '700', color: colors.textPrimary }, section: { backgroundColor: colors.bgPanel, borderRadius: 12, overflow: 'hidden' }, row: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm + 2, paddingVertical: spacing.md, paddingHorizontal: spacing.md + 2 }, rowLabel: { flex: 1, fontSize: typography.bodySize, fontWeight: '500', color: colors.textPrimary }, hint: { fontSize: typography.metaSize, color: colors.textMuted, lineHeight: 18, paddingHorizontal: spacing.md + 2, paddingBottom: spacing.md }, settingsButton: { alignSelf: 'flex-start', marginHorizontal: spacing.md + 2, marginBottom: spacing.md, paddingVertical: spacing.xs, paddingHorizontal: spacing.sm, borderRadius: 8, backgroundColor: colors.bgRaised }, settingsButtonPressed: { opacity: 0.6 }, settingsButtonText: { color: colors.textPrimary, fontSize: typography.metaSize, fontWeight: '600' } })