diff --git a/main.js b/main.js
index 0536b6c..513aa9c 100644
--- a/main.js
+++ b/main.js
@@ -1,5 +1,5 @@
// Modules to control application life and create native browser window
-const { app, BrowserWindow, Menu, ipcMain } = require("electron");
+const { app, BrowserWindow, Menu, ipcMain, dialog } = require("electron");
const path = require("path");
const serve = require("electron-serve");
const loadURL = serve({ directory: "public" });
@@ -7,6 +7,7 @@ const config = require("./src/config/config");
const { setupTitlebar, attachTitlebarToWindow } = require(
"custom-electron-titlebar/main",
);
+const { isValidOsuFolder } = require("./src/util/osuUtil");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
@@ -112,6 +113,33 @@ function registerIPCPipes() {
return true;
});
+ ipcMain.handle("ezpplauncher:settings", async (e) => {
+ return config.all();
+ });
+
+ ipcMain.handle("ezpplauncher:set-folder", async (e) => {
+ const folderResult = await dialog.showOpenDialog({
+ title: "Select osu! installation directory",
+ properties: ["openDirectory"],
+ });
+ if (!folderResult.canceled) {
+ const folder = folderResult.filePaths[0];
+ if (await isValidOsuFolder(folder)) {
+ config.set("osuPath", folder);
+ mainWindow.webContents.send("ezpplauncher:alert", {
+ type: "success",
+ message: "osu! path successfully saved!",
+ });
+ } else {
+ mainWindow.webContents.send("ezpplauncher:alert", {
+ type: "error",
+ message: "invalid osu! path!",
+ });
+ }
+ }
+ return config.all();
+ });
+
ipcMain.handle("ezpplauncher:launch", async (e) => {
mainWindow.webContents.send("ezpplauncher:launchstatus", {
status: "Checking osu! directory...",
diff --git a/preload.js b/preload.js
index 0c862fb..62af955 100644
--- a/preload.js
+++ b/preload.js
@@ -22,25 +22,49 @@ window.addEventListener("login-attempt", async (e) => {
);
});
-window.addEventListener("autologin-attempt", async (e) => {
+window.addEventListener("autologin-attempt", async () => {
const loginResult = await ipcRenderer.invoke("ezpplauncher:autologin");
window.dispatchEvent(
new CustomEvent("login-result", { detail: loginResult }),
);
});
-window.addEventListener("logout", async (e) => {
+window.addEventListener("logout", async () => {
await ipcRenderer.invoke("ezpplauncher:logout");
});
-window.addEventListener("guest-login", async (e) => {
+window.addEventListener("guest-login", async () => {
await ipcRenderer.invoke("ezpplauncher:guestlogin");
});
-window.addEventListener("launch", async (e) => {
+window.addEventListener("launch", async () => {
await ipcRenderer.invoke("ezpplauncher:launch");
});
+window.addEventListener("settings-get", async () => {
+ const settings = await ipcRenderer.invoke("ezpplauncher:settings");
+ window.dispatchEvent(
+ new CustomEvent("settings-result", { detail: settings }),
+ );
+});
+
+window.addEventListener("folder-set", async (e) => {
+ const result = await ipcRenderer.invoke("ezpplauncher:set-folder");
+ window.dispatchEvent(
+ new CustomEvent("settings-result", { detail: result }),
+ );
+});
+
+window.addEventListener("settings-set", async (e) => {
+ await ipcRenderer.invoke("ezpplauncher:settings-set", e.detail);
+});
+
+ipcRenderer.addListener("ezpplauncher:alert", (e, args) => {
+ window.dispatchEvent(
+ new CustomEvent("alert", { detail: args }),
+ );
+});
+
ipcRenderer.addListener("ezpplauncher:launchstatus", (e, args) => {
window.dispatchEvent(
new CustomEvent("launchStatusUpdate", { detail: args }),
diff --git a/src/App.svelte b/src/App.svelte
index 0ba0886..e7c4213 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -22,7 +22,7 @@
import { Page } from "./consts/pages";
import Login from "./pages/Login.svelte";
import Launch from "./pages/Launch.svelte";
- import { Toaster } from "svelte-french-toast";
+ import toast, { Toaster } from "svelte-french-toast";
import type { User } from "./types/user";
import Settings from "./pages/Settings.svelte";
@@ -51,6 +51,40 @@
const progress = (e as CustomEvent).detail.progress;
launchPercentage.set(progress);
});
+
+ window.addEventListener("alert", (e) => {
+ console.log((e as CustomEvent).detail);
+ const toastMessage = (e as CustomEvent).detail;
+ switch (toastMessage.type) {
+ case "success": {
+ toast.success(toastMessage.message, {
+ position: "bottom-center",
+ className:
+ "dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
+ duration: 1500,
+ });
+ break;
+ }
+ case "error": {
+ toast.error(toastMessage.message, {
+ position: "bottom-center",
+ className:
+ "dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
+ duration: 1500,
+ });
+ break;
+ }
+ default: {
+ toast(toastMessage.message, {
+ icon: "ℹ",
+ position: "bottom-center",
+ className:
+ "dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
+ duration: 1500,
+ });
+ }
+ }
+ });
diff --git a/src/config/config.js b/src/config/config.js
index ae42aad..ad5e97e 100644
--- a/src/config/config.js
+++ b/src/config/config.js
@@ -38,7 +38,15 @@ const get = (
return result ? result.val ?? undefined : undefined;
};
+const all = () => {
+ const result = db.prepare(
+ `SELECT configKey key, configValue val FROM config WHERE 1`,
+ ).all();
+ return result ?? undefined;
+};
+
module.exports = {
+ all,
get,
set,
remove,
diff --git a/src/pages/Settings.svelte b/src/pages/Settings.svelte
index 6b1642f..209130a 100644
--- a/src/pages/Settings.svelte
+++ b/src/pages/Settings.svelte
@@ -3,6 +3,19 @@
import { FolderSolid } from "flowbite-svelte-icons";
import { currentPage } from "../storage/localStore";
import { Page } from "../consts/pages";
+
+ let folderPath: string = "";
+
+ window.addEventListener("settings-result", (e) => {
+ const settings: Record[] = (e as CustomEvent).detail;
+ const osuPath = settings.find((setting) => setting.key == "osuPath");
+ folderPath = osuPath ? osuPath.val : "";
+ });
+ window.dispatchEvent(new CustomEvent("settings-get"));
+
+ const setFolderPath = () => {
+ window.dispatchEvent(new CustomEvent("folder-set"));
+ };
-