@@ -26,13 +26,19 @@ import { injectAppEvents } from '@/providers/app-events'
2626
2727import { debugInfoExports , type DebugInfoExportTask } from './debug-info-export'
2828import { createDownloadTransferTracker } from './download-transfer'
29+ import {
30+ externalFileDownloads ,
31+ type ExternalFileDownloadTask ,
32+ getExternalFileDownloadRate ,
33+ } from './external-file-downloads'
2934import { createInstallJobProgressTracker } from './install-job-progress'
3035import { storeVerificationTask } from './store-verification'
3136import { useInstallJobDisplay } from './use-install-job-display'
3237
3338export interface DownloadManagerJob {
3439 id : string
35- kind ?: 'debug-export'
40+ kind ?: 'external-file' | 'debug-export'
41+ serverId ?: string
3642 createdAt ?: string
3743 instanceId : string | null
3844 status : InstallJobSnapshot [ 'status' ]
@@ -69,6 +75,13 @@ const verificationMessages = defineMessages({
6975 } ,
7076} )
7177
78+ const fileMessages = defineMessages ( {
79+ preparing : { id : 'app.file-download.preparing' , defaultMessage : 'Preparing download…' } ,
80+ waiting : { id : 'app.file-download.waiting' , defaultMessage : 'Waiting for the server…' } ,
81+ canceling : { id : 'app.file-download.canceling' , defaultMessage : 'Canceling download…' } ,
82+ canceled : { id : 'app.action-bar.install.summary.canceled' , defaultMessage : 'Canceled' } ,
83+ } )
84+
7285const debugExportMessages = defineMessages ( {
7386 canceled : { id : 'app.action-bar.install.summary.canceled' , defaultMessage : 'Canceled' } ,
7487 title : {
@@ -167,12 +180,14 @@ export function useDownloadManager() {
167180 const task = storeVerificationTask . value
168181 return task ? [ buildVerificationRow ( task ) ] : [ ]
169182 } )
183+ const fileRows = computed ( ( ) => [ ...externalFileDownloads . value . values ( ) ] . map ( buildFileRow ) )
170184 const debugExportRows = computed ( ( ) =>
171185 [ ...debugInfoExports . value . values ( ) ] . map ( buildDebugExportRow ) ,
172186 )
173187 const allRows = computed ( ( ) => [
174188 ...rows . value ,
175189 ...verificationRows . value ,
190+ ...fileRows . value ,
176191 ...debugExportRows . value ,
177192 ] )
178193
@@ -197,10 +212,11 @@ export function useDownloadManager() {
197212 )
198213 const rate = computed ( ( ) =>
199214 display . formatRate (
200- activeJobs . value . reduce (
201- ( total , job ) => total + ( transfer . get ( job . id , now . value ) . rate ?? 0 ) ,
202- 0 ,
203- ) ,
215+ activeJobs . value . reduce ( ( total , job ) => {
216+ const file = externalFileDownloads . value . get ( job . id )
217+ const fileRate = file ? getExternalFileDownloadRate ( file , now . value ) : null
218+ return total + ( fileRate ?? transfer . get ( job . id , now . value ) . rate ?? 0 )
219+ } , 0 ) ,
204220 ) ,
205221 )
206222
@@ -246,6 +262,68 @@ export function useDownloadManager() {
246262 }
247263 }
248264
265+ function buildFileRow ( task : ExternalFileDownloadTask ) : DownloadManagerJob {
266+ const rate = getExternalFileDownloadRate ( task , now . value )
267+ const progress = task . totalBytes ? Math . min ( 0.99 , task . downloadedBytes / task . totalBytes ) : 0
268+ const text =
269+ task . error ??
270+ formatMessage (
271+ task . canceling
272+ ? fileMessages . canceling
273+ : task . status === 'canceled'
274+ ? fileMessages . canceled
275+ : task . status === 'succeeded'
276+ ? commonMessages . savedLabel
277+ : task . stage === 'preparing'
278+ ? fileMessages . preparing
279+ : task . stage === 'waiting'
280+ ? fileMessages . waiting
281+ : task . stage === 'saving'
282+ ? commonMessages . savingButton
283+ : commonMessages . downloadingButton ,
284+ )
285+
286+ return {
287+ id : task . id ,
288+ kind : 'external-file' ,
289+ serverId : task . serverId ,
290+ createdAt : task . createdAt ,
291+ instanceId : null ,
292+ status : task . status ,
293+ paused : false ,
294+ canceling : task . canceling ,
295+ canPause : false ,
296+ canCancel : task . status === 'running' && task . stage !== 'saving' ,
297+ title : task . serverName ?? task . filename ,
298+ iconUrl : null ,
299+ text,
300+ taskType : task . filename ,
301+ finishedAt : task . finishedAt ,
302+ progress,
303+ overallProgress : task . status === 'succeeded' ? 1 : progress ,
304+ progressLabel :
305+ task . status === 'running' && ( task . stage === 'downloading' || task . stage === 'saving' )
306+ ? [
307+ task . totalBytes
308+ ? `${ formatBytes ( task . downloadedBytes ) } / ${ formatBytes ( task . totalBytes ) } `
309+ : formatBytes ( task . downloadedBytes ) ,
310+ display . formatRate ( rate ) ,
311+ ]
312+ . filter ( Boolean )
313+ . join ( ' · ' )
314+ : '' ,
315+ waiting : task . stage !== 'downloading' || ! task . totalBytes ,
316+ eta :
317+ rate && task . totalBytes
318+ ? display . formatEta ( ( task . totalBytes - task . downloadedBytes ) / rate )
319+ : '' ,
320+ canRetry : false ,
321+ canCopyDetails : ! ! task . error ,
322+ copied : copiedJobs . value . has ( task . id ) ,
323+ busy : busyJobs . value . has ( task . id ) ,
324+ }
325+ }
326+
249327 function buildVerificationRow (
250328 task : NonNullable < typeof storeVerificationTask . value > ,
251329 ) : DownloadManagerJob {
@@ -387,6 +465,11 @@ export function useDownloadManager() {
387465 await runAction ( id , debugExport . cancel )
388466 return
389467 }
468+ const file = externalFileDownloads . value . get ( id )
469+ if ( file ) {
470+ await runAction ( id , file . cancel )
471+ return
472+ }
390473 if ( ! jobs . value . get ( id ) ?. can_cancel ) return
391474 await runJobAction ( id , ( ) => install_job_cancel ( id ) )
392475 }
@@ -403,6 +486,11 @@ export function useDownloadManager() {
403486 if ( debugExport . status !== 'running' ) debugInfoExports . value . delete ( id )
404487 return
405488 }
489+ const file = externalFileDownloads . value . get ( id )
490+ if ( file ) {
491+ if ( file . status !== 'running' ) externalFileDownloads . value . delete ( id )
492+ return
493+ }
406494 if ( storeVerificationTask . value ?. id === id ) {
407495 if ( storeVerificationTask . value . status !== 'running' ) storeVerificationTask . value = null
408496 return
@@ -424,10 +512,8 @@ export function useDownloadManager() {
424512
425513 async function copyDetails ( id : string ) {
426514 await runAction ( id , async ( ) => {
427- const debugExport = debugInfoExports . value . get ( id )
428- const details = debugExport
429- ? ( debugExport . error ?? '' )
430- : await install_job_support_details ( id )
515+ const file = externalFileDownloads . value . get ( id ) ?? debugInfoExports . value . get ( id )
516+ const details = file ? ( file . error ?? '' ) : await install_job_support_details ( id )
431517 if ( disposed ) return
432518 await navigator . clipboard . writeText ( details )
433519 if ( disposed ) return
0 commit comments