Add wakelock feature to prevent system sleep while Goose is working (#3321)
Signed-off-by: Simon Sickle <51972200+simonsickle@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,7 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
|
|||||||
const [menuBarIconEnabled, setMenuBarIconEnabled] = useState(true);
|
const [menuBarIconEnabled, setMenuBarIconEnabled] = useState(true);
|
||||||
const [dockIconEnabled, setDockIconEnabled] = useState(true);
|
const [dockIconEnabled, setDockIconEnabled] = useState(true);
|
||||||
const [quitConfirmationEnabled, setQuitConfirmationEnabled] = useState(true);
|
const [quitConfirmationEnabled, setQuitConfirmationEnabled] = useState(true);
|
||||||
|
const [wakelockEnabled, setWakelockEnabled] = useState(true);
|
||||||
const [isMacOS, setIsMacOS] = useState(false);
|
const [isMacOS, setIsMacOS] = useState(false);
|
||||||
const [isDockSwitchDisabled, setIsDockSwitchDisabled] = useState(false);
|
const [isDockSwitchDisabled, setIsDockSwitchDisabled] = useState(false);
|
||||||
const [showNotificationModal, setShowNotificationModal] = useState(false);
|
const [showNotificationModal, setShowNotificationModal] = useState(false);
|
||||||
@@ -147,6 +148,10 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
|
|||||||
setQuitConfirmationEnabled(enabled);
|
setQuitConfirmationEnabled(enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.electron.getWakelockState().then((enabled) => {
|
||||||
|
setWakelockEnabled(enabled);
|
||||||
|
});
|
||||||
|
|
||||||
if (isMacOS) {
|
if (isMacOS) {
|
||||||
window.electron.getDockIconState().then((enabled) => {
|
window.electron.getDockIconState().then((enabled) => {
|
||||||
setDockIconEnabled(enabled);
|
setDockIconEnabled(enabled);
|
||||||
@@ -202,6 +207,14 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleWakelockToggle = async () => {
|
||||||
|
const newState = !wakelockEnabled;
|
||||||
|
const success = await window.electron.setWakelock(newState);
|
||||||
|
if (success) {
|
||||||
|
setWakelockEnabled(newState);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleShowPricingToggle = (checked: boolean) => {
|
const handleShowPricingToggle = (checked: boolean) => {
|
||||||
setShowPricing(checked);
|
setShowPricing(checked);
|
||||||
localStorage.setItem('show_pricing', String(checked));
|
localStorage.setItem('show_pricing', String(checked));
|
||||||
@@ -299,6 +312,23 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Prevent Sleep */}
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-text-default text-xs">Prevent Sleep</h3>
|
||||||
|
<p className="text-xs text-text-muted max-w-md mt-[2px]">
|
||||||
|
Keep your computer awake while Goose is running a task (screen can still lock)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Switch
|
||||||
|
checked={wakelockEnabled}
|
||||||
|
onCheckedChange={handleWakelockToggle}
|
||||||
|
variant="mono"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Cost Tracking */}
|
{/* Cost Tracking */}
|
||||||
{COST_TRACKING_ENABLED && (
|
{COST_TRACKING_ENABLED && (
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
|||||||
+35
-7
@@ -494,6 +494,9 @@ let appConfig = {
|
|||||||
let windowCounter = 0;
|
let windowCounter = 0;
|
||||||
const windowMap = new Map<number, BrowserWindow>();
|
const windowMap = new Map<number, BrowserWindow>();
|
||||||
|
|
||||||
|
// Track power save blocker ID globally
|
||||||
|
let powerSaveBlockerId: number | null = null;
|
||||||
|
|
||||||
interface RecipeConfig {
|
interface RecipeConfig {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
@@ -1090,6 +1093,36 @@ ipcMain.handle('get-quit-confirmation-state', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle wakelock setting
|
||||||
|
ipcMain.handle('set-wakelock', async (_event, enable: boolean) => {
|
||||||
|
try {
|
||||||
|
const settings = loadSettings();
|
||||||
|
settings.enableWakelock = enable;
|
||||||
|
saveSettings(settings);
|
||||||
|
|
||||||
|
// Stop any existing power save blocker when disabling the setting
|
||||||
|
if (!enable && powerSaveBlockerId !== null) {
|
||||||
|
powerSaveBlocker.stop(powerSaveBlockerId);
|
||||||
|
powerSaveBlockerId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error setting wakelock:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('get-wakelock-state', () => {
|
||||||
|
try {
|
||||||
|
const settings = loadSettings();
|
||||||
|
return settings.enableWakelock ?? false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting wakelock state:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Add file/directory selection handler
|
// Add file/directory selection handler
|
||||||
ipcMain.handle('select-file-or-directory', async () => {
|
ipcMain.handle('select-file-or-directory', async () => {
|
||||||
const result = (await dialog.showOpenDialog({
|
const result = (await dialog.showOpenDialog({
|
||||||
@@ -1889,24 +1922,19 @@ app.whenReady().then(async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let powerSaveBlockerId: number | null = null;
|
|
||||||
|
|
||||||
ipcMain.handle('start-power-save-blocker', () => {
|
ipcMain.handle('start-power-save-blocker', () => {
|
||||||
log.info('Starting power save blocker...');
|
|
||||||
if (powerSaveBlockerId === null) {
|
if (powerSaveBlockerId === null) {
|
||||||
powerSaveBlockerId = powerSaveBlocker.start('prevent-display-sleep');
|
powerSaveBlockerId = powerSaveBlocker.start('prevent-app-suspension');
|
||||||
log.info('Started power save blocker');
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('stop-power-save-blocker', () => {
|
ipcMain.handle('stop-power-save-blocker', () => {
|
||||||
log.info('Stopping power save blocker...');
|
|
||||||
if (powerSaveBlockerId !== null) {
|
if (powerSaveBlockerId !== null) {
|
||||||
powerSaveBlocker.stop(powerSaveBlockerId);
|
powerSaveBlocker.stop(powerSaveBlockerId);
|
||||||
powerSaveBlockerId = null;
|
powerSaveBlockerId = null;
|
||||||
log.info('Stopped power save blocker');
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ type ElectronAPI = {
|
|||||||
setSchedulingEngine: (engine: string) => Promise<boolean>;
|
setSchedulingEngine: (engine: string) => Promise<boolean>;
|
||||||
setQuitConfirmation: (show: boolean) => Promise<boolean>;
|
setQuitConfirmation: (show: boolean) => Promise<boolean>;
|
||||||
getQuitConfirmationState: () => Promise<boolean>;
|
getQuitConfirmationState: () => Promise<boolean>;
|
||||||
|
setWakelock: (enable: boolean) => Promise<boolean>;
|
||||||
|
getWakelockState: () => Promise<boolean>;
|
||||||
openNotificationsSettings: () => Promise<boolean>;
|
openNotificationsSettings: () => Promise<boolean>;
|
||||||
on: (
|
on: (
|
||||||
channel: string,
|
channel: string,
|
||||||
@@ -176,6 +178,8 @@ const electronAPI: ElectronAPI = {
|
|||||||
setSchedulingEngine: (engine: string) => ipcRenderer.invoke('set-scheduling-engine', engine),
|
setSchedulingEngine: (engine: string) => ipcRenderer.invoke('set-scheduling-engine', engine),
|
||||||
setQuitConfirmation: (show: boolean) => ipcRenderer.invoke('set-quit-confirmation', show),
|
setQuitConfirmation: (show: boolean) => ipcRenderer.invoke('set-quit-confirmation', show),
|
||||||
getQuitConfirmationState: () => ipcRenderer.invoke('get-quit-confirmation-state'),
|
getQuitConfirmationState: () => ipcRenderer.invoke('get-quit-confirmation-state'),
|
||||||
|
setWakelock: (enable: boolean) => ipcRenderer.invoke('set-wakelock', enable),
|
||||||
|
getWakelockState: () => ipcRenderer.invoke('get-wakelock-state'),
|
||||||
openNotificationsSettings: () => ipcRenderer.invoke('open-notifications-settings'),
|
openNotificationsSettings: () => ipcRenderer.invoke('open-notifications-settings'),
|
||||||
on: (
|
on: (
|
||||||
channel: string,
|
channel: string,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface Settings {
|
|||||||
showDockIcon: boolean;
|
showDockIcon: boolean;
|
||||||
schedulingEngine: SchedulingEngine;
|
schedulingEngine: SchedulingEngine;
|
||||||
showQuitConfirmation: boolean;
|
showQuitConfirmation: boolean;
|
||||||
|
enableWakelock: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
@@ -30,6 +31,7 @@ const defaultSettings: Settings = {
|
|||||||
showDockIcon: true,
|
showDockIcon: true,
|
||||||
schedulingEngine: 'builtin-cron',
|
schedulingEngine: 'builtin-cron',
|
||||||
showQuitConfirmation: true,
|
showQuitConfirmation: true,
|
||||||
|
enableWakelock: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Settings management
|
// Settings management
|
||||||
|
|||||||
Reference in New Issue
Block a user