mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-01-23 21:44:55 +03:00
feat: browser window for notification
This commit is contained in:
parent
753a293cd7
commit
bdba3dd29c
@ -49,27 +49,43 @@ export const mergeAchievements = async (
|
||||
});
|
||||
|
||||
if (newAchievements.length) {
|
||||
WindowManager.mainWindow?.webContents.send(
|
||||
"on-achievement-unlocked",
|
||||
objectId,
|
||||
shop
|
||||
);
|
||||
}
|
||||
|
||||
if (newAchievements.length > 0 && publishNotification) {
|
||||
const achievement = newAchievements.pop()!;
|
||||
const achievement = newAchievements.at(-1)!;
|
||||
const achievementInfo = JSON.parse(
|
||||
localGameAchievement?.achievements || "[]"
|
||||
).find((steamAchievement) => {
|
||||
return achievement.name === steamAchievement.name;
|
||||
});
|
||||
|
||||
publishNewAchievementNotification(
|
||||
game.title ?? "",
|
||||
WindowManager.mainWindow?.webContents.send(
|
||||
"on-achievement-unlocked",
|
||||
objectId,
|
||||
shop,
|
||||
achievementInfo.displayName,
|
||||
achievementInfo.icon,
|
||||
newAchievements.length
|
||||
achievementInfo.icon
|
||||
);
|
||||
|
||||
if (publishNotification) {
|
||||
WindowManager.notificationWindow?.webContents.send(
|
||||
"on-achievement-unlocked",
|
||||
objectId,
|
||||
shop,
|
||||
achievementInfo.displayName,
|
||||
achievementInfo.icon
|
||||
);
|
||||
|
||||
WindowManager.notificationWindow?.setBounds({ y: 50 });
|
||||
|
||||
setTimeout(() => {
|
||||
WindowManager.notificationWindow?.setBounds({ y: -100 });
|
||||
}, 4000);
|
||||
|
||||
publishNewAchievementNotification(
|
||||
game.title ?? "",
|
||||
achievementInfo.displayName,
|
||||
achievementInfo.icon,
|
||||
newAchievements.length
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);
|
||||
|
@ -19,6 +19,7 @@ import { HydraApi } from "./hydra-api";
|
||||
|
||||
export class WindowManager {
|
||||
public static mainWindow: Electron.BrowserWindow | null = null;
|
||||
public static notificationWindow: Electron.BrowserWindow | null = null;
|
||||
|
||||
private static loadURL(hash = "") {
|
||||
// HMR for renderer base on electron-vite cli.
|
||||
@ -78,7 +79,45 @@ export class WindowManager {
|
||||
app.quit();
|
||||
}
|
||||
WindowManager.mainWindow?.setProgressBar(-1);
|
||||
WindowManager.mainWindow = null;
|
||||
});
|
||||
|
||||
this.notificationWindow = new BrowserWindow({
|
||||
transparent: true,
|
||||
maximizable: false,
|
||||
minimizable: false,
|
||||
focusable: true,
|
||||
skipTaskbar: true,
|
||||
frame: false,
|
||||
width: 240,
|
||||
height: 60,
|
||||
x: 25,
|
||||
y: -100,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "../preload/index.mjs"),
|
||||
sandbox: false,
|
||||
},
|
||||
});
|
||||
if (!app.isPackaged)
|
||||
WindowManager.notificationWindow?.webContents.openDevTools();
|
||||
|
||||
this.notificationWindow.setVisibleOnAllWorkspaces(true, {
|
||||
visibleOnFullScreen: true,
|
||||
});
|
||||
this.notificationWindow.setAlwaysOnTop(true, "screen-saver", 1);
|
||||
|
||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
|
||||
this.notificationWindow.loadURL(
|
||||
`${process.env["ELECTRON_RENDERER_URL"]}#/achievement-notification`
|
||||
);
|
||||
} else {
|
||||
this.notificationWindow.loadFile(
|
||||
path.join(__dirname, "../renderer/index.html"),
|
||||
{
|
||||
hash: "achievement-notification",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static openAuthWindow() {
|
||||
|
@ -51,12 +51,21 @@ contextBridge.exposeInMainWorld("electron", {
|
||||
getTrendingGames: () => ipcRenderer.invoke("getTrendingGames"),
|
||||
getGameAchievements: (objectId: string, shop: GameShop) =>
|
||||
ipcRenderer.invoke("getGameAchievements", objectId, shop),
|
||||
onAchievementUnlocked: (cb: (objectId: string, shop: GameShop) => void) => {
|
||||
onAchievementUnlocked: (
|
||||
cb: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
displayName: string,
|
||||
iconUrl: string
|
||||
) => void
|
||||
) => {
|
||||
const listener = (
|
||||
_event: Electron.IpcRendererEvent,
|
||||
objectId: string,
|
||||
shop: GameShop
|
||||
) => cb(objectId, shop);
|
||||
shop: GameShop,
|
||||
displayName: string,
|
||||
iconUrl: string
|
||||
) => cb(objectId, shop, displayName, iconUrl);
|
||||
ipcRenderer.on("on-achievement-unlocked", listener);
|
||||
return () =>
|
||||
ipcRenderer.removeListener("on-achievement-unlocked", listener);
|
||||
|
7
src/renderer/src/declaration.d.ts
vendored
7
src/renderer/src/declaration.d.ts
vendored
@ -71,7 +71,12 @@ declare global {
|
||||
shop: GameShop
|
||||
) => Promise<GameAchievement[]>;
|
||||
onAchievementUnlocked: (
|
||||
cb: (objectId: string, shop: GameShop) => void
|
||||
cb: (
|
||||
objectId: string,
|
||||
shop: GameShop,
|
||||
displayName: string,
|
||||
iconUrl: string
|
||||
) => void
|
||||
) => () => Electron.IpcRenderer;
|
||||
|
||||
/* Library */
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
import { store } from "./store";
|
||||
|
||||
import resources from "@locales";
|
||||
import { Achievemnt } from "./pages/achievement/achievement";
|
||||
|
||||
Sentry.init({});
|
||||
|
||||
@ -65,6 +66,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<Route path="/settings" Component={Settings} />
|
||||
<Route path="/profile/:userId" Component={Profile} />
|
||||
</Route>
|
||||
<Route path="/achievement-notification" Component={Achievemnt} />
|
||||
</Routes>
|
||||
</HashRouter>
|
||||
</Provider>
|
||||
|
62
src/renderer/src/pages/achievement/achievement.tsx
Normal file
62
src/renderer/src/pages/achievement/achievement.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function Achievemnt() {
|
||||
const [achievementInfo, setAchievementInfo] = useState<{
|
||||
displayName: string;
|
||||
icon: string;
|
||||
} | null>(null);
|
||||
|
||||
const [audio, setAudio] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electron.onAchievementUnlocked(
|
||||
(_object, _shop, displayName, icon) => {
|
||||
console.log("Achievement unlocked", displayName, icon);
|
||||
setAudio(
|
||||
"https://us-tuna-sounds-files.voicemod.net/ade71f0d-a41b-4e3a-8097-9f1cc585745c-1646035604239.mp3"
|
||||
);
|
||||
|
||||
setAchievementInfo({
|
||||
displayName,
|
||||
icon,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (audio) {
|
||||
const audioElement = new Audio(audio);
|
||||
audioElement.volume = 1.0;
|
||||
audioElement.play();
|
||||
setAudio(null);
|
||||
}
|
||||
}, [audio]);
|
||||
|
||||
if (!achievementInfo) return <p>Nada</p>;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: "8px",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={achievementInfo.icon}
|
||||
alt={achievementInfo.displayName}
|
||||
style={{ width: 60, height: 60 }}
|
||||
/>
|
||||
<div>
|
||||
<p>Achievement unlocked</p>
|
||||
<p>{achievementInfo.displayName}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user