Add download pausing, canceling and resuming

This commit is contained in:
Lncvrt committed 2026-03-10 21:22:24 -07:00
1 parent 0b4e639630
commit 4054fdd06b
6 files changed
+317 -91

No files matched your search

+4
View File
@@ -14,6 +14,7 @@ body {
--col6: rgb(96, 96, 96);
--col7: rgb(112, 112, 112);
--col8: rgb(128, 128, 128);
--col9: rgb(144, 144, 144);
}
.red-theme {
@@ -26,6 +27,7 @@ body {
--col6: rgb(120, 96, 96);
--col7: rgb(136, 112, 112);
--col8: rgb(152, 128, 128);
--col9: rgb(168, 144, 144);
}
.blue-theme {
@@ -38,6 +40,7 @@ body {
--col6: rgb(96, 96, 120);
--col7: rgb(112, 112, 136);
--col8: rgb(128, 128, 152);
--col9: rgb(144, 144, 168);
}
.purple-theme {
@@ -50,6 +53,7 @@ body {
--col6: rgb(108, 96, 120);
--col7: rgb(124, 112, 136);
--col8: rgb(140, 128, 152);
--col9: rgb(156, 144, 168);
}
.button {
+74 -3
View File
@@ -228,7 +228,7 @@ export default function RootLayout ({
const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev
const copy = [...prev]
copy[i] = { ...copy[i], hash_checking: true }
copy[i] = { ...copy[i], hash_checking: true, downloading: false }
return copy
})
})
@@ -266,6 +266,58 @@ export default function RootLayout ({
})
})
)
unlisteners.push(
await listen<string>('download-start', event => {
const displayName = event.payload
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev
const copy = [...prev]
copy[i] = {
...copy[i],
downloading: true,
paused: false,
failed: false
}
return copy
})
})
)
unlisteners.push(
await listen<string>('download-stop', event => {
const displayName = event.payload
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev
const copy = [...prev]
copy[i] = { ...copy[i], downloading: false }
return copy
})
})
)
unlisteners.push(
await listen<string>('download-cancelled', event => {
const displayName = event.payload
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === displayName)
if (i === -1) return prev
if (prev[i].canceled) {
return prev.filter((_, idx) => idx !== i)
}
const copy = [...prev]
copy[i] = {
...copy[i],
downloading: false,
paused: true,
failed: false
}
return copy
})
})
)
}
setupListeners()
@@ -349,6 +401,9 @@ export default function RootLayout ({
0,
0,
false,
false,
false,
false,
true,
false,
0,
@@ -356,7 +411,10 @@ export default function RootLayout ({
0,
false,
0,
0
0,
null,
null,
null
)
)
@@ -424,6 +482,19 @@ export default function RootLayout ({
return
}
setDownloadProgress(prev =>
prev.map(d =>
d.version === versionId
? {
...d,
url: data.data.url,
executable: info.executable,
hash: data.data.hash
}
: d
)
)
const res = await invoke<string>('download', {
url: data.data.url,
name: info.id,
@@ -447,7 +518,7 @@ export default function RootLayout ({
writeVersionsConfig(updated)
return updated
})
} else {
} else if (res !== '0') {
setDownloadProgress(prev =>
prev.map(d =>
d.version === versionId
+59 -1
View File
@@ -2,6 +2,9 @@ import { useGlobal } from '@/app/GlobalProvider'
import prettyBytes from 'pretty-bytes'
import ProgressBar from '../ProgressBar'
import { formatEtaSmart } from '@/lib/Util'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCancel, faPause, faPlay } from '@fortawesome/free-solid-svg-icons'
import { invoke } from '@tauri-apps/api/core'
export default function DownloadsPopup () {
const {
@@ -19,7 +22,62 @@ export default function DownloadsPopup () {
{downloadProgress.map((v, i) => {
const queuePosition = downloadQueue.indexOf(v.version)
return (
<div key={i} className='popup-entry flex flex-col justify-between'>
<div
key={i}
className='popup-entry flex flex-col justify-between relative'
>
<div className='absolute right-2 top-2 flex flex-row gap-2'>
<div
className='cursor-pointer bg-(--col5) hover:bg-(--col7) border border-(--col7) hover:border-(--col9) transition-colors w-8 h-8 flex items-center justify-center rounded-full'
hidden={!v.downloading}
onClick={async () => {
await invoke('cancel_download', { name: v.version })
}}
>
<FontAwesomeIcon icon={faPause} className='w-6 h-6' />
</div>
<div
className='cursor-pointer bg-(--col5) hover:bg-(--col7) border border-(--col7) hover:border-(--col9) transition-colors w-8 h-8 flex items-center justify-center rounded-full'
hidden={!v.paused}
onClick={async () => {
await invoke<string>('download', {
url: v.url,
name: v.version,
executable: v.executable,
hash: v.hash
})
}}
>
<FontAwesomeIcon icon={faPlay} className='w-6 h-6' />
</div>
<div
className='cursor-pointer bg-(--col5) hover:bg-(--col7) border border-(--col7) hover:border-(--col9) transition-colors w-8 h-8 flex items-center justify-center rounded-full'
hidden={!v.downloading && !v.paused}
onClick={async () => {
if (!v.paused) {
await invoke('cancel_download', { name: v.version })
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === v.version)
if (i === -1) return prev
const copy = [...prev]
copy[i] = {
...copy[i],
canceled: true
}
return copy
})
} else {
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === v.version)
if (i === -1) return prev
return prev.filter((_, idx) => idx !== i)
})
}
}}
>
<FontAwesomeIcon icon={faCancel} className='w-6 h-6' />
</div>
</div>
<p className='text-2xl text-center'>
{getVersionInfo(v.version)?.displayName}
</p>
+7 -1
View File
@@ -4,6 +4,9 @@ export class DownloadProgress {
public progress: number,
public progressBytes: number,
public failed: boolean,
public downloading: boolean,
public paused: boolean,
public canceled: boolean,
public queued: boolean,
public hash_checking: boolean,
public speed: number,
@@ -11,6 +14,9 @@ export class DownloadProgress {
public etaSecs: number,
public unzipping: boolean,
public unzipTotal: number,
public unzipped: number
public unzipped: number,
public url: string | null,
public executable: string | null,
public hash: string | null
) {}
}