aboutsummaryrefslogtreecommitdiffstats
path: root/src/stores
diff options
context:
space:
mode:
authorLibravatar André Oliveira <37463445+SpecialAro@users.noreply.github.com>2023-09-02 16:28:04 +0100
committerLibravatar GitHub <noreply@github.com>2023-09-02 15:28:04 +0000
commitd1c623f4c3d72c859f9ad9cb985be127d6a3eb62 (patch)
treee102da856ae328c70e822d60ac53909acd4627b9 /src/stores
parentDowngrade 'electron' to 25.x (diff)
downloadferdium-app-d1c623f4c3d72c859f9ad9cb985be127d6a3eb62.tar.gz
ferdium-app-d1c623f4c3d72c859f9ad9cb985be127d6a3eb62.tar.zst
ferdium-app-d1c623f4c3d72c859f9ad9cb985be127d6a3eb62.zip
feat: Add Download Manager (pause, stop, delete) (#1339)
Diffstat (limited to 'src/stores')
-rw-r--r--src/stores/AppStore.ts104
-rw-r--r--src/stores/UIStore.ts7
2 files changed, 111 insertions, 0 deletions
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts
index b317d99fc..1c1336819 100644
--- a/src/stores/AppStore.ts
+++ b/src/stores/AppStore.ts
@@ -61,6 +61,22 @@ const CATALINA_NOTIFICATION_HACK_KEY =
61 61
62const locales = generatedTranslations(); 62const locales = generatedTranslations();
63 63
64interface Download {
65 id: string;
66 serviceId: string;
67 filename: string;
68 url: string;
69 savePath?: string;
70 state?: 'progressing' | 'interrupted' | 'completed' | 'cancelled';
71 paused?: boolean;
72 canResume?: boolean;
73 progress?: number;
74 totalBytes?: number;
75 receivedBytes?: number;
76 startTime?: number;
77 endTime?: number;
78}
79
64export default class AppStore extends TypedStore { 80export default class AppStore extends TypedStore {
65 updateStatusTypes = { 81 updateStatusTypes = {
66 CHECKING: 'CHECKING', 82 CHECKING: 'CHECKING',
@@ -114,6 +130,10 @@ export default class AppStore extends TypedStore {
114 130
115 fetchDataInterval: null | NodeJS.Timer = null; 131 fetchDataInterval: null | NodeJS.Timer = null;
116 132
133 @observable downloads: Download[] = [];
134
135 @observable justFinishedDownloading: boolean = false;
136
117 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 137 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
118 super(stores, api, actions); 138 super(stores, api, actions);
119 139
@@ -136,6 +156,14 @@ export default class AppStore extends TypedStore {
136 this._toggleCollapseMenu.bind(this), 156 this._toggleCollapseMenu.bind(this),
137 ); 157 );
138 this.actions.app.clearAllCache.listen(this._clearAllCache.bind(this)); 158 this.actions.app.clearAllCache.listen(this._clearAllCache.bind(this));
159 this.actions.app.addDownload.listen(this._addDownload.bind(this));
160 this.actions.app.removeDownload.listen(this._removeDownload.bind(this));
161 this.actions.app.updateDownload.listen(this._updateDownload.bind(this));
162 this.actions.app.endedDownload.listen(this._endedDownload.bind(this));
163 this.actions.app.stopDownload.listen(this._stopDownload.bind(this));
164 this.actions.app.togglePauseDownload.listen(
165 this._togglePauseDownload.bind(this),
166 );
139 167
140 this.registerReactions([ 168 this.registerReactions([
141 this._offlineCheck.bind(this), 169 this._offlineCheck.bind(this),
@@ -300,6 +328,10 @@ export default class AppStore extends TypedStore {
300 return this.getAppCacheSizeRequest.execute().result; 328 return this.getAppCacheSizeRequest.execute().result;
301 } 329 }
302 330
331 @computed get isDownloading() {
332 return this.downloads.some(download => download.state === 'progressing');
333 }
334
303 @computed get debugInfo() { 335 @computed get debugInfo() {
304 const settings = cleanseJSObject(this.stores.settings.app); 336 const settings = cleanseJSObject(this.stores.settings.app);
305 settings.lockedPassword = '******'; 337 settings.lockedPassword = '******';
@@ -518,6 +550,78 @@ export default class AppStore extends TypedStore {
518 this.locale = value; 550 this.locale = value;
519 } 551 }
520 552
553 @action _addDownload(download: Download) {
554 this.downloads.unshift(download);
555 debug('Download added', this.downloads);
556 }
557
558 @action _removeDownload(id: string | null) {
559 debug(`Removed download ${id}`);
560 if (id === null) {
561 const indexesToRemove: number[] = [];
562 this.downloads.map(item => {
563 if (!item.state) return;
564 if (item.state === 'completed' || item.state === 'cancelled') {
565 indexesToRemove.push(this.downloads.indexOf(item));
566 }
567 });
568
569 if (indexesToRemove.length === 0) return;
570
571 this.downloads = this.downloads.filter(
572 (_, index) => !indexesToRemove.includes(index),
573 );
574
575 debug('Removed all completed downloads');
576 return;
577 }
578
579 const index = this.downloads.findIndex(item => item.id === id);
580 if (index !== -1) {
581 this.downloads.splice(index, 1);
582 }
583
584 debug(`Removed download ${id}`);
585 }
586
587 @action _updateDownload(download: Download) {
588 const index = this.downloads.findIndex(item => item.id === download.id);
589 if (index !== -1) {
590 this.downloads[index] = { ...this.downloads[index], ...download };
591 }
592
593 debug('Download updated', this.downloads[index]);
594 }
595
596 @action _endedDownload(download: Download) {
597 const index = this.downloads.findIndex(item => item.id === download.id);
598 if (index !== -1) {
599 this.downloads[index] = { ...this.downloads[index], ...download };
600 }
601
602 debug('Download ended', this.downloads[index]);
603
604 if (!this.isDownloading && download.state === 'completed') {
605 this.justFinishedDownloading = true;
606
607 setTimeout(() => {
608 this.justFinishedDownloading = false;
609 }, ms('2s'));
610 }
611 }
612
613 @action _stopDownload(downloadId: string | undefined) {
614 ipcRenderer.send('stop-download', {
615 downloadId,
616 });
617 }
618
619 @action _togglePauseDownload(downloadId: string | undefined) {
620 ipcRenderer.send('toggle-pause-download', {
621 downloadId,
622 });
623 }
624
521 _setLocale() { 625 _setLocale() {
522 if (this.stores.user?.isLoggedIn && this.stores.user?.data.locale) { 626 if (this.stores.user?.isLoggedIn && this.stores.user?.data.locale) {
523 this._changeLocale(this.stores.user.data.locale); 627 this._changeLocale(this.stores.user.data.locale);
diff --git a/src/stores/UIStore.ts b/src/stores/UIStore.ts
index 4ed45fc3b..a3330c2e6 100644
--- a/src/stores/UIStore.ts
+++ b/src/stores/UIStore.ts
@@ -18,6 +18,7 @@ export default class UIStore extends TypedStore {
18 makeObservable(this); 18 makeObservable(this);
19 19
20 // Register action handlers 20 // Register action handlers
21 this.actions.ui.openDownloads.listen(this._openDownloads.bind(this));
21 this.actions.ui.openSettings.listen(this._openSettings.bind(this)); 22 this.actions.ui.openSettings.listen(this._openSettings.bind(this));
22 this.actions.ui.closeSettings.listen(this._closeSettings.bind(this)); 23 this.actions.ui.closeSettings.listen(this._closeSettings.bind(this));
23 this.actions.ui.toggleServiceUpdatedInfoBar.listen( 24 this.actions.ui.toggleServiceUpdatedInfoBar.listen(
@@ -97,6 +98,12 @@ export default class UIStore extends TypedStore {
97 } 98 }
98 99
99 // Actions 100 // Actions
101 @action _openDownloads({ path = '/downloadmanager' }): void {
102 const downloadsPath =
103 path === '/downloadmanager' ? path : `/downloadmanager/${path}`;
104 this.stores.router.push(downloadsPath);
105 }
106
100 @action _openSettings({ path = '/settings' }): void { 107 @action _openSettings({ path = '/settings' }): void {
101 const settingsPath = path === '/settings' ? path : `/settings/${path}`; 108 const settingsPath = path === '/settings' ? path : `/settings/${path}`;
102 this.stores.router.push(settingsPath); 109 this.stores.router.push(settingsPath);