mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-03-28 08:15:55 +00:00
added notifications for mobile
This commit is contained in:
parent
6ed45501f7
commit
77ef45345d
@ -11,7 +11,9 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':capacitor-browser')
|
implementation project(':capacitor-browser')
|
||||||
implementation project(':capacitor-filesystem')
|
implementation project(':capacitor-filesystem')
|
||||||
|
implementation project(':capacitor-local-notifications')
|
||||||
implementation project(':evva-capacitor-secure-storage-plugin')
|
implementation project(':evva-capacitor-secure-storage-plugin')
|
||||||
|
implementation project(':transistorsoft-capacitor-background-fetch')
|
||||||
implementation "androidx.webkit:webkit:1.4.0"
|
implementation "androidx.webkit:webkit:1.4.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:requestLegacyExternalStorage="true">
|
android:requestLegacyExternalStorage="true"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@ -40,4 +41,5 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
BIN
android/app/src/main/res/drawable/qort.png
Normal file
BIN
android/app/src/main/res/drawable/qort.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
@ -21,6 +21,10 @@ allprojects {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
// capacitor-background-fetch
|
||||||
|
url("${project(':transistorsoft-capacitor-background-fetch').projectDir}/libs")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,5 +8,11 @@ project(':capacitor-browser').projectDir = new File('../node_modules/@capacitor/
|
|||||||
include ':capacitor-filesystem'
|
include ':capacitor-filesystem'
|
||||||
project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android')
|
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'
|
include ':evva-capacitor-secure-storage-plugin'
|
||||||
project(':evva-capacitor-secure-storage-plugin').projectDir = new File('../node_modules/@evva/capacitor-secure-storage-plugin/android')
|
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')
|
||||||
|
@ -3,7 +3,13 @@ import type { CapacitorConfig } from '@capacitor/cli';
|
|||||||
const config: CapacitorConfig = {
|
const config: CapacitorConfig = {
|
||||||
appId: 'com.example.app',
|
appId: 'com.example.app',
|
||||||
appName: 'Qortal ',
|
appName: 'Qortal ',
|
||||||
webDir: 'dist'
|
webDir: 'dist',
|
||||||
|
"plugins": {
|
||||||
|
"LocalNotifications": {
|
||||||
|
"smallIcon": "qort",
|
||||||
|
"iconColor": "#09b6e8"
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@capacitor/cli": "^6.1.2",
|
"@capacitor/cli": "^6.1.2",
|
||||||
"@capacitor/core": "^6.1.2",
|
"@capacitor/core": "^6.1.2",
|
||||||
"@capacitor/filesystem": "^6.0.1",
|
"@capacitor/filesystem": "^6.0.1",
|
||||||
|
"@capacitor/local-notifications": "^6.1.0",
|
||||||
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
||||||
"@dnd-kit/core": "^6.1.0",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
@ -35,6 +36,7 @@
|
|||||||
"@tiptap/pm": "^2.5.9",
|
"@tiptap/pm": "^2.5.9",
|
||||||
"@tiptap/react": "^2.5.9",
|
"@tiptap/react": "^2.5.9",
|
||||||
"@tiptap/starter-kit": "^2.5.9",
|
"@tiptap/starter-kit": "^2.5.9",
|
||||||
|
"@transistorsoft/capacitor-background-fetch": "^6.0.1",
|
||||||
"@types/chrome": "^0.0.263",
|
"@types/chrome": "^0.0.263",
|
||||||
"asmcrypto.js": "2.3.2",
|
"asmcrypto.js": "2.3.2",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
@ -515,6 +517,14 @@
|
|||||||
"@capacitor/core": "^6.0.0"
|
"@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": {
|
"node_modules/@chatscope/chat-ui-kit-react": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@chatscope/chat-ui-kit-react/-/chat-ui-kit-react-2.0.3.tgz",
|
"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"
|
"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": {
|
"node_modules/@types/aria-query": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@capacitor/cli": "^6.1.2",
|
"@capacitor/cli": "^6.1.2",
|
||||||
"@capacitor/core": "^6.1.2",
|
"@capacitor/core": "^6.1.2",
|
||||||
"@capacitor/filesystem": "^6.0.1",
|
"@capacitor/filesystem": "^6.0.1",
|
||||||
|
"@capacitor/local-notifications": "^6.1.0",
|
||||||
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
||||||
"@dnd-kit/core": "^6.1.0",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
"@dnd-kit/sortable": "^8.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
@ -39,6 +40,7 @@
|
|||||||
"@tiptap/pm": "^2.5.9",
|
"@tiptap/pm": "^2.5.9",
|
||||||
"@tiptap/react": "^2.5.9",
|
"@tiptap/react": "^2.5.9",
|
||||||
"@tiptap/starter-kit": "^2.5.9",
|
"@tiptap/starter-kit": "^2.5.9",
|
||||||
|
"@transistorsoft/capacitor-background-fetch": "^6.0.1",
|
||||||
"@types/chrome": "^0.0.263",
|
"@types/chrome": "^0.0.263",
|
||||||
"asmcrypto.js": "2.3.2",
|
"asmcrypto.js": "2.3.2",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
|
@ -695,20 +695,18 @@ function App() {
|
|||||||
executeEvent("openDirectMessage", {
|
executeEvent("openDirectMessage", {
|
||||||
from: message.payload.from,
|
from: message.payload.from,
|
||||||
});
|
});
|
||||||
} else if (message.action === "NOTIFICATION_OPEN_GROUP" && isMainWindow) {
|
} else if (message.action === "NOTIFICATION_OPEN_GROUP") {
|
||||||
executeEvent("openGroupMessage", {
|
executeEvent("openGroupMessage", {
|
||||||
from: message.payload.from,
|
from: message.payload.from,
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (
|
||||||
message.action === "NOTIFICATION_OPEN_ANNOUNCEMENT_GROUP" &&
|
message.action === "NOTIFICATION_OPEN_ANNOUNCEMENT_GROUP"
|
||||||
isMainWindow
|
|
||||||
) {
|
) {
|
||||||
executeEvent("openGroupAnnouncement", {
|
executeEvent("openGroupAnnouncement", {
|
||||||
from: message.payload.from,
|
from: message.payload.from,
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (
|
||||||
message.action === "NOTIFICATION_OPEN_THREAD_NEW_POST" &&
|
message.action === "NOTIFICATION_OPEN_THREAD_NEW_POST"
|
||||||
isMainWindow
|
|
||||||
) {
|
) {
|
||||||
executeEvent("openThreadNewPost", {
|
executeEvent("openThreadNewPost", {
|
||||||
data: message.payload.data,
|
data: message.payload.data,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
// TODO
|
|
||||||
import "./qortalRequests";
|
import "./qortalRequests";
|
||||||
import { isArray } from "lodash";
|
import { isArray } from "lodash";
|
||||||
import {
|
import {
|
||||||
@ -88,6 +88,16 @@ import {
|
|||||||
versionCase,
|
versionCase,
|
||||||
} from "./background-cases";
|
} from "./background-cases";
|
||||||
import { getData, removeKeysAndLogout, storeData } from "./utils/chromeStorage";
|
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) {
|
export function cleanUrl(url) {
|
||||||
return url?.replace(/^(https?:\/\/)?(www\.)?/, "");
|
return url?.replace(/^(https?:\/\/)?(www\.)?/, "");
|
||||||
@ -384,35 +394,21 @@ const handleNotificationDirect = async (directs) => {
|
|||||||
(newestLatestTimestamp &&
|
(newestLatestTimestamp &&
|
||||||
newestLatestTimestamp?.timestamp > oldestLatestTimestamp?.timestamp)
|
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(
|
LocalNotifications.schedule({
|
||||||
// {
|
notifications: [
|
||||||
// action: "notification",
|
{
|
||||||
// payload: {
|
title: `New Direct message! ${
|
||||||
// },
|
newestLatestTimestamp?.name && `from ${newestLatestTimestamp.name}`
|
||||||
// }
|
}`,
|
||||||
// )
|
body: "You have received a new direct message",
|
||||||
// audio.play();
|
id: notificationId,
|
||||||
playNotificationSound();
|
schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!isFocused) {
|
if (!isFocused) {
|
||||||
@ -431,32 +427,21 @@ const handleNotificationDirect = async (directs) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const notificationId = "chat_notification_" + Date.now();
|
const notificationId = "chat_notification_" + Date.now();
|
||||||
// chrome.notifications.create(notificationId, {
|
|
||||||
// type: "basic",
|
LocalNotifications.schedule({
|
||||||
// iconUrl: "qort.png", // Add an appropriate icon for chat notifications
|
notifications: [
|
||||||
// title: `New Direct message!`,
|
{
|
||||||
// message: "You have received a new direct message",
|
title: `New Direct message!`,
|
||||||
// priority: 2, // Use the maximum priority to ensure it's noticeable
|
body: "You have received a new direct message",
|
||||||
// });
|
id: notificationId,
|
||||||
if (!isMobile) {
|
schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
|
||||||
setTimeout(() => {
|
}
|
||||||
chrome.notifications.clear(notificationId);
|
]
|
||||||
}, 7000);
|
});
|
||||||
}
|
|
||||||
playNotificationSound();
|
|
||||||
// audio.play();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setChatHeadsDirect(dataDirects);
|
setChatHeadsDirect(dataDirects);
|
||||||
// chrome.runtime.sendMessage(
|
|
||||||
// {
|
|
||||||
// action: "setChatHeads",
|
|
||||||
// payload: {
|
|
||||||
// data,
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
async function getThreadActivity(): Promise<any | null> {
|
async function getThreadActivity(): Promise<any | null> {
|
||||||
@ -625,28 +610,21 @@ const handleNotification = async (groups) => {
|
|||||||
"_type=group" +
|
"_type=group" +
|
||||||
`_from=${newestLatestTimestamp.groupId}`;
|
`_from=${newestLatestTimestamp.groupId}`;
|
||||||
|
|
||||||
// chrome.notifications.create(notificationId, {
|
LocalNotifications.schedule({
|
||||||
// type: "basic",
|
notifications: [
|
||||||
// iconUrl: "qort.png", // Add an appropriate icon for chat notifications
|
{
|
||||||
// title: "New Group Message!",
|
title: "New Group Message!",
|
||||||
// message: `You have received a new message from ${newestLatestTimestamp?.groupName}`,
|
body: `You have received a new message from ${newestLatestTimestamp?.groupName}`,
|
||||||
// priority: 2, // Use the maximum priority to ensure it's noticeable
|
id: notificationId,
|
||||||
|
schedule: { at: new Date(Date.now() + 1000) }, // 1 second from now
|
||||||
// });
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
if (!isMobile) {
|
if (!isMobile) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
chrome.notifications.clear(notificationId);
|
chrome.notifications.clear(notificationId);
|
||||||
}, 7000);
|
}, 7000);
|
||||||
}
|
}
|
||||||
// chrome.runtime.sendMessage(
|
|
||||||
// {
|
|
||||||
// action: "notification",
|
|
||||||
// payload: {
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// audio.play();
|
|
||||||
playNotificationSound();
|
|
||||||
lastGroupNotification = Date.now();
|
lastGroupNotification = Date.now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -667,277 +645,31 @@ const handleNotification = async (groups) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const notificationId = "chat_notification_" + Date.now();
|
const notificationId = "chat_notification_" + Date.now();
|
||||||
// chrome.notifications.create(notificationId, {
|
|
||||||
// type: "basic",
|
LocalNotifications.schedule({
|
||||||
// iconUrl: "qort.png", // Add an appropriate icon for chat notifications
|
notifications: [
|
||||||
// title: "New Group Message!",
|
{
|
||||||
// message: "You have received a new message from one of your groups",
|
title: "New Group Message!",
|
||||||
// priority: 2, // Use the maximum priority to ensure it's noticeable
|
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
|
||||||
if (!isMobile) {
|
}
|
||||||
setTimeout(() => {
|
]
|
||||||
chrome.notifications.clear(notificationId);
|
});
|
||||||
}, 7000);
|
|
||||||
}
|
|
||||||
playNotificationSound();
|
|
||||||
// audio.play();
|
|
||||||
lastGroupNotification = Date.now();
|
lastGroupNotification = Date.now();
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (!data || data?.length === 0) return;
|
if (!data || data?.length === 0) return;
|
||||||
setChatHeads(dataWithUpdates);
|
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 () => {
|
const listenForNewGroupAnnouncements = async () => {
|
||||||
try {
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user