From fd80b8578640316e71b43f318010e1ad726887de Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:25:11 -0300 Subject: [PATCH] feat: parse xml --- package.json | 1 - .../index.ts} | 45 ++++----- src/main/services/notifications/xml.ts | 98 +++++++++++++++++++ yarn.lock | 29 ------ 4 files changed, 117 insertions(+), 56 deletions(-) rename src/main/services/{notifications.ts => notifications/index.ts} (82%) create mode 100644 src/main/services/notifications/xml.ts diff --git a/package.json b/package.json index abe43e2e..6dcba624 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,6 @@ "lottie-react": "^2.4.0", "parse-torrent": "^11.0.17", "piscina": "^4.7.0", - "powertoast": "^3.0.0", "react-hook-form": "^7.53.0", "react-i18next": "^14.1.0", "react-loading-skeleton": "^3.4.0", diff --git a/src/main/services/notifications.ts b/src/main/services/notifications/index.ts similarity index 82% rename from src/main/services/notifications.ts rename to src/main/services/notifications/index.ts index e7cb1374..e156bc80 100644 --- a/src/main/services/notifications.ts +++ b/src/main/services/notifications/index.ts @@ -4,13 +4,13 @@ import { parseICO } from "icojs"; import trayIcon from "@resources/tray-icon.png?asset"; import { Game } from "@main/entity"; import { gameRepository, userPreferencesRepository } from "@main/repository"; -import { toXmlString } from "powertoast"; import fs from "node:fs"; import axios from "axios"; import path from "node:path"; import sound from "sound-play"; import { achievementSoundPath } from "@main/constants"; import icon from "@resources/icon.png?asset"; +import { NotificationOptions, toXmlString } from "./xml"; const getGameIconNativeImage = async (gameId: number) => { try { @@ -101,7 +101,7 @@ export const publishCombinedNewAchievementNotification = async ( ? await downloadImage(achievementIcon) : icon; - new Notification({ + const options: NotificationOptions = { title: "New achievement unlocked", body: t("new_achievements_unlocked", { ns: "achievement", @@ -110,16 +110,11 @@ export const publishCombinedNewAchievementNotification = async ( }), icon: iconPath, silent: true, - toastXml: toXmlString({ - title: "New achievement unlocked", - message: t("new_achievements_unlocked", { - ns: "achievement", - gameCount, - achievementCount, - }), - icon: iconPath, - silent: true, - }), + }; + + new Notification({ + ...options, + toastXml: toXmlString(options), }).show(); sound.play(achievementSoundPath); @@ -133,24 +128,22 @@ export const publishNewAchievementNotification = async (achievement: { }) => { const iconPath = await downloadImage(achievement.achievementIcon); - new Notification({ + const options: NotificationOptions = { title: "New achievement unlocked", body: achievement.displayName, icon: iconPath, silent: true, - toastXml: toXmlString({ - title: "New achievement unlocked", - message: achievement.displayName, - icon: iconPath, - silent: true, - progress: { - value: Math.round( - (achievement.unlockedAchievementCount * 100) / - achievement.totalAchievementCount - ), - valueOverride: `${achievement.unlockedAchievementCount}/${achievement.totalAchievementCount} achievements`, - }, - }), + progress: { + value: + achievement.unlockedAchievementCount / + achievement.totalAchievementCount, + valueOverride: `${achievement.unlockedAchievementCount}/${achievement.totalAchievementCount} achievements`, + }, + }; + + new Notification({ + ...options, + toastXml: toXmlString(options), }).show(); sound.play(achievementSoundPath); diff --git a/src/main/services/notifications/xml.ts b/src/main/services/notifications/xml.ts new file mode 100644 index 00000000..4e8bb826 --- /dev/null +++ b/src/main/services/notifications/xml.ts @@ -0,0 +1,98 @@ +export interface NotificationOptions { + title: string; + body?: string; + icon: string; + duration?: "short" | "long"; + silent?: boolean; + progress?: { + title?: string; + status?: string; + value: number; + valueOverride: string; + }; +} +function escape(string: string) { + return string.replace(/[<>&'"]/g, (match) => { + switch (match) { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + default: + return ""; + } + }); +} + +function addAttributeOrTrim(name, value) { + return value ? `${name}="${value}" ` : ""; +} + +const Activation = { + types: [ + "protocol", + "background", + "foreground", + "system", //system call such as alarm (snooze/dismiss), also used by Notification Visualizer + ], + behavior: ["default", "pendingUpdate"], +}; + +const Scenarios = [ + "default", + "alarm", + "reminder", + "incomingCall", + "urgent", //win10/11 22h2 +]; + +export function toXmlString(options: NotificationOptions) { + let template = + ""; + + //Visual + template += ``; + if (options.icon) + template += ``; + template += + `` + + ``; + + //Progress bar + if (options.progress) { + template += + ""; + } + template += ""; + + //Actions + template += ""; + template += ""; + + //Audio + template += ""; + + return template; +} diff --git a/yarn.lock b/yarn.lock index 23785ffd..a92e503e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2824,26 +2824,6 @@ "@types/babel__core" "^7.20.5" react-refresh "^0.14.0" -"@xan105/error@^1.6.2", "@xan105/error@^1.7.0": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@xan105/error/-/error-1.7.1.tgz#d417e839cef7d79df4594943553d3d5b14f26bfa" - integrity sha512-FYIUYijbmg62L9QQ5BsR14DuZatAJJvwo10yzuEDEsu8L0FAa4DZivWFAf66nYjEiSz50SFGtMxWSyG+y/ZGGw== - -"@xan105/fs@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@xan105/fs/-/fs-2.2.1.tgz#46ca0f943443f5fa5daebd0af6bee289637be098" - integrity sha512-jYvheYkJ1F6XfUYSfCIgdfgx/yWiW5uitXhydEceirICNMRubboNQM1LUB5+ZDmKq4hCNyjqxv4TPeARMcOepQ== - dependencies: - "@xan105/error" "^1.6.2" - "@xan105/is" "^2.9.3" - -"@xan105/is@^2.9.3": - version "2.9.3" - resolved "https://registry.yarnpkg.com/@xan105/is/-/is-2.9.3.tgz#81c2152202e450c0aad8927fdc6eea30649f30d6" - integrity sha512-1Ivr52VENqksdcvhar+rv+kTSsDWFBPyScpMIJibZJMzSOyiGmu25bJOwiSVl0x2hFJcQW2FFUURUqYyxe9X1g== - dependencies: - "@xan105/error" "^1.6.2" - "@xmldom/xmldom@^0.8.8": version "0.8.10" resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz" @@ -7031,15 +7011,6 @@ postgres-range@^1.1.1: resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== -powertoast@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/powertoast/-/powertoast-3.0.0.tgz#38cbcfde8cb15867ef14d89d0c890c76a445f828" - integrity sha512-nlGnBkMchJS6P4uQgjROpzHs72WqgB6cYP7hDFACXOZUSu2lXgDqJ5fKt2B/53jO+UynVlbhAQHHQvSOLUAUmQ== - dependencies: - "@xan105/error" "^1.7.0" - "@xan105/fs" "^2.2.1" - "@xan105/is" "^2.9.3" - prebuild-install@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056"