mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-01-18 13:26:33 +01:00
wip
This commit is contained in:
parent
0eb6b4f192
commit
d29dd1567f
@ -160,10 +160,6 @@ function Notifications(props) {
|
||||
});
|
||||
};
|
||||
|
||||
const _sleep = async ms => {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
};
|
||||
|
||||
/**
|
||||
* Submits onchain bitcoin addresses and ln invoice preimage hashes to GroundControl server, so later we could
|
||||
* be notified if they were paid
|
||||
@ -224,11 +220,6 @@ function Notifications(props) {
|
||||
}
|
||||
};
|
||||
|
||||
Notifications.isNotificationsEnabled = async () => {
|
||||
const levels = await getLevels();
|
||||
return !!(await getPushToken()) && !!levels.level_all;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates whether the provided GroundControl URI is valid by pinging it.
|
||||
*
|
||||
@ -289,55 +280,6 @@ function Notifications(props) {
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Queries groundcontrol for token configuration, which contains subscriptions to notification levels
|
||||
*
|
||||
* @returns {Promise<{}|*>}
|
||||
*/
|
||||
const getLevels = async () => {
|
||||
const pushToken = await getPushToken();
|
||||
if (!pushToken || !pushToken.token || !pushToken.os) return;
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await Promise.race([
|
||||
fetch(`${baseURI}/getTokenConfiguration`, {
|
||||
method: 'POST',
|
||||
headers: _getHeaders(),
|
||||
body: JSON.stringify({
|
||||
token: pushToken.token,
|
||||
os: pushToken.os,
|
||||
}),
|
||||
}),
|
||||
_sleep(3000),
|
||||
]);
|
||||
} catch (_) {}
|
||||
|
||||
if (!response) return {};
|
||||
|
||||
return await response.json();
|
||||
};
|
||||
|
||||
Notifications.getStoredNotifications = async () => {
|
||||
let notifications = [];
|
||||
try {
|
||||
const stringified = await AsyncStorage.getItem(NOTIFICATIONS_STORAGE);
|
||||
notifications = JSON.parse(stringified);
|
||||
if (!Array.isArray(notifications)) notifications = [];
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
console.error('Invalid notifications format:', e);
|
||||
notifications = [];
|
||||
await AsyncStorage.setItem(NOTIFICATIONS_STORAGE, '[]');
|
||||
} else {
|
||||
console.error('Error accessing notifications:', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return notifications;
|
||||
};
|
||||
|
||||
Notifications.addNotification = async notification => {
|
||||
let notifications = [];
|
||||
try {
|
||||
@ -379,30 +321,6 @@ function Notifications(props) {
|
||||
}
|
||||
};
|
||||
|
||||
Notifications.clearStoredNotifications = async () => {
|
||||
try {
|
||||
await AsyncStorage.setItem(NOTIFICATIONS_STORAGE, JSON.stringify([]));
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
Notifications.getDeliveredNotifications = () => {
|
||||
return new Promise(resolve => {
|
||||
PushNotification.getDeliveredNotifications(notifications => resolve(notifications));
|
||||
});
|
||||
};
|
||||
|
||||
Notifications.removeDeliveredNotifications = (identifiers = []) => {
|
||||
PushNotification.removeDeliveredNotifications(identifiers);
|
||||
};
|
||||
|
||||
Notifications.setApplicationIconBadgeNumber = function (badges) {
|
||||
PushNotification.setApplicationIconBadgeNumber(badges);
|
||||
};
|
||||
|
||||
Notifications.removeAllDeliveredNotifications = () => {
|
||||
PushNotification.removeAllDeliveredNotifications();
|
||||
};
|
||||
|
||||
// on app launch (load module):
|
||||
(async () => {
|
||||
// first, fetching to see if app uses custom GroundControl server, not the default one
|
||||
@ -420,7 +338,7 @@ function Notifications(props) {
|
||||
}
|
||||
|
||||
// every launch should clear badges:
|
||||
Notifications.setApplicationIconBadgeNumber(0);
|
||||
setApplicationIconBadgeNumber(0);
|
||||
|
||||
if (!(await getPushToken())) return;
|
||||
// if we previously had token that means we already acquired permission from the user and it is safe to call
|
||||
@ -431,6 +349,10 @@ function Notifications(props) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _sleep = async ms => {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
};
|
||||
|
||||
export const isNotificationsCapable = hasGmsSync() || hasHmsSync() || Platform.OS !== 'android';
|
||||
|
||||
export const getPushToken = async () => {
|
||||
@ -445,6 +367,35 @@ export const getPushToken = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Queries groundcontrol for token configuration, which contains subscriptions to notification levels
|
||||
*
|
||||
* @returns {Promise<{}|*>}
|
||||
*/
|
||||
const getLevels = async () => {
|
||||
const pushToken = await getPushToken();
|
||||
if (!pushToken || !pushToken.token || !pushToken.os) return;
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await Promise.race([
|
||||
fetch(`${baseURI}/getTokenConfiguration`, {
|
||||
method: 'POST',
|
||||
headers: _getHeaders(),
|
||||
body: JSON.stringify({
|
||||
token: pushToken.token,
|
||||
os: pushToken.os,
|
||||
}),
|
||||
}),
|
||||
_sleep(3000),
|
||||
]);
|
||||
} catch (_) {}
|
||||
|
||||
if (!response) return {};
|
||||
|
||||
return await response.json();
|
||||
};
|
||||
|
||||
/**
|
||||
* The opposite of `majorTomToGroundControl` call.
|
||||
*
|
||||
@ -491,12 +442,36 @@ export const unsubscribe = async (addresses, hashes, txids) => {
|
||||
}
|
||||
};
|
||||
|
||||
function _getHeaders() {
|
||||
const _getHeaders = () => {
|
||||
return {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const clearStoredNotifications = async () => {
|
||||
try {
|
||||
await AsyncStorage.setItem(NOTIFICATIONS_STORAGE, JSON.stringify([]));
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
export const getDeliveredNotifications = () => {
|
||||
return new Promise(resolve => {
|
||||
PushNotification.getDeliveredNotifications(notifications => resolve(notifications));
|
||||
});
|
||||
};
|
||||
|
||||
export const removeDeliveredNotifications = (identifiers = []) => {
|
||||
PushNotification.removeDeliveredNotifications(identifiers);
|
||||
};
|
||||
|
||||
export const setApplicationIconBadgeNumber = function (badges) {
|
||||
PushNotification.setApplicationIconBadgeNumber(badges);
|
||||
};
|
||||
|
||||
export const removeAllDeliveredNotifications = () => {
|
||||
PushNotification.removeAllDeliveredNotifications();
|
||||
};
|
||||
|
||||
export const getDefaultUri = () => {
|
||||
return groundControlUri;
|
||||
@ -529,4 +504,29 @@ export const getSavedUri = async () => {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const isNotificationsEnabled = async () => {
|
||||
const levels = await getLevels();
|
||||
return !!(await getPushToken()) && !!levels.level_all;
|
||||
};
|
||||
|
||||
export const getStoredNotifications = async () => {
|
||||
let notifications = [];
|
||||
try {
|
||||
const stringified = await AsyncStorage.getItem(NOTIFICATIONS_STORAGE);
|
||||
notifications = JSON.parse(stringified);
|
||||
if (!Array.isArray(notifications)) notifications = [];
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
console.error('Invalid notifications format:', e);
|
||||
notifications = [];
|
||||
await AsyncStorage.setItem(NOTIFICATIONS_STORAGE, '[]');
|
||||
} else {
|
||||
console.error('Error accessing notifications:', e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return notifications;
|
||||
};
|
||||
export default Notifications;
|
||||
|
@ -7,7 +7,13 @@ import A from '../blue_modules/analytics';
|
||||
import { getClipboardContent } from '../blue_modules/clipboard';
|
||||
import { updateExchangeRate } from '../blue_modules/currency';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../blue_modules/hapticFeedback';
|
||||
import Notifications from '../blue_modules/notifications';
|
||||
import Notifications, {
|
||||
clearStoredNotifications,
|
||||
getDeliveredNotifications,
|
||||
getStoredNotifications,
|
||||
removeAllDeliveredNotifications,
|
||||
setApplicationIconBadgeNumber,
|
||||
} from '../blue_modules/notifications';
|
||||
import { LightningCustodianWallet } from '../class';
|
||||
import DeeplinkSchemaMatch from '../class/deeplink-schema-match';
|
||||
import loc from '../loc';
|
||||
@ -43,16 +49,11 @@ const CompanionDelegates = () => {
|
||||
|
||||
const processPushNotifications = useCallback(async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
// @ts-ignore: Notifications type is not defined
|
||||
const notifications2process = await Notifications.getStoredNotifications();
|
||||
// @ts-ignore: Notifications type is not defined
|
||||
await Notifications.clearStoredNotifications();
|
||||
// @ts-ignore: Notifications type is not defined
|
||||
Notifications.setApplicationIconBadgeNumber(0);
|
||||
// @ts-ignore: Notifications type is not defined
|
||||
const deliveredNotifications = await Notifications.getDeliveredNotifications();
|
||||
// @ts-ignore: Notifications type is not defined
|
||||
setTimeout(() => Notifications.removeAllDeliveredNotifications(), 5000);
|
||||
const notifications2process = await getStoredNotifications();
|
||||
await clearStoredNotifications();
|
||||
setApplicationIconBadgeNumber(0);
|
||||
const deliveredNotifications = await getDeliveredNotifications();
|
||||
setTimeout(() => removeAllDeliveredNotifications(), 5000);
|
||||
|
||||
for (const payload of notifications2process) {
|
||||
const wasTapped = payload.foreground === false || (payload.foreground === true && payload.userInteraction);
|
||||
|
@ -2,7 +2,14 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { I18nManager, Linking, ScrollView, StyleSheet, TextInput, View, Pressable } from 'react-native';
|
||||
import { Button as ButtonRNElements } from '@rneui/themed';
|
||||
// @ts-ignore: no declaration file
|
||||
import Notifications, { getDefaultUri, getPushToken, getSavedUri, saveUri } from '../../blue_modules/notifications';
|
||||
import Notifications, {
|
||||
getDefaultUri,
|
||||
getPushToken,
|
||||
getSavedUri,
|
||||
getStoredNotifications,
|
||||
saveUri,
|
||||
isNotificationsEnabled,
|
||||
} from '../../blue_modules/notifications';
|
||||
import { BlueCard, BlueSpacing20, BlueSpacing40, BlueText } from '../../BlueComponents';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import { Button } from '../../components/Button';
|
||||
@ -15,7 +22,7 @@ import { openSettings } from 'react-native-permissions';
|
||||
|
||||
const NotificationSettings: React.FC = () => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isNotificationsEnabled, setNotificationsEnabled] = useState(false);
|
||||
const [isNotificationsEnabledState, setNotificationsEnabledState] = useState(false);
|
||||
const [tokenInfo, setTokenInfo] = useState('<empty>');
|
||||
const [URI, setURI] = useState<string | undefined>();
|
||||
const [tapCount, setTapCount] = useState(0);
|
||||
@ -43,7 +50,7 @@ const NotificationSettings: React.FC = () => {
|
||||
|
||||
const onNotificationsSwitch = async (value: boolean) => {
|
||||
try {
|
||||
setNotificationsEnabled(value);
|
||||
setNotificationsEnabledState(value);
|
||||
if (value) {
|
||||
// User is enabling notifications
|
||||
// @ts-ignore: refactor later
|
||||
@ -63,8 +70,7 @@ const NotificationSettings: React.FC = () => {
|
||||
await Notifications.setLevels(false);
|
||||
}
|
||||
|
||||
// @ts-ignore: refactor later
|
||||
setNotificationsEnabled(await Notifications.isNotificationsEnabled());
|
||||
setNotificationsEnabledState(await isNotificationsEnabled());
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
presentAlert({ message: (error as Error).message });
|
||||
@ -74,20 +80,17 @@ const NotificationSettings: React.FC = () => {
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// @ts-ignore: refactor later
|
||||
setNotificationsEnabled(await Notifications.isNotificationsEnabled());
|
||||
setNotificationsEnabledState(await isNotificationsEnabled());
|
||||
setURI((await getSavedUri()) ?? getDefaultUri());
|
||||
// @ts-ignore: refactor later
|
||||
setTokenInfo(
|
||||
'token: ' +
|
||||
// @ts-ignore: refactor later
|
||||
JSON.stringify(await getPushToken()) +
|
||||
' permissions: ' +
|
||||
// @ts-ignore: refactor later
|
||||
JSON.stringify(await Notifications.checkPermissions()) +
|
||||
' stored notifications: ' +
|
||||
// @ts-ignore: refactor later
|
||||
JSON.stringify(await Notifications.getStoredNotifications()),
|
||||
JSON.stringify(await getStoredNotifications()),
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@ -131,7 +134,7 @@ const NotificationSettings: React.FC = () => {
|
||||
title={loc.settings.notifications}
|
||||
subtitle={loc.notifications.notifications_subtitle}
|
||||
disabled={isLoading}
|
||||
switch={{ onValueChange: onNotificationsSwitch, value: isNotificationsEnabled, testID: 'NotificationsSwitch' }}
|
||||
switch={{ onValueChange: onNotificationsSwitch, value: isNotificationsEnabledState, testID: 'NotificationsSwitch' }}
|
||||
/>
|
||||
|
||||
<Pressable onPress={handleTap}>
|
||||
|
Loading…
Reference in New Issue
Block a user