import React, { useCallback, useEffect, useState } from 'react'; import { I18nManager, Linking, ScrollView, StyleSheet, TextInput, View, Pressable, AppState } from 'react-native'; import { Button as ButtonRNElements } from '@rneui/themed'; import { getDefaultUri, getPushToken, getSavedUri, getStoredNotifications, saveUri, isNotificationsEnabled, setLevels, tryToObtainPermissions, cleanUserOptOutFlag, isGroundControlUriValid, checkPermissions, checkNotificationPermissionStatus, NOTIFICATIONS_NO_AND_DONT_ASK_FLAG, } from '../../blue_modules/notifications'; import { BlueCard, BlueSpacing20, BlueSpacing40, BlueText } from '../../BlueComponents'; import presentAlert from '../../components/Alert'; import { Button } from '../../components/Button'; import CopyToClipboardButton from '../../components/CopyToClipboardButton'; import ListItem, { PressableWrapper } from '../../components/ListItem'; import { useTheme } from '../../components/themes'; import loc from '../../loc'; import { Divider } from '@rneui/base'; import { openSettings } from 'react-native-permissions'; import AsyncStorage from '@react-native-async-storage/async-storage'; const NotificationSettings: React.FC = () => { const [isLoading, setIsLoading] = useState(true); const [isNotificationsEnabledState, setNotificationsEnabledState] = useState(undefined); const [tokenInfo, setTokenInfo] = useState(''); const [URI, setURI] = useState(); const [tapCount, setTapCount] = useState(0); const { colors } = useTheme(); const stylesWithThemeHook = { root: { backgroundColor: colors.background, }, scroll: { backgroundColor: colors.background, }, scrollBody: { backgroundColor: colors.background, }, uri: { borderColor: colors.formBorder, borderBottomColor: colors.formBorder, backgroundColor: colors.inputBackgroundColor, }, }; const handleTap = () => { setTapCount(prevCount => prevCount + 1); }; const showNotificationPermissionAlert = () => { presentAlert({ title: loc.settings.notifications, message: loc.notifications.permission_denied_message, buttons: [ { text: loc._.ok, style: 'cancel', }, { text: loc.settings.header, onPress: onSystemSettings, style: 'default', }, ], }); }; const onNotificationsSwitch = async (value: boolean) => { if (value) { const currentStatus = await checkNotificationPermissionStatus(); if (currentStatus === 'blocked') { // If permissions are denied/blocked, show alert and reset the toggle showNotificationPermissionAlert(); setNotificationsEnabledState(false); return; } } try { setNotificationsEnabledState(value); if (value) { await cleanUserOptOutFlag(); const permissionsGranted = await tryToObtainPermissions(); if (permissionsGranted) { await setLevels(true); await AsyncStorage.removeItem(NOTIFICATIONS_NO_AND_DONT_ASK_FLAG); } else { showNotificationPermissionAlert(); setNotificationsEnabledState(false); } } else { await setLevels(false); await AsyncStorage.setItem(NOTIFICATIONS_NO_AND_DONT_ASK_FLAG, 'true'); setNotificationsEnabledState(false); } setNotificationsEnabledState(await isNotificationsEnabled()); } catch (error) { console.error(error); presentAlert({ message: (error as Error).message }); setNotificationsEnabledState(false); } }; const updateNotificationStatus = async () => { try { const currentStatus = await checkNotificationPermissionStatus(); const isEnabled = await isNotificationsEnabled(); const isDisabledByUser = (await AsyncStorage.getItem(NOTIFICATIONS_NO_AND_DONT_ASK_FLAG)) === 'true'; if (!isDisabledByUser) { setNotificationsEnabledState(currentStatus === 'granted' && isEnabled); } else { setNotificationsEnabledState(false); } } catch (error) { console.log('Error updating notification status:', error); } }; useEffect(() => { (async () => { try { const isDisabledByUser = (await AsyncStorage.getItem(NOTIFICATIONS_NO_AND_DONT_ASK_FLAG)) === 'true'; if (isDisabledByUser) { console.debug('Notifications were disabled by the user. Skipping auto-activation.'); setNotificationsEnabledState(false); } else { await updateNotificationStatus(); } setURI((await getSavedUri()) ?? getDefaultUri()); setTokenInfo( 'token: ' + JSON.stringify(await getPushToken()) + ' permissions: ' + JSON.stringify(await checkPermissions()) + ' stored notifications: ' + JSON.stringify(await getStoredNotifications()), ); } catch (e) { console.error(e); presentAlert({ message: (e as Error).message }); } finally { setIsLoading(false); } })(); const appStateListener = AppState.addEventListener('change', nextAppState => { if (nextAppState === 'active') { setTimeout(async () => { const isDisabledByUser = (await AsyncStorage.getItem(NOTIFICATIONS_NO_AND_DONT_ASK_FLAG)) === 'true'; if (!isDisabledByUser) { updateNotificationStatus(); } }, 300); } }); return () => { appStateListener.remove(); }; }, []); const save = useCallback(async () => { setIsLoading(true); try { if (URI) { if (await isGroundControlUriValid(URI)) { await saveUri(URI); presentAlert({ message: loc.settings.saved }); } else { presentAlert({ message: loc.settings.not_a_valid_uri }); } } else { await saveUri(''); presentAlert({ message: loc.settings.saved }); } } catch (error) { console.error('Error saving URI:', error); } setIsLoading(false); }, [URI]); const onSystemSettings = () => { openSettings('notifications'); }; return ( {loc.settings.push_notifications_explanation} {tapCount >= 10 && ( <> {loc.settings.groundcontrol_explanation} Linking.openURL('https://github.com/BlueWallet/GroundControl')} titleStyle={{ color: colors.buttonAlternativeTextColor }} title="github.com/BlueWallet/GroundControl" color={colors.buttonTextColor} buttonStyle={styles.buttonStyle} /> setTapCount(tapCount + 1)}> ♪ Ground Control to Major Tom ♪ setTapCount(tapCount + 1)}> ♪ Commencing countdown, engines on ♪