add notification and system notification

This commit is contained in:
MathieuG-P
2022-12-26 00:09:52 +01:00
parent 89ac6077be
commit ef202e33ec
11 changed files with 138 additions and 5 deletions
+1
View File
@@ -2,3 +2,4 @@ export const BS_EXECUTABLE = "Beat Saber.exe";
export const OCULUS_BS_DIR = "hyperbolic-magnetism-beat-saber"
export const BS_APP_ID = "620980";
export const BS_DEPOT = "620981";
export const APP_NAME = "BSManager";
+6
View File
@@ -1,6 +1,8 @@
import { ipcMain, shell, dialog, app } from 'electron';
import { UtilsService } from '../services/utils.service';
import { IpcRequest } from 'shared/models/ipc';
import { SystemNotificationOptions } from 'shared/models/notification/system-notification.model';
import { NotificationService } from '../services/notification.service';
// TODO IMPROVE WINDOW CONTROL BY USING WINDOW SERVICE
@@ -55,3 +57,7 @@ ipcMain.on("current-version", async (event, request: IpcRequest<void>) => {
ipcMain.on("open-logs", async (event, request: IpcRequest<void>) => {
shell.openPath(app.getPath("logs"));
});
ipcMain.on("notify-system", async (event, request: IpcRequest<SystemNotificationOptions>) => {
NotificationService.getInstance().notify(request.args)
});
+4 -1
View File
@@ -19,6 +19,7 @@ import { AppWindow } from 'shared/models/window-manager/app-window.model';
import { LocalMapsManagerService } from './services/additional-content/local-maps-manager.service';
import { LocalPlaylistsManagerService } from './services/additional-content/local-playlists-manager.service';
import { LocalModelsManagerService } from './services/additional-content/local-models-manager.service';
import { APP_NAME } from './constants';
const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
@@ -89,7 +90,9 @@ else{
app.whenReady().then(() => {
// process.argv.push("modelsaber://platform/1671435302/The grinch mountain.plat"); // to force deep-link (oneClick map)
app.setAppUserModelId(APP_NAME);
process.argv.push("beatsaver://2d5bc"); // to force deep-link (oneClick map)
initServicesMustBeInitialized();
+27
View File
@@ -0,0 +1,27 @@
import { Notification } from "electron";
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
import { UtilsService } from "./utils.service";
export class NotificationService {
private static instance: NotificationService;
public static getInstance(): NotificationService{
if(!NotificationService.instance){ NotificationService.instance = new NotificationService(); }
return NotificationService.instance;
}
private readonly APP_ICON: string;
private readonly utils: UtilsService;
private constructor(){
this.utils = UtilsService.getInstance();
this.APP_ICON = this.utils.getAssetsPath("favicon.ico");
}
public notify(options: SystemNotificationOptions){
new Notification({...options, icon: this.APP_ICON}).show();
}
}
@@ -3,6 +3,7 @@ import { resolveHtmlPath } from "../util";
import { UtilsService } from "./utils.service";
import { AppWindow } from "shared/models/window-manager/app-window.model";
import path from "path";
import { APP_NAME } from "../constants";
export class WindowManagerService{
@@ -21,6 +22,7 @@ export class WindowManagerService{
}
private readonly baseWindowOption: BrowserWindowConstructorOptions = {
title: APP_NAME,
icon: this.utilsService.getAssetsPath("favicon.ico"),
show: false,
frame: false,
+38 -3
View File
@@ -150,16 +150,51 @@ export function SettingsPage() {
const openLogs = () => ipcService.sendLazy("open-logs");
// TODO TRANSLATE
const showDeepLinkError = (isDesactivation: boolean) => {
const desc = isDesactivation ? "Une erreur inconnue c'est produite" : "Impossible d'activer les installations OneClick";
notificationService.notifyError({title: "notifications.types.error", desc, duration: 3000});
}
const showDeepLinkSuccess = (isDesactivation: boolean) => {
const desc = isDesactivation ? "Les installations OneClick ont été désactivées" : "Les installations OneClick ont été activées";
const title = isDesactivation ? "OneClick désactivée !" : "OneClick activée !";
notificationService.notifySuccess({title, desc, duration: 3000});
}
const showDeepLinkWarning = (isDesactivation: boolean) => {
const desc = isDesactivation ? "Un problème est survenu lors de la désactivation des OneClicks, veuillez réessayez" : "Un problème est survenu lors de l'activation des OneClicks, veuillez réessayez";
notificationService.notifyWarning({title: "Attention !", desc, duration: 3000});
}
const toogleMapDeepLinks = () => {
mapsManager.toogleDeepLinks().finally(() => mapsManager.isDeepLinksEnabled().then(enabled => setMapDeepLinksEnabled(() => enabled)));
const isDesactivation = mapDeepLinksEnabled;
mapsManager.toogleDeepLinks().catch(() => {
showDeepLinkError(isDesactivation);
}).then(res => {
if(!res){ return showDeepLinkWarning(isDesactivation); }
showDeepLinkSuccess(isDesactivation)
}).finally(() => mapsManager.isDeepLinksEnabled().then(enabled => setMapDeepLinksEnabled(() => enabled)));
}
const tooglePlaylistsDeepLinks = () => {
playlistsManager.toogleDeepLinks().finally(() => playlistsManager.isDeepLinksEnabled().then(enabled => setPlaylistsDeepLinkEnabled(() => enabled)));
const isDesactivation = playlistsDeepLinkEnabled;
playlistsManager.toogleDeepLinks().catch(() => {
showDeepLinkError(isDesactivation);
}).then(res => {
if(!res){ return showDeepLinkWarning(isDesactivation); }
showDeepLinkSuccess(isDesactivation)
}).finally(() => playlistsManager.isDeepLinksEnabled().then(enabled => setPlaylistsDeepLinkEnabled(() => enabled)));
}
const toogleModelsDeepLinks = () => {
modelsManager.toogleDeepLinks().finally(() => modelsManager.isDeepLinksEnabled().then(enabled => setModelsDeepLinkEnabled(() => enabled)));
const isDesactivation = modelsDeepLinkEnabled;
modelsManager.toogleDeepLinks().catch(() => {
showDeepLinkError(isDesactivation)
}).then(res => {
if(!res){ return showDeepLinkWarning(isDesactivation); }
showDeepLinkSuccess(isDesactivation)
}).finally(() => modelsManager.isDeepLinksEnabled().then(enabled => setModelsDeepLinkEnabled(() => enabled)));
}
return (
+19 -1
View File
@@ -1,17 +1,27 @@
import { BehaviorSubject } from "rxjs";
import { SystemNotificationOptions } from "shared/models/notification/system-notification.model";
import { I18nService } from "./i18n.service";
import { IpcService } from "./ipc.service";
export class NotificationService{
private static instance: NotificationService;
public readonly notifications$: BehaviorSubject<ResolvableNotification[]>;
public static getInstance(): NotificationService{
if(!NotificationService.instance){ NotificationService.instance = new NotificationService(); }
return NotificationService.instance;
}
public readonly notifications$: BehaviorSubject<ResolvableNotification[]>;
private readonly ipc: IpcService;
private readonly i18n: I18nService;
private constructor(){
this.ipc = IpcService.getInstance();
this.i18n = I18nService.getInstance();
this.notifications$ = new BehaviorSubject<ResolvableNotification[]>([]);
}
@@ -46,6 +56,14 @@ export class NotificationService{
return this.notify(notification);
}
public notifySystem(options: SystemNotificationOptions){
options.body = options.body && this.i18n.translate(options.body);
options.title = options.title && this.i18n.translate(options.title);
this.ipc.sendLazy<SystemNotificationOptions>("notify-system", {args: options});
}
}
export interface Notification {
@@ -4,6 +4,7 @@ import { BsmImage } from "renderer/components/shared/bsm-image.component";
import TitleBar from "renderer/components/title-bar/title-bar.component";
import { IpcService } from "renderer/services/ipc.service";
import { MapsDownloaderService } from "renderer/services/maps-downloader.service";
import { NotificationService } from "renderer/services/notification.service";
import { ProgressBarService } from "renderer/services/progress-bar.service";
import { ThemeService } from "renderer/services/theme.service";
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
@@ -20,6 +21,7 @@ export default function OneClickDownloadMap() {
const themeService = ThemeService.getInstance();
const progressBar = ProgressBarService.getInstance();
const windows = WindowManagerService.getInstance();
const notification = NotificationService.getInstance();
const [mapInfo, setMapInfo] = useState<BsvMapDetail>(null);
@@ -38,6 +40,7 @@ export default function OneClickDownloadMap() {
const promise = new Promise<void>(async (resolve, reject) => {
try{
const ipcRes = await ipc.send<{id: string, isHash: boolean}>("one-click-map-info");
if(!ipcRes.success){ return reject(ipcRes.error); }
@@ -60,6 +63,16 @@ export default function OneClickDownloadMap() {
});
// TODO TRANSLATE
promise.catch(() => {
notification.notifySystem({title: "Erreur", body: "Une erreur c'est produite lors de l'installation de la map"});
})
promise.then(() => {
notification.notifySystem({title: "OneClick", body: "Installation de la map terminé"});
});
promise.finally(() =>{
windows.close("oneclick-download-map.html");
});
@@ -4,6 +4,7 @@ import { BsmImage } from "renderer/components/shared/bsm-image.component";
import TitleBar from "renderer/components/title-bar/title-bar.component";
import { IpcService } from "renderer/services/ipc.service";
import { ModelDownloaderService } from "renderer/services/model-downloader.service";
import { NotificationService } from "renderer/services/notification.service";
import { ProgressBarService } from "renderer/services/progress-bar.service";
import { ThemeService } from "renderer/services/theme.service";
import { ModelSaberService } from "renderer/services/thrird-partys/model-saber.service";
@@ -19,6 +20,7 @@ export default function OneClickDownloadModel() {
const progress = ProgressBarService.getInstance();
const modelDownloader = ModelDownloaderService.getInstance();
const windows = WindowManagerService.getInstance();
const notification = NotificationService.getInstance();
const [model, setModel] = useState<MSModel>(null);
@@ -48,6 +50,16 @@ export default function OneClickDownloadModel() {
});
// TODO TRANSLATE
promise.catch(() => {
notification.notifySystem({title: "Erreur", body: "Une erreur c'est produite lors de l'installation du model"});
})
promise.then(() => {
notification.notifySystem({title: "OneClick", body: "Installation du model terminé"});
});
promise.finally(() => windows.close("oneclick-download-model.html"));
return () => {
@@ -5,6 +5,7 @@ import { BsmImage } from "renderer/components/shared/bsm-image.component";
import TitleBar from "renderer/components/title-bar/title-bar.component";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { IpcService } from "renderer/services/ipc.service"
import { NotificationService } from "renderer/services/notification.service";
import { PlaylistDownloaderService } from "renderer/services/playlist-downloader.service";
import { ThemeService } from "renderer/services/theme.service";
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
@@ -21,6 +22,7 @@ export default function OneClickDownloadPlaylist() {
const playlistDownloader = PlaylistDownloaderService.getInstance();
const mapsContainer = useRef<HTMLDivElement>(null);
const windows = WindowManagerService.getInstance();
const notification = NotificationService.getInstance();
const [playlist, setPlaylist] = useState<BsvPlaylist>(null);
const downloadedMap = useObservable(playlistDownloader.progress$.pipe(filter(download => !!download), map(download => [...(download.downloadedMaps ?? []), download?.current])), []);
@@ -49,6 +51,16 @@ export default function OneClickDownloadPlaylist() {
});
// TODO TRANSLATE
promise.catch(() => {
notification.notifySystem({title: "Erreur", body: "Une erreur c'est produite lors de l'installation de la playlist"});
})
promise.then(() => {
notification.notifySystem({title: "OneClick", body: "Installation de la playlist terminé"});
});
promise.finally(() => {
windows.close("oneclick-download-playlist.html");
});
@@ -0,0 +1,4 @@
export interface SystemNotificationOptions {
title?: string,
body?: string
}