Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Turn computer off when all downloads have finished #3685

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
11 changes: 10 additions & 1 deletion public/locales/ar/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,16 @@
"type": "النوع"
},
"title": "التنزيلات",
"ETA": "الوقت المقدَّر"
"ETA": "الوقت المقدَّر",
sassou5018 marked this conversation as resolved.
Show resolved Hide resolved
"auto-shutdown": {
"label": "أوقف الجهاز تلقائيًا عند انتهاء جميع التنزيلات بنجاح",
"description": "سيؤدي هذا إلى إيقاف تشغيل الجهاز عند انتهاء جميع التنزيلات بنجاح",
"cancellationPrompt": {
"title": "سيتم إيقاف التشغيل تلقائيًا في 10 ثوانٍ",
"message": "هل تريد إلغاء إيقاف التشغيل؟",
"cancel": "إلغاء إيقاف التشغيل"
}
}
},
"epic": {
"offline-notification-body": "قد لا تعمل الخدمات عبر الإنترنت بشكل كامل لأن خوادم أَبِك جيمز غير متصلة بالإنترنت!",
Expand Down
11 changes: 10 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,16 @@
"start-time": "Started at",
"type": "Type"
},
"title": "Downloads"
"title": "Downloads",
"auto-shutdown": {
"label": "Automatically shutdown machine when all downloads are finished",
"description": "This will shutdown the machine when all downloads are successfully finished.",
"cancellationPrompt": {
"title": "Automatically shutting down in 10 seconds...",
"message": "Do you want to cancel the shutdown?",
"cancel": "Cancel shutdown"
}
}
},
"emptyLibrary": {
"noGames": "Your library is empty. You can <1>log in</1> using a store or click <3></3> to add one manually.",
Expand Down
11 changes: 10 additions & 1 deletion public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,16 @@
"type": "Type"
},
"title": "Téléchargements",
"ETA": "Temps estimé"
"ETA": "Temps estimé",
"auto-shutdown": {
"label": "Arrêt automatique",
"description": "Cela éteindra la machine lorsque tous les téléchargements seront terminés avec succès.",
"cancellationPrompt": {
"title": "Arrêt automatique dans 10s...",
"message": "Voulez vous annuler l'arrêt automatique ?",
"cancel": "Annuler l'arrêt"
}
}
},
"epic": {
"offline-notification-body": "Les services en ligne peuvent ne pas entièrement fonctionner car les serveurs d'Epic Games sont hors ligne !",
Expand Down
6 changes: 6 additions & 0 deletions src/backend/api/downloadmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,9 @@ export const resumeCurrentDownload = () =>

export const pauseCurrentDownload = () =>
ipcRenderer.send('pauseCurrentDownload')

export const setAutoShutdown = (value: boolean) =>
ipcRenderer.send('setAutoShutdown', value)

export const getAutoShutdownValue = async () =>
ipcRenderer.invoke('getAutoShutdownValue')
49 changes: 48 additions & 1 deletion src/backend/downloadmanager/downloadqueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import i18next from 'i18next'
import { createRedistDMQueueElement } from 'backend/storeManagers/gog/redist'
import { existsSync } from 'fs'
import { gogRedistPath } from 'backend/constants'
import { shutdown } from 'backend/utils/os/shutdown'
import { dialog } from 'electron'

const downloadManager = new TypeCheckedStoreBackend('downloadManager', {
cwd: 'store',
Expand All @@ -23,6 +25,7 @@ const downloadManager = new TypeCheckedStoreBackend('downloadManager', {

let queueState: DownloadManagerState = 'idle'
let currentElement: DMQueueElement | null = null
let didReallyDownload = false

function getFirstQueueElement() {
const elements = downloadManager.get('queue', [])
Expand Down Expand Up @@ -84,6 +87,7 @@ async function initQueue() {
? await installQueueElement(element.params)
: await updateQueueElement(element.params)
element.endTime = Date.now()
didReallyDownload = status === 'done'

processNotification(element, status)

Expand All @@ -97,6 +101,39 @@ async function initQueue() {
}

queueState = 'idle'
if (!isPaused() && isIdle() && getAutoShutdown() && didReallyDownload) {
logInfo(
'Auto shutdown enabled. Shutting down in 10s...',
LogPrefix.DownloadManager
)
dialog
.showMessageBox({
title: i18next.t(
'download-manager.auto-shutdown.cancellationPrompt.title',
'Automatically shutting down in 10 seconds...'
),
message: i18next.t(
'download-manager.auto-shutdown.cancellationPrompt.message',
'Do you want to cancel the shutdown?'
),
buttons: [
i18next.t(
'download-manager.auto-shutdown.cancellationPrompt.cancel',
'Cancel shutdown'
)
]
})
.then((result) => {
if (result.response === 0) {
logInfo('Shutdown cancelled by user', LogPrefix.DownloadManager)
setAutoShutdown(false)
}
})

setTimeout(() => {
getAutoShutdown() ? shutdown() : null
}, 10000)
}
sassou5018 marked this conversation as resolved.
Show resolved Hide resolved
}

async function addToQueue(element: DMQueueElement) {
Expand Down Expand Up @@ -251,6 +288,14 @@ function resumeCurrentDownload() {
initQueue()
}

function getAutoShutdown(): boolean {
return downloadManager.get('autoShutdown', false)
}

function setAutoShutdown(value: boolean) {
downloadManager.set('autoShutdown', value)
}

function stopCurrentDownload() {
const { appName, runner } = currentElement!.params
callAbortController(appName)
Expand Down Expand Up @@ -318,5 +363,7 @@ export {
getQueueInformation,
cancelCurrentDownload,
pauseCurrentDownload,
resumeCurrentDownload
resumeCurrentDownload,
setAutoShutdown,
getAutoShutdown
}
10 changes: 9 additions & 1 deletion src/backend/downloadmanager/ipc_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import { ipcMain } from 'electron'
import {
addToQueue,
cancelCurrentDownload,
getAutoShutdown,
getQueueInformation,
pauseCurrentDownload,
removeFromQueue,
resumeCurrentDownload
resumeCurrentDownload,
setAutoShutdown
} from './downloadqueue'

ipcMain.handle('addToDMQueue', async (e, element) => {
await addToQueue(element)
})

ipcMain.on('setAutoShutdown', (e, value: boolean) => {
setAutoShutdown(value)
})

ipcMain.on('removeFromDMQueue', (e, appName) => {
removeFromQueue(appName)
})
Expand All @@ -29,3 +35,5 @@ ipcMain.on('cancelDownload', (e, removeDownloaded) => {
})

ipcMain.handle('getDMQueueInformation', getQueueInformation)

ipcMain.handle('getAutoShutdownValue', getAutoShutdown)
25 changes: 25 additions & 0 deletions src/backend/utils/os/shutdown/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { exec } from 'child_process'

/**
* Shuts down the system.
*/
export const shutdown = async () => {
switch (process.platform) {
case 'win32': {
exec('shutdown /s /t 0')
break
}
case 'linux': {
exec('shutdown now')
break
}
case 'darwin': {
exec('shutdown -h now')
break
}
default: {
console.log('Unsupported OS')
break
}
}
}
2 changes: 2 additions & 0 deletions src/common/typedefs/ipcBridge.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ interface SyncIPCFunctions {
addShortcut: (appName: string, runner: Runner, fromMenu: boolean) => void
removeShortcut: (appName: string, runner: Runner) => void
removeFromDMQueue: (appName: string) => void
setAutoShutdown: (value: boolean) => void
clearDMFinished: () => void
abort: (id: string) => void
'connectivity-changed': (newStatus: ConnectivityStatus) => void
Expand Down Expand Up @@ -256,6 +257,7 @@ interface AsyncIPCFunctions {
finished: DMQueueElement[]
state: DownloadManagerState
}
getAutoShutdownValue: () => boolean
'get-connectivity-status': () => {
status: ConnectivityStatus
retryIn: number
Expand Down
1 change: 1 addition & 0 deletions src/common/types/electron_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export interface StoreStructure {
downloadManager: {
queue: DMQueueElement[]
finished: DMQueueElement[]
autoShutdown: boolean
}
gogSyncStore: {
[appName: string]: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ToggleSwitch } from 'frontend/components/UI'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'

export default function DownloadManagerFooter() {
const { t } = useTranslation()
const [autoShutdown, setAutoShutdown] = useState(false)
useEffect(() => {
window.api.getAutoShutdownValue().then((value) => {
setAutoShutdown(value)
})
}, [])

const handleAutoShutdown = () => {
setAutoShutdown((prev) => {
window.api.setAutoShutdown(!prev)
return !prev
})
}
return (
<div className="autoShutdown">
<ToggleSwitch
handleChange={handleAutoShutdown}
value={autoShutdown}
title={t(
'download-manager.auto-shutdown.label',
'Automatically shutdown machine when all downloads are finished'
)}
description={t(
'download-manager.auto-shutdown.description',
'This will shutdown the machine when all downloads are successfully finished.'
)}
htmlId="autoshutdowntoggle"
/>
</div>
)
}
6 changes: 6 additions & 0 deletions src/frontend/screens/DownloadManager/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,9 @@
border-radius: 6px;
margin: var(--space-3xs) var(--space-lg);
}

.autoShutdown {
padding: var(--space-md) 0;
grid-template-columns: 2fr 1fr 1fr 1fr 10%;
margin: 0 var(--space-sm-fixed);
}
3 changes: 3 additions & 0 deletions src/frontend/screens/DownloadManager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { downloadManagerStore } from 'frontend/helpers/electronStores'
import { DMQueue } from 'frontend/types'
import DownloadManagerItem from './components/DownloadManagerItem'
import { hasHelp } from 'frontend/hooks/hasHelp'
import DownloadManagerFooter from './DownloadManagerFooter'

export default React.memo(function DownloadManager(): JSX.Element | null {
const { t } = useTranslation()
Expand Down Expand Up @@ -181,6 +182,8 @@ export default React.memo(function DownloadManager(): JSX.Element | null {
</div>
</div>
)}
{/* Currently only has auto shutdown switch */}
<DownloadManagerFooter />
</>
)
})
Loading