diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle
index 3afe430..d4f22b6 100644
--- a/android/app/capacitor.build.gradle
+++ b/android/app/capacitor.build.gradle
@@ -11,7 +11,9 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-browser')
implementation project(':capacitor-filesystem')
+ implementation project(':capacitor-local-notifications')
implementation project(':evva-capacitor-secure-storage-plugin')
+ implementation project(':transistorsoft-capacitor-background-fetch')
implementation "androidx.webkit:webkit:1.4.0"
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 9da5091..2b2013c 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -8,7 +8,8 @@
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme"
- android:requestLegacyExternalStorage="true">
+ android:requestLegacyExternalStorage="true"
+ android:usesCleartextTraffic="true">
+
diff --git a/android/app/src/main/java/com/example/app/BackgroundFetchHeadlessTask.java b/android/app/src/main/java/com/example/app/BackgroundFetchHeadlessTask.java
new file mode 100644
index 0000000..fac2dc1
--- /dev/null
+++ b/android/app/src/main/java/com/example/app/BackgroundFetchHeadlessTask.java
@@ -0,0 +1,31 @@
+package com.example.app;
+
+
+import android.content.Context;
+import android.util.Log;
+
+import com.transistorsoft.tsbackgroundfetch.BackgroundFetch;
+import com.transistorsoft.tsbackgroundfetch.BGTask;
+
+public class BackgroundFetchHeadlessTask{
+ public void onFetch(Context context, BGTask task) {
+ // Get a reference to the BackgroundFetch Android API.
+ BackgroundFetch backgroundFetch = BackgroundFetch.getInstance(context);
+ // Get the taskId.
+ String taskId = task.getTaskId();
+ // Log a message to adb logcat.
+ Log.d("MyHeadlessTask", "BackgroundFetchHeadlessTask onFetch -- CUSTOM IMPLEMENTATION: " + taskId);
+
+ boolean isTimeout = task.getTimedOut();
+ // Is this a timeout?
+ if (isTimeout) {
+ backgroundFetch.finish(taskId);
+ return;
+ }
+ // Do your work here...
+ //
+ //
+ // Signal finish just like the Javascript API.
+ backgroundFetch.finish(taskId);
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/res/drawable/qort.png b/android/app/src/main/res/drawable/qort.png
new file mode 100644
index 0000000..39d090f
Binary files /dev/null and b/android/app/src/main/res/drawable/qort.png differ
diff --git a/android/build.gradle b/android/build.gradle
index 85a5dda..7e1c3f3 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -21,6 +21,10 @@ allprojects {
repositories {
google()
mavenCentral()
+ maven {
+ // capacitor-background-fetch
+ url("${project(':transistorsoft-capacitor-background-fetch').projectDir}/libs")
+ }
}
}
diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle
index 6835b8c..c72458d 100644
--- a/android/capacitor.settings.gradle
+++ b/android/capacitor.settings.gradle
@@ -8,5 +8,11 @@ project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/
include ':capacitor-filesystem'
project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
+include ':capacitor-local-notifications'
+project(':capacitor-local-notifications').projectDir = new File('../node_modules/@capacitor/local-notifications/android')
+
include ':evva-capacitor-secure-storage-plugin'
project(':evva-capacitor-secure-storage-plugin').projectDir = new File('../node_modules/@evva/capacitor-secure-storage-plugin/android')
+
+include ':transistorsoft-capacitor-background-fetch'
+project(':transistorsoft-capacitor-background-fetch').projectDir = new File('../node_modules/@transistorsoft/capacitor-background-fetch/android')
diff --git a/capacitor.config.ts b/capacitor.config.ts
index c52b4e7..d64b8cd 100644
--- a/capacitor.config.ts
+++ b/capacitor.config.ts
@@ -3,7 +3,13 @@ import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'Qortal ',
- webDir: 'dist'
+ webDir: 'dist',
+ "plugins": {
+ "LocalNotifications": {
+ "smallIcon": "qort",
+ "iconColor": "#09b6e8"
+ }
+ }
};
export default config;
diff --git a/package-lock.json b/package-lock.json
index 720f615..5258f9f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@capacitor/cli": "^6.1.2",
"@capacitor/core": "^6.1.2",
"@capacitor/filesystem": "^6.0.1",
+ "@capacitor/local-notifications": "^6.1.0",
"@chatscope/chat-ui-kit-react": "^2.0.3",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
@@ -35,6 +36,7 @@
"@tiptap/pm": "^2.5.9",
"@tiptap/react": "^2.5.9",
"@tiptap/starter-kit": "^2.5.9",
+ "@transistorsoft/capacitor-background-fetch": "^6.0.1",
"@types/chrome": "^0.0.263",
"asmcrypto.js": "2.3.2",
"bcryptjs": "2.4.3",
@@ -515,6 +517,14 @@
"@capacitor/core": "^6.0.0"
}
},
+ "node_modules/@capacitor/local-notifications": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@capacitor/local-notifications/-/local-notifications-6.1.0.tgz",
+ "integrity": "sha512-EjEnbApdFiZYeJgxKIDtgFRNSmeHySnyAeyoTn6HUTYMkTOaHFGAd7NU964k7gbX4al/CBp0cMA8iMG0c7kh1w==",
+ "peerDependencies": {
+ "@capacitor/core": "^6.0.0"
+ }
+ },
"node_modules/@chatscope/chat-ui-kit-react": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@chatscope/chat-ui-kit-react/-/chat-ui-kit-react-2.0.3.tgz",
@@ -3041,6 +3051,14 @@
"url": "https://github.com/sponsors/ueberdosis"
}
},
+ "node_modules/@transistorsoft/capacitor-background-fetch": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@transistorsoft/capacitor-background-fetch/-/capacitor-background-fetch-6.0.1.tgz",
+ "integrity": "sha512-/OyQ4IVu1clWsqt0eKYAX8Ynj1X1Asw5HM94HyH1il3jL5lXe6CLmRFqicXDxabYge+ACXfVLim/P2EovQ1IIg==",
+ "peerDependencies": {
+ "@capacitor/core": "^6.0.0"
+ }
+ },
"node_modules/@types/aria-query": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
diff --git a/package.json b/package.json
index e8da587..cf6d2c6 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"@capacitor/cli": "^6.1.2",
"@capacitor/core": "^6.1.2",
"@capacitor/filesystem": "^6.0.1",
+ "@capacitor/local-notifications": "^6.1.0",
"@chatscope/chat-ui-kit-react": "^2.0.3",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
@@ -39,6 +40,7 @@
"@tiptap/pm": "^2.5.9",
"@tiptap/react": "^2.5.9",
"@tiptap/starter-kit": "^2.5.9",
+ "@transistorsoft/capacitor-background-fetch": "^6.0.1",
"@types/chrome": "^0.0.263",
"asmcrypto.js": "2.3.2",
"bcryptjs": "2.4.3",
diff --git a/src/App.tsx b/src/App.tsx
index 3d87362..6142e9d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -695,20 +695,18 @@ function App() {
executeEvent("openDirectMessage", {
from: message.payload.from,
});
- } else if (message.action === "NOTIFICATION_OPEN_GROUP" && isMainWindow) {
+ } else if (message.action === "NOTIFICATION_OPEN_GROUP") {
executeEvent("openGroupMessage", {
from: message.payload.from,
});
} else if (
- message.action === "NOTIFICATION_OPEN_ANNOUNCEMENT_GROUP" &&
- isMainWindow
+ message.action === "NOTIFICATION_OPEN_ANNOUNCEMENT_GROUP"
) {
executeEvent("openGroupAnnouncement", {
from: message.payload.from,
});
} else if (
- message.action === "NOTIFICATION_OPEN_THREAD_NEW_POST" &&
- isMainWindow
+ message.action === "NOTIFICATION_OPEN_THREAD_NEW_POST"
) {
executeEvent("openThreadNewPost", {
data: message.payload.data,
diff --git a/src/background.ts b/src/background.ts
index f45e376..2c08196 100644
--- a/src/background.ts
+++ b/src/background.ts
@@ -1,5 +1,5 @@
// @ts-nocheck
-// TODO
+
import "./qortalRequests";
import { isArray } from "lodash";
import {
@@ -88,6 +88,16 @@ import {
versionCase,
} from "./background-cases";
import { getData, removeKeysAndLogout, storeData } from "./utils/chromeStorage";
+import {BackgroundFetch} from '@transistorsoft/capacitor-background-fetch';
+import { LocalNotifications } from '@capacitor/local-notifications';
+
+
+LocalNotifications.requestPermissions().then(permission => {
+ if (permission.display === 'granted') {
+ console.log("Notifications enabled");
+ }
+});
+
export function cleanUrl(url) {
return url?.replace(/^(https?:\/\/)?(www\.)?/, "");
@@ -384,35 +394,21 @@ const handleNotificationDirect = async (directs) => {
(newestLatestTimestamp &&
newestLatestTimestamp?.timestamp > oldestLatestTimestamp?.timestamp)
) {
- // const notificationId =
- // "chat_notification_" +
- // Date.now() +
- // "_type=direct" +
- // `_from=${newestLatestTimestamp.address}`;
- // chrome.notifications.create(notificationId, {
- // type: "basic",
- // iconUrl: "qort.png", // Add an appropriate icon for chat notifications
- // title: `New Direct message! ${
- // newestLatestTimestamp?.name && `from ${newestLatestTimestamp.name}`
- // }`,
- // message: "You have received a new direct message",
- // priority: 2, // Use the maximum priority to ensure it's noticeable
- // });
- // if (!isMobile) {
- // setTimeout(() => {
- // chrome.notifications.clear(notificationId);
- // }, 7000);
- // }
+
- // chrome.runtime.sendMessage(
- // {
- // action: "notification",
- // payload: {
- // },
- // }
- // )
- // audio.play();
- playNotificationSound();
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: `New Direct message! ${
+ newestLatestTimestamp?.name && `from ${newestLatestTimestamp.name}`
+ }`,
+ body: "You have received a new direct message",
+ id: notificationId,
+ schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
+ }
+ ]
+ });
+
}
} catch (error) {
if (!isFocused) {
@@ -431,32 +427,21 @@ const handleNotificationDirect = async (directs) => {
});
const notificationId = "chat_notification_" + Date.now();
- // chrome.notifications.create(notificationId, {
- // type: "basic",
- // iconUrl: "qort.png", // Add an appropriate icon for chat notifications
- // title: `New Direct message!`,
- // message: "You have received a new direct message",
- // priority: 2, // Use the maximum priority to ensure it's noticeable
- // });
- if (!isMobile) {
- setTimeout(() => {
- chrome.notifications.clear(notificationId);
- }, 7000);
- }
- playNotificationSound();
- // audio.play();
- // }
+
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: `New Direct message!`,
+ body: "You have received a new direct message",
+ id: notificationId,
+ schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
+ }
+ ]
+ });
}
} finally {
setChatHeadsDirect(dataDirects);
- // chrome.runtime.sendMessage(
- // {
- // action: "setChatHeads",
- // payload: {
- // data,
- // },
- // }
- // );
+
}
};
async function getThreadActivity(): Promise {
@@ -625,28 +610,21 @@ const handleNotification = async (groups) => {
"_type=group" +
`_from=${newestLatestTimestamp.groupId}`;
- // chrome.notifications.create(notificationId, {
- // type: "basic",
- // iconUrl: "qort.png", // Add an appropriate icon for chat notifications
- // title: "New Group Message!",
- // message: `You have received a new message from ${newestLatestTimestamp?.groupName}`,
- // priority: 2, // Use the maximum priority to ensure it's noticeable
-
- // });
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: "New Group Message!",
+ body: `You have received a new message from ${newestLatestTimestamp?.groupName}`,
+ id: notificationId,
+ schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
+ }
+ ]
+ });
if (!isMobile) {
setTimeout(() => {
chrome.notifications.clear(notificationId);
}, 7000);
}
- // chrome.runtime.sendMessage(
- // {
- // action: "notification",
- // payload: {
- // },
- // }
- // )
- // audio.play();
- playNotificationSound();
lastGroupNotification = Date.now();
}
}
@@ -667,277 +645,31 @@ const handleNotification = async (groups) => {
});
const notificationId = "chat_notification_" + Date.now();
- // chrome.notifications.create(notificationId, {
- // type: "basic",
- // iconUrl: "qort.png", // Add an appropriate icon for chat notifications
- // title: "New Group Message!",
- // message: "You have received a new message from one of your groups",
- // priority: 2, // Use the maximum priority to ensure it's noticeable
-
- // });
- if (!isMobile) {
- setTimeout(() => {
- chrome.notifications.clear(notificationId);
- }, 7000);
- }
- playNotificationSound();
- // audio.play();
+
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: "New Group Message!",
+ body: "You have received a new message from one of your groups",
+ id: notificationId,
+ schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
+ }
+ ]
+ });
+
+
lastGroupNotification = Date.now();
- // }
+
}
} finally {
if (!data || data?.length === 0) return;
setChatHeads(dataWithUpdates);
- // chrome.runtime.sendMessage(
- // {
- // action: "setChatHeads",
- // payload: {
- // data,
- // },
- // }
- // );
+
}
};
-export const checkThreads = async (bringBack) => {
- try {
- let myName = "";
- const userData = await getUserInfo();
- if (userData?.name) {
- myName = userData.name;
- }
- let newAnnouncements = [];
- let dataToBringBack = [];
- const threadActivity = await getThreadActivity();
- if (!threadActivity) return null;
- const selectedThreads = [
- ...threadActivity.createdThreads.slice(0, 2),
- ...threadActivity.mostVisitedThreads.slice(0, 2),
- ...threadActivity.recentThreads.slice(0, 2),
- ];
- if (selectedThreads?.length === 0) return null;
- const tempData = {};
- for (const thread of selectedThreads) {
- try {
- const identifier = `thmsg-${thread?.threadId}`;
- const name = thread?.qortalName;
- const endpoint = await getArbitraryEndpoint();
- const url = await createEndpoint(
- `${endpoint}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=1&includemetadata=false&offset=${0}&reverse=true&prefix=true`
- );
- const response = await fetch(url, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- });
- const responseData = await response.json();
-
- const latestMessage = responseData.filter(
- (pub) => pub?.name !== myName
- )[0];
- // const latestMessage = responseData[0]
-
- if (!latestMessage) {
- continue;
- }
-
- if (
- checkDifference(latestMessage.created) &&
- latestMessage.created > thread?.lastVisited &&
- (!thread?.lastNotified || thread?.lastNotified < thread?.created)
- ) {
- tempData[thread.threadId] = latestMessage.created;
- newAnnouncements.push(thread);
- }
- if (latestMessage.created > thread?.lastVisited) {
- dataToBringBack.push(thread);
- }
- } catch (error) {
- conosle.log({ error });
- }
- }
-
- if (bringBack) {
- return dataToBringBack;
- }
-
- const updateThreadWithLastNotified = {
- ...threadActivity,
- createdThreads: (threadActivity?.createdThreads || [])?.map((item) => {
- if (tempData[item.threadId]) {
- return {
- ...item,
- lastNotified: tempData[item.threadId],
- };
- } else {
- return item;
- }
- }),
- mostVisitedThreads: (threadActivity?.mostVisitedThreads || [])?.map(
- (item) => {
- if (tempData[item.threadId]) {
- return {
- ...item,
- lastNotified: tempData[item.threadId],
- };
- } else {
- return item;
- }
- }
- ),
- recentThreads: (threadActivity?.recentThreads || [])?.map((item) => {
- if (tempData[item.threadId]) {
- return {
- ...item,
- lastNotified: tempData[item.threadId],
- };
- } else {
- return item;
- }
- }),
- };
-
- const wallet = await getSaveWallet();
- const address = wallet.address0;
- storeData(`threadactivity-${address}`, updateThreadWithLastNotified).catch(() => null);
- if (newAnnouncements.length > 0) {
- const notificationId =
- "chat_notification_" +
- Date.now() +
- "_type=thread-post" +
- `_data=${JSON.stringify(newAnnouncements[0])}`;
- let isDisableNotifications =
- (await getUserSettings({ key: "disable-push-notifications" })) || false;
- if (!isDisableNotifications) {
- // chrome.notifications.create(notificationId, {
- // type: "basic",
- // iconUrl: "qort.png", // Add an appropriate icon for chat notifications
- // title: `New thread post!`,
- // message: `New post in ${newAnnouncements[0]?.thread?.threadData?.title}`,
- // priority: 2, // Use the maximum priority to ensure it's noticeable
-
- // });
- // if (!isMobile) {
- // setTimeout(() => {
- // chrome.notifications.clear(notificationId);
- // }, 7000);
- // }
- playNotificationSound();
- }
- }
- const savedtimestampAfter = await getTimestampGroupAnnouncement();
- window.postMessage({
- action: "SET_GROUP_ANNOUNCEMENTS",
- payload: savedtimestampAfter,
- }, "*");
- } catch (error) {
- } finally {
- }
-};
-export const checkNewMessages = async () => {
- try {
- let mutedGroups = (await getUserSettings({ key: "mutedGroups" })) || [];
- if (!isArray(mutedGroups)) mutedGroups = [];
- let myName = "";
- const userData = await getUserInfo();
- if (userData?.name) {
- myName = userData.name;
- }
-
- let newAnnouncements = [];
- const activeData = (await getStoredData("active-groups-directs")) || {
- groups: [],
- directs: [],
- };
- const groups = activeData?.groups;
- if (!groups || groups?.length === 0) return;
- const savedtimestamp = await getTimestampGroupAnnouncement();
-
- await Promise.all(
- groups.map(async (group) => {
- try {
- const identifier = `grp-${group.groupId}-anc-`;
- const endpoint = await getArbitraryEndpoint();
- const url = await createEndpoint(
- `${endpoint}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=1&includemetadata=false&offset=0&reverse=true&prefix=true`
- );
- const response = await requestQueueAnnouncements.enqueue(() => {
- return fetch(url, {
- method: "GET",
- headers: {
- "Content-Type": "application/json",
- },
- });
- });
- const responseData = await response.json();
-
- const latestMessage = responseData.filter(
- (pub) => pub?.name !== myName
- )[0];
- if (!latestMessage) {
- return; // continue to the next group
- }
-
- if (
- checkDifference(latestMessage.created) &&
- (!savedtimestamp[group.groupId] ||
- latestMessage.created >
- savedtimestamp?.[group.groupId]?.notification)
- ) {
- newAnnouncements.push(group);
- await addTimestampGroupAnnouncement({
- groupId: group.groupId,
- timestamp: Date.now(),
- });
- // save new timestamp
- }
- } catch (error) {
- console.error(error); // Handle error if needed
- }
- })
- );
- let isDisableNotifications =
- (await getUserSettings({ key: "disable-push-notifications" })) || false;
-
- if (
- newAnnouncements.length > 0 &&
- !mutedGroups.includes(newAnnouncements[0]?.groupId) &&
- !isDisableNotifications
- ) {
- const notificationId =
- "chat_notification_" +
- Date.now() +
- "_type=group-announcement" +
- `_from=${newAnnouncements[0]?.groupId}`;
-
- // chrome.notifications.create(notificationId, {
- // type: "basic",
- // iconUrl: "qort.png", // Add an appropriate icon for chat notifications
- // title: `New group announcement!`,
- // message: `You have received a new announcement from ${newAnnouncements[0]?.groupName}`,
- // priority: 2, // Use the maximum priority to ensure it's noticeable
-
- // });
- // if (!isMobile) {
- // setTimeout(() => {
- // chrome.notifications.clear(notificationId);
- // }, 7000);
- // }
- playNotificationSound();
- }
- const savedtimestampAfter = await getTimestampGroupAnnouncement();
- window.postMessage({
- action: "SET_GROUP_ANNOUNCEMENTS",
- payload: savedtimestampAfter,
- }, "*");
-
- } catch (error) {
- } finally {
- }
-};
const listenForNewGroupAnnouncements = async () => {
try {
@@ -3146,10 +2878,299 @@ const checkGroupList = async () => {
};
+export const checkNewMessages = async () => {
+ try {
+ let mutedGroups = await getUserSettings({key: 'mutedGroups'}) || []
+ if(!isArray(mutedGroups)) mutedGroups = []
+ let myName = "";
+ const userData = await getUserInfo();
+ if (userData?.name) {
+ myName = userData.name;
+ }
-// Reconnect when service worker wakes up
+ let newAnnouncements = [];
+ const activeData = (await getStoredData("active-groups-directs")) || {
+ groups: [],
+ directs: [],
+ };
+ const groups = activeData?.groups;
+ if (!groups || groups?.length === 0) return;
+ const savedtimestamp = await getTimestampGroupAnnouncement();
+
+ await Promise.all(
+ groups.map(async (group) => {
+ try {
+ const identifier = `grp-${group.groupId}-anc-`;
+ const endpoint = await getArbitraryEndpoint();
+ const url = await createEndpoint(
+ `${endpoint}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=1&includemetadata=false&offset=0&reverse=true&prefix=true`
+ );
+ const response = await requestQueueAnnouncements.enqueue(() => {
+ return fetch(url, {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ });
+ const responseData = await response.json();
+
+ const latestMessage = responseData.filter(
+ (pub) => pub?.name !== myName
+ )[0];
+ if (!latestMessage) {
+ return; // continue to the next group
+ }
+
+ if (
+ checkDifference(latestMessage.created) &&
+ (!savedtimestamp[group.groupId] ||
+ latestMessage.created >
+ savedtimestamp?.[group.groupId]?.notification)
+ ) {
+ newAnnouncements.push(group);
+ await addTimestampGroupAnnouncement({
+ groupId: group.groupId,
+ timestamp: Date.now(),
+ });
+ // save new timestamp
+ }
+ } catch (error) {
+ console.error(error); // Handle error if needed
+ }
+ })
+ );
+ let isDisableNotifications = await getUserSettings({key: 'disable-push-notifications'}) || false
+
+ if (newAnnouncements.length > 0 && !mutedGroups.includes(newAnnouncements[0]?.groupId) && !isDisableNotifications) {
+ const notificationId =
+ "chat_notification_" +
+ Date.now() +
+ "_type=group-announcement" +
+ `_from=${newAnnouncements[0]?.groupId}`;
+
+
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: "New group announcement!",
+ body: `You have received a new announcement from ${newAnnouncements[0]?.groupName}`,
+ id: notificationId,
+ schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
+ }
+ ]
+ });
+ }
+ const savedtimestampAfter = await getTimestampGroupAnnouncement();
+ window.postMessage({
+ action: "SET_GROUP_ANNOUNCEMENTS",
+ payload: savedtimestampAfter,
+ }, "*");
+ } catch (error) {
+ } finally {
+ }
+};
+
+const checkActiveChatsForNotifications = async () => {
+ try {
+
+ checkGroupList();
+
+
+
+ } catch (error) {}
+};
+
+export const checkThreads = async (bringBack) => {
+ try {
+ let myName = "";
+ const userData = await getUserInfo();
+ if (userData?.name) {
+ myName = userData.name;
+ }
+ let newAnnouncements = [];
+ let dataToBringBack = [];
+ const threadActivity = await getThreadActivity();
+ if (!threadActivity) return null;
+
+ const selectedThreads = [
+ ...threadActivity.createdThreads.slice(0, 2),
+ ...threadActivity.mostVisitedThreads.slice(0, 2),
+ ...threadActivity.recentThreads.slice(0, 2),
+ ];
+
+ if (selectedThreads?.length === 0) return null;
+ const tempData = {};
+ for (const thread of selectedThreads) {
+ try {
+ const identifier = `thmsg-${thread?.threadId}`;
+ const name = thread?.qortalName;
+ const endpoint = await getArbitraryEndpoint();
+ const url = await createEndpoint(
+ `${endpoint}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=1&includemetadata=false&offset=${0}&reverse=true&prefix=true`
+ );
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ const responseData = await response.json();
+
+ const latestMessage = responseData.filter(
+ (pub) => pub?.name !== myName
+ )[0];
+ // const latestMessage = responseData[0]
+
+ if (!latestMessage) {
+ continue;
+ }
+
+ if (
+ checkDifference(latestMessage.created) &&
+ latestMessage.created > thread?.lastVisited &&
+ (!thread?.lastNotified || thread?.lastNotified < thread?.created)
+ ) {
+ tempData[thread.threadId] = latestMessage.created;
+ newAnnouncements.push(thread);
+ }
+ if (latestMessage.created > thread?.lastVisited) {
+ dataToBringBack.push(thread);
+ }
+ } catch (error) {
+ conosle.log({ error });
+ }
+ }
+
+ if (bringBack) {
+ return dataToBringBack;
+ }
+
+ const updateThreadWithLastNotified = {
+ ...threadActivity,
+ createdThreads: (threadActivity?.createdThreads || [])?.map((item) => {
+ if (tempData[item.threadId]) {
+ return {
+ ...item,
+ lastNotified: tempData[item.threadId],
+ };
+ } else {
+ return item;
+ }
+ }),
+ mostVisitedThreads: (threadActivity?.mostVisitedThreads || [])?.map(
+ (item) => {
+ if (tempData[item.threadId]) {
+ return {
+ ...item,
+ lastNotified: tempData[item.threadId],
+ };
+ } else {
+ return item;
+ }
+ }
+ ),
+ recentThreads: (threadActivity?.recentThreads || [])?.map((item) => {
+ if (tempData[item.threadId]) {
+ return {
+ ...item,
+ lastNotified: tempData[item.threadId],
+ };
+ } else {
+ return item;
+ }
+ }),
+ };
+
+ const wallet = await getSaveWallet();
+ const address = wallet.address0;
+ const dataString = JSON.stringify(updateThreadWithLastNotified);
+ chrome.storage.local.set({ [`threadactivity-${address}`]: dataString });
+
+ if (newAnnouncements.length > 0) {
+ const notificationId =
+ "chat_notification_" +
+ Date.now() +
+ "_type=thread-post" +
+ `_data=${JSON.stringify(newAnnouncements[0])}`;
+ let isDisableNotifications = await getUserSettings({key: 'disable-push-notifications'}) || false
+ if(!isDisableNotifications){
+
+ LocalNotifications.schedule({
+ notifications: [
+ {
+ title: `New thread post!`,
+ body: `New post in ${newAnnouncements[0]?.thread?.threadData?.title}`,
+ id: notificationId,
+ schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
+ }
+ ]
+ });
+ }
+
+ }
+ const savedtimestampAfter = await getTimestampGroupAnnouncement();
+ window.postMessage({
+ action: "SET_GROUP_ANNOUNCEMENTS",
+ payload: savedtimestampAfter,
+ }, "*");
+ } catch (error) {
+ } finally {
+ }
+};
+
+// Configure Background Fetch
+BackgroundFetch.configure({
+ minimumFetchInterval: 15, // Minimum 15-minute interval
+ enableHeadless: true, // Enable headless mode for Android
+}, async (taskId) => {
+ // This is where your background task logic goes
+ const wallet = await getSaveWallet();
+ const address = wallet.address0;
+ console.log('alarm', address)
+ if (!address) return;
+ checkActiveChatsForNotifications();
+ checkNewMessages();
+ checkThreads();
+
+ await new Promise((res)=> {
+ setTimeout(() => {
+ res()
+ }, 55000);
+ })
+ // Always finish the task when complete
+ BackgroundFetch.finish(taskId);
+}, (taskId) => {
+ // Optional timeout callback
+ BackgroundFetch.finish(taskId);
+});
+LocalNotifications.addListener('localNotificationActionPerformed', async (notification) => {
+ const notificationId = notification.notification.id;
+ // Check the type of notification by parsing notificationId
+ const isDirect = notificationId.includes('_type=direct_');
+ const isGroup = notificationId.includes('_type=group_');
+ const isGroupAnnouncement = notificationId.includes('_type=group-announcement_');
+ const isNewThreadPost = notificationId.includes('_type=thread-post_');
+
+
+ // Handle specific notification types
+ if (isDirect) {
+ const fromValue = notificationId.split('_from=')[1];
+ handleDirectNotification(fromValue);
+ } else if (isGroup) {
+ const fromValue = notificationId.split('_from=')[1];
+ handleGroupNotification(fromValue);
+ } else if (isGroupAnnouncement) {
+ const fromValue = notificationId.split('_from=')[1];
+ handleAnnouncementNotification(fromValue);
+ } else if (isNewThreadPost) {
+ const dataValue = notificationId.split('_data=')[1];
+ const dataParsed = JSON.parse(dataValue);
+ handleThreadPostNotification(dataParsed);
+ }
+});