diff --git a/electron-builder.yml b/electron-builder.yml index 53c67d97..d33428bc 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -8,6 +8,7 @@ extraResources: - from: node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe to: fastlist.exe - from: node_modules/create-desktop-shortcuts/src/windows.vbs + - from: resources/hydralauncher.vbs files: - "!**/.vscode/*" - "!src/*" diff --git a/resources/hydralauncher.vbs b/resources/hydralauncher.vbs new file mode 100644 index 00000000..ff611acf --- /dev/null +++ b/resources/hydralauncher.vbs @@ -0,0 +1,3 @@ +Set WshShell = CreateObject("WScript.Shell" ) +WshShell.Run """%localappdata%\Programs\Hydra\Hydra.exe""", 0 'Must quote command if it has spaces; must escape quotes +Set WshShell = Nothing diff --git a/src/main/constants.ts b/src/main/constants.ts index 850c9ada..62713a2c 100644 --- a/src/main/constants.ts +++ b/src/main/constants.ts @@ -14,3 +14,12 @@ export const logsPath = path.join(app.getPath("appData"), "hydra", "logs"); export const seedsPath = app.isPackaged ? path.join(process.resourcesPath, "seeds") : path.join(__dirname, "..", "..", "seeds"); + +export const windowsStartupPath = path.join( + app.getPath("appData"), + "Microsoft", + "Windows", + "Start Menu", + "Programs", + "Startup" +); diff --git a/src/main/events/index.ts b/src/main/events/index.ts index 2a466f98..d1075e3e 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -49,4 +49,8 @@ import "./profile/update-profile"; ipcMain.handle("ping", () => "pong"); ipcMain.handle("getVersion", () => app.getVersion()); +ipcMain.handle( + "isPortableVersion", + () => process.env.PORTABLE_EXECUTABLE_FILE != null +); ipcMain.handle("getDefaultDownloadsPath", () => defaultDownloadsPath); diff --git a/src/main/events/user-preferences/auto-launch.ts b/src/main/events/user-preferences/auto-launch.ts index 3292d2a6..37831db9 100644 --- a/src/main/events/user-preferences/auto-launch.ts +++ b/src/main/events/user-preferences/auto-launch.ts @@ -1,18 +1,35 @@ +import { windowsStartupPath } from "@main/constants"; import { registerEvent } from "../register-event"; import AutoLaunch from "auto-launch"; import { app } from "electron"; +import fs from "node:fs"; +import path from "node:path"; const autoLaunch = async ( _event: Electron.IpcMainInvokeEvent, enabled: boolean ) => { - const appLauncher = new AutoLaunch({ - name: app.getName(), - }); - if (enabled) { - appLauncher.enable().catch(); + if (!app.isPackaged) return; + + if (process.platform == "win32") { + const destination = path.join(windowsStartupPath, "hydralauncher.vbs"); + + if (enabled) { + const scriptPath = path.join(process.resourcesPath, "hydralauncher.vbs"); + + fs.copyFileSync(scriptPath, destination); + } else { + fs.rmSync(destination); + } } else { - appLauncher.disable().catch(); + const appLauncher = new AutoLaunch({ + name: app.getName(), + }); + if (enabled) { + appLauncher.enable().catch(); + } else { + appLauncher.disable().catch(); + } } }; diff --git a/src/preload/index.ts b/src/preload/index.ts index f75eba5d..ecabe9e8 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -110,6 +110,7 @@ contextBridge.exposeInMainWorld("electron", { ping: () => ipcRenderer.invoke("ping"), getVersion: () => ipcRenderer.invoke("getVersion"), getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"), + isPortableVersion: () => ipcRenderer.invoke("isPortableVersion"), openExternal: (src: string) => ipcRenderer.invoke("openExternal", src), isUserLoggedIn: () => ipcRenderer.invoke("isUserLoggedIn"), showOpenDialog: (options: Electron.OpenDialogOptions) => diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index abf1743f..ae89bb8b 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -104,6 +104,7 @@ declare global { getVersion: () => Promise; ping: () => string; getDefaultDownloadsPath: () => Promise; + isPortableVersion: () => Promise; showOpenDialog: ( options: Electron.OpenDialogOptions ) => Promise; diff --git a/src/renderer/src/pages/settings/settings-behavior.tsx b/src/renderer/src/pages/settings/settings-behavior.tsx index 7f7aa5fd..f0b4b4c4 100644 --- a/src/renderer/src/pages/settings/settings-behavior.tsx +++ b/src/renderer/src/pages/settings/settings-behavior.tsx @@ -10,6 +10,8 @@ export function SettingsBehavior() { (state) => state.userPreferences.value ); + const [showRunAtStartup, setShowRunAtStartup] = useState(false); + const { updateUserPreferences } = useContext(settingsContext); const [form, setForm] = useState({ @@ -28,6 +30,12 @@ export function SettingsBehavior() { } }, [userPreferences]); + useEffect(() => { + window.electron.isPortableVersion().then((isPortableVersion) => { + setShowRunAtStartup(!isPortableVersion); + }); + }, []); + const handleChange = (values: Partial) => { setForm((prev) => ({ ...prev, ...values })); updateUserPreferences(values); @@ -45,14 +53,16 @@ export function SettingsBehavior() { } /> - { - handleChange({ runAtStartup: !form.runAtStartup }); - window.electron.autoLaunch(!form.runAtStartup); - }} - checked={form.runAtStartup} - /> + {showRunAtStartup && ( + { + handleChange({ runAtStartup: !form.runAtStartup }); + window.electron.autoLaunch(!form.runAtStartup); + }} + checked={form.runAtStartup} + /> + )} ); }