From db083d573acf335f4d62884d1b0e980a5ab30238 Mon Sep 17 00:00:00 2001 From: Geomitron <22552797+Geomitron@users.noreply.github.com> Date: Tue, 11 Feb 2020 20:50:51 -0500 Subject: [PATCH] Cancel, Retry, and Warning download UI --- package-lock.json | 247 +++++++++--------- package.json | 18 +- .../chart-sidebar/chart-sidebar.component.ts | 4 +- .../downloads-modal.component.html | 17 +- .../downloads-modal.component.scss | 4 + .../downloads-modal.component.ts | 31 ++- src/app/core/services/download.service.ts | 44 ++-- ...dDownloadHandler.ts => DownloadHandler.ts} | 55 +++- src/electron/ipc/download/FileDownloader.ts | 20 +- src/electron/ipc/download/FileExtractor.ts | 9 + src/electron/shared/Database.ts | 1 + src/electron/shared/IPCHandler.ts | 10 +- .../shared/interfaces/download.interface.ts | 10 +- 13 files changed, 291 insertions(+), 179 deletions(-) rename src/electron/ipc/download/{AddDownloadHandler.ts => DownloadHandler.ts} (69%) diff --git a/package-lock.json b/package-lock.json index ed1c233..231dcc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,33 +10,33 @@ "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==" }, "@angular-devkit/architect": { - "version": "0.803.24", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.24.tgz", - "integrity": "sha512-ONY/Ppzyvtb0tqgwnzQvlGlexb5nTyy58ljgL1aQLTO3cNTkpl4IQYUCTdvn61gGA+FWPAXMCCbNqOPZMsOZCQ==", + "version": "0.803.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.25.tgz", + "integrity": "sha512-usV/zEncKCKQuF6AD3pRU6N5i5fbaAux/qZb+nbOz9/2G5jrXwe5sH+y3vxbgqB83e3LqusEQCTu7/tfg6LwZg==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.24", + "@angular-devkit/core": "8.3.25", "rxjs": "6.4.0" } }, "@angular-devkit/build-angular": { - "version": "0.803.24", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.24.tgz", - "integrity": "sha512-uA789spMVghXehwAhl5zK0loY/wfxblUiL+y21T24LMCJc15a9QX5dwbXH72ioHz7qdzb/agXk7AK+foc2/0Hw==", + "version": "0.803.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.25.tgz", + "integrity": "sha512-WY0E7NgXuog3phhz5ZdutZPWQ9nbOr+omGN5KI1e8MZs1sJO4xkyaGRT8zOulkogkqJ2NboTBq3j9uSbZkcYeg==", "dev": true, "requires": { - "@angular-devkit/architect": "0.803.24", - "@angular-devkit/build-optimizer": "0.803.24", - "@angular-devkit/build-webpack": "0.803.24", - "@angular-devkit/core": "8.3.24", + "@angular-devkit/architect": "0.803.25", + "@angular-devkit/build-optimizer": "0.803.25", + "@angular-devkit/build-webpack": "0.803.25", + "@angular-devkit/core": "8.3.25", "@babel/core": "7.8.3", "@babel/preset-env": "7.8.3", - "@ngtools/webpack": "8.3.24", + "@ngtools/webpack": "8.3.25", "ajv": "6.10.2", "autoprefixer": "9.6.1", - "browserslist": "4.8.3", + "browserslist": "4.8.6", "cacache": "12.0.2", - "caniuse-lite": "1.0.30001019", + "caniuse-lite": "1.0.30001024", "circular-dependency-plugin": "5.2.0", "clean-css": "4.2.1", "copy-webpack-plugin": "5.1.1", @@ -81,12 +81,31 @@ "webpack-sources": "1.4.3", "webpack-subresource-integrity": "1.1.0-rc.6", "worker-plugin": "3.2.0" + }, + "dependencies": { + "browserslist": { + "version": "4.8.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.6.tgz", + "integrity": "sha512-ZHao85gf0eZ0ESxLfCp73GG9O/VTytYDIkIiZDlURppLTI9wErSM/5yAKEq6rcUdxBLjMELmrYUJGg5sxGKMHg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001023", + "electron-to-chromium": "^1.3.341", + "node-releases": "^1.1.47" + } + }, + "caniuse-lite": { + "version": "1.0.30001024", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001024.tgz", + "integrity": "sha512-LubRSEPpOlKlhZw9wGlLHo8ZVj6ugGU3xGUfLPneNBledSd9lIM5cCGZ9Mz/mMCJUhEt4jZpYteZNVRdJw5FRA==", + "dev": true + } } }, "@angular-devkit/build-optimizer": { - "version": "0.803.24", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.24.tgz", - "integrity": "sha512-Z+d7M+WpBq7AWWRwbxzb1l9O9qkylxnDRKxXvq3Tzjn43g+2WyspE91dMyrg1ISc+p8jgX6xKSblRLvtWqpA8w==", + "version": "0.803.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.25.tgz", + "integrity": "sha512-MiQimuEs8QeM3xo7bR3Yk1OWHHlp2pGCc2GLUMIcWhKqM+QjoRky0HoGoBazbznx292l+xjFjANvPEKbqJ2v7Q==", "dev": true, "requires": { "loader-utils": "1.2.3", @@ -94,31 +113,23 @@ "tslib": "1.10.0", "typescript": "3.5.3", "webpack-sources": "1.4.3" - }, - "dependencies": { - "typescript": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", - "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", - "dev": true - } } }, "@angular-devkit/build-webpack": { - "version": "0.803.24", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.24.tgz", - "integrity": "sha512-Bbd5KUGaE+edN0sp8K3azuqS/JTBmeWXIumdBEtqWyL6VsohX7fL+toJlSvRkj8lg02LVyozAFetXKnyaBkfCQ==", + "version": "0.803.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.25.tgz", + "integrity": "sha512-WR7HWJIWL6TB3WHG7ZFn8s0z3WlojeQlod75UIKl5i+f4OU90kp8kxcoH5G6OCXu56x5w40oIi1ve5ljjWSJkw==", "dev": true, "requires": { - "@angular-devkit/architect": "0.803.24", - "@angular-devkit/core": "8.3.24", + "@angular-devkit/architect": "0.803.25", + "@angular-devkit/core": "8.3.25", "rxjs": "6.4.0" } }, "@angular-devkit/core": { - "version": "8.3.24", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.24.tgz", - "integrity": "sha512-xpT5yg+ddGDnifryBv2sRSYtq5F3iZIS+lN/K2AhhEa50B7Z+QaCVlEzoV/IfrGd6sLArdnKYwjLHFZ0LElUuw==", + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.25.tgz", + "integrity": "sha512-l7Gqy1tMrTpRmPVlovcFX8UA3mtXRlgO8kcSsbJ9MKRKNTCcxlfsWEYY5igyDBUVh6ADkgSIu0nuk31ZGTe0lw==", "dev": true, "requires": { "ajv": "6.10.2", @@ -129,12 +140,12 @@ } }, "@angular-devkit/schematics": { - "version": "8.3.24", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.24.tgz", - "integrity": "sha512-HrwDCgw7i3GrNns0Ce5zStWkxBqlcLuDkMcLY6981jpvVzgXMIQ+YqDrJ2kD46xHh979ev7hhw1d6jwPXh85Xw==", + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.25.tgz", + "integrity": "sha512-/p1MkfursfLy+JRGXlJGPEmX55lrFCsR/2khWAVXZcMaFR3QlR/b6/zvB8I2pHFfr0/XWnYTT/BsF7rJjO3RmA==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.24", + "@angular-devkit/core": "8.3.25", "rxjs": "6.4.0" } }, @@ -153,16 +164,16 @@ } }, "@angular/cli": { - "version": "8.3.24", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.24.tgz", - "integrity": "sha512-cUB6H+BAISMdaFsstcyvC+17hOV3ET4MaVgcmgT2cL7A4vMBRBxJ0cW4r3D9c6e7m4wipyJzOUESYoIHu0cp4A==", + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.25.tgz", + "integrity": "sha512-CPJI5nnbBvvyBUFwOHfRXy/KVwsiYlcbDAeIk1klcjQjbVFYZbnY0iAhNupy9j7rPQhb7jle5oslU3TLfbqOTQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.803.24", - "@angular-devkit/core": "8.3.24", - "@angular-devkit/schematics": "8.3.24", - "@schematics/angular": "8.3.24", - "@schematics/update": "0.803.24", + "@angular-devkit/architect": "0.803.25", + "@angular-devkit/core": "8.3.25", + "@angular-devkit/schematics": "8.3.25", + "@schematics/angular": "8.3.25", + "@schematics/update": "0.803.25", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", "debug": "^4.1.1", @@ -1082,9 +1093,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001023", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", - "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "version": "1.0.30001027", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz", + "integrity": "sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg==", "dev": true }, "semver": { @@ -1216,9 +1227,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001023", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", - "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "version": "1.0.30001027", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz", + "integrity": "sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg==", "dev": true }, "semver": { @@ -2012,9 +2023,9 @@ } }, "@electron/get": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.7.2.tgz", - "integrity": "sha512-LSE4LZGMjGS9TloDx0yO44D2UTbaeKRk+QjlhWLiQlikV6J4spgDCjb6z4YIcqmPAwNzlNCnWF4dubytwI+ATA==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.7.6.tgz", + "integrity": "sha512-zlNikt6ziVLNcm4lly1L4y62fJd/eYpEBjF5DiV/VAQq2vdPjH4sbUphXt9upmHz86lAhAj8g9lTnWrxJ/KBZw==", "dev": true, "requires": { "debug": "^4.1.1", @@ -2080,12 +2091,12 @@ "dev": true }, "@ngtools/webpack": { - "version": "8.3.24", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.24.tgz", - "integrity": "sha512-OpR7t/99qNOpADayCuM67agBVdYkdbFyEEcOLaDFYh3LsefHOSSxtAGv8M77e7dguvtaljHTiVkMxgcXFsZM0Q==", + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.25.tgz", + "integrity": "sha512-yHvgxXUXlgdWijtzcRjTaUqzK+6TVK/8p7PreBR00GsLxhl4U1jQSC6yDaZUCjOaEkiczFWl4hEuC4wTU/hLdg==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.24", + "@angular-devkit/core": "8.3.25", "enhanced-resolve": "4.1.0", "rxjs": "6.4.0", "tree-kill": "1.2.2", @@ -2219,23 +2230,23 @@ } }, "@schematics/angular": { - "version": "8.3.24", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.24.tgz", - "integrity": "sha512-0nf/LgMHAvhjWS97Pl3JGMqS9/4PI+C0+vJoAo6D7ax8Fb+wuY5uD6Pb7ZqaZALlEnqTgE+FBQ1K8VBVbuwKbA==", + "version": "8.3.25", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.25.tgz", + "integrity": "sha512-/vEPtE+fvgsWPml/MVqzmlGPBujadPPNwaTuuj5Uz1aVcKeEYzLkbN8YQOpml4vxZHCF8RDwNdGiU4SZg63Jfg==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.24", - "@angular-devkit/schematics": "8.3.24" + "@angular-devkit/core": "8.3.25", + "@angular-devkit/schematics": "8.3.25" } }, "@schematics/update": { - "version": "0.803.24", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.24.tgz", - "integrity": "sha512-NvCKn3QfpRjx1EzL56q9IC9fRtDXZP4bMGs/2tj+wtdBNHgm6ZJMJ9qc4mGeztKGbDFLmnX3Xz0XawAl+KeYzQ==", + "version": "0.803.25", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.25.tgz", + "integrity": "sha512-VIlqhJsCStA3aO4llxZ7lAOvQUqppyZdrEO7f/ApIJmuofPQTkO5Hx21tnv0dyExwoqPCSIHzEu4Tmc0/TWM1A==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.24", - "@angular-devkit/schematics": "8.3.24", + "@angular-devkit/core": "8.3.25", + "@angular-devkit/schematics": "8.3.25", "@yarnpkg/lockfile": "1.1.0", "ini": "1.3.5", "pacote": "9.5.5", @@ -2328,9 +2339,9 @@ } }, "@types/node": { - "version": "8.9.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz", - "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==" + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.0.tgz", + "integrity": "sha512-JRq4kw1GQZrF90YRrp3C1kIoioAEj9PweNF2Qgp/6XZYVgXPl7OWKdggFNtRxlBPyl40Fz/bOhCnXuKMFaJ06w==" }, "@types/source-list-map": { "version": "0.1.2", @@ -2363,12 +2374,12 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.19.0.tgz", - "integrity": "sha512-u7IcQ9qwsB6U806LupZmINRnQjC+RJyv36sV/ugaFWMHTbFm/hlLTRx3gGYJgHisxcGSTnf+I/fPDieRMhPSQQ==", + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.19.2.tgz", + "integrity": "sha512-HX2qOq2GOV04HNrmKnTpSIpHjfl7iwdXe3u/Nvt+/cpmdvzYvY0NHSiTkYN257jHnq4OM/yo+OsFgati+7LqJA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.19.0", + "@typescript-eslint/experimental-utils": "2.19.2", "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -2387,13 +2398,13 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.19.0.tgz", - "integrity": "sha512-zwpg6zEOPbhB3+GaQfufzlMUOO6GXCNZq6skk+b2ZkZAIoBhVoanWK255BS1g5x9bMwHpLhX0Rpn5Fc3NdCZdg==", + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.19.2.tgz", + "integrity": "sha512-B88QuwT1wMJR750YvTJBNjMZwmiPpbmKYLm1yI7PCc3x0NariqPwqaPsoJRwU9DmUi0cd9dkhz1IqEnwfD+P1A==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.19.0", + "@typescript-eslint/typescript-estree": "2.19.2", "eslint-scope": "^5.0.0" }, "dependencies": { @@ -2410,21 +2421,21 @@ } }, "@typescript-eslint/parser": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.19.0.tgz", - "integrity": "sha512-s0jZoxAWjHnuidbbN7aA+BFVXn4TCcxEVGPV8lWMxZglSs3NRnFFAlL+aIENNmzB2/1jUJuySi6GiM6uACPmpg==", + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.19.2.tgz", + "integrity": "sha512-8uwnYGKqX9wWHGPGdLB9sk9+12sjcdqEEYKGgbS8A0IvYX59h01o8os5qXUHMq2na8vpDRaV0suTLM7S8wraTA==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.19.0", - "@typescript-eslint/typescript-estree": "2.19.0", + "@typescript-eslint/experimental-utils": "2.19.2", + "@typescript-eslint/typescript-estree": "2.19.2", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.19.0.tgz", - "integrity": "sha512-n6/Xa37k0jQdwpUszffi19AlNbVCR0sdvCs3DmSKMD7wBttKY31lhD2fug5kMD91B2qW4mQldaTEc1PEzvGu8w==", + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.19.2.tgz", + "integrity": "sha512-Xu/qa0MDk6upQWqE4Qy2X16Xg8Vi32tQS2PR0AvnT/ZYS4YGDvtn2MStOh5y8Zy2mg4NuL06KUHlvCh95j9C6Q==", "dev": true, "requires": { "debug": "^4.1.1", @@ -3572,9 +3583,9 @@ } }, "boolean": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.0.tgz", - "integrity": "sha512-OElxJ1lUSinuoUnkpOgLmxp0DC4ytEhODEL6QJU0NpxE/mI4rUSh8h1P1Wkvfi3xQEBcxXR2gBIPNYNuaFcAbQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz", + "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==", "dev": true, "optional": true }, @@ -4645,17 +4656,6 @@ "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } } }, "find-cache-dir": { @@ -4668,6 +4668,15 @@ "make-dir": "^2.0.0", "pkg-dir": "^3.0.0" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -5370,9 +5379,9 @@ "dev": true }, "electron": { - "version": "7.1.11", - "resolved": "https://registry.npmjs.org/electron/-/electron-7.1.11.tgz", - "integrity": "sha512-YDXfnovKY+8iZ5ISQh1kRqYIRKbpOSxGXCx2WVxPFPutEQ7Q/Xzr3h4GePEY25/NXMytMfhKaAZAYjtWUm3r9Q==", + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/electron/-/electron-7.1.12.tgz", + "integrity": "sha512-gOJxAlJX2UyCRRncKzKzHSZStDI6MdoDzsustTCzudoZx3vlst1kkIP0n5t3TWTNoKNY/ihRsYIpeu63ar1m/g==", "dev": true, "requires": { "@electron/get": "^1.0.1", @@ -5381,9 +5390,9 @@ }, "dependencies": { "@types/node": { - "version": "12.12.26", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.26.tgz", - "integrity": "sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==", + "version": "12.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.27.tgz", + "integrity": "sha512-odQFl/+B9idbdS0e8IxDl2ia/LP8KZLXhV3BUeI98TrZp0uoIzQPhGd+5EtzHmT0SMOIaPd7jfz6pOHLWTtl7A==", "dev": true } } @@ -7782,9 +7791,9 @@ }, "dependencies": { "semver": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.2.tgz", - "integrity": "sha512-BJs9T/H8sEVHbeigqzIEo57Iu/3DG6c4QoqTfbQB3BPA4zgzAomh/Fk9E7QtjWQ8mx2dgA9YCfSF4y9k9bHNpQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz", + "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==", "dev": true, "optional": true } @@ -9832,9 +9841,9 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz", - "integrity": "sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", + "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", "dev": true, "requires": { "@babel/core": "^7.7.5", @@ -10438,9 +10447,9 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "loglevel": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.6.tgz", - "integrity": "sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.7.tgz", + "integrity": "sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==", "dev": true }, "longest": { @@ -13127,9 +13136,9 @@ } }, "rimraf": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.1.tgz", - "integrity": "sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" diff --git a/package.json b/package.json index 496aa01..6200bc4 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,13 @@ "private": true, "scripts": { "start": "run-p serve:angular serve:electron", + "serve:electron": "wait-on http-get://localhost:4200/ && tsc -p tsconfig.electron.json && electron . --dev", "lint": "ng lint", "clean": "rimraf dist release", "build:windows": "ng build -c production && tsc -p tsconfig.electron.json && electron-builder build --windows", "build:mac": "ng build -c production && tsc -p tsconfig.electron.json && electron-builder build --mac", "build:linux": "ng build -c production && tsc -p tsconfig.electron.json && electron-builder build --linux", - "serve:angular": "ng serve", - "serve:electron": "wait-on http-get://localhost:4200/ && tsc -p tsconfig.electron.json && electron . --dev" + "serve:angular": "ng serve" }, "dependencies": { "7zip-bin": "^5.0.3", @@ -52,20 +52,20 @@ "zone.js": "~0.9.1" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.803.24", + "@angular-devkit/build-angular": "^0.803.25", "@angular-eslint/builder": "0.0.1-alpha.18", - "@angular/cli": "~8.3.24", + "@angular/cli": "^8.3.25", "@angular/compiler-cli": "~8.2.14", "@angular/language-service": "~8.2.14", - "@types/node": "~8.9.4", - "@typescript-eslint/eslint-plugin": "^2.19.0", - "@typescript-eslint/parser": "^2.19.0", - "electron": "^7.1.11", + "@types/node": "11.15.0", + "@typescript-eslint/eslint-plugin": "^2.19.2", + "@typescript-eslint/parser": "^2.19.2", + "electron": "^7.1.12", "electron-builder": "^22.3.2", "electron-reload": "^1.5.0", "eslint": "^6.8.0", "npm-run-all": "^4.1.5", - "rimraf": "^3.0.1", + "rimraf": "^3.0.2", "ts-node": "~7.0.0", "tslint": "~5.15.0", "typescript": "~3.5.3", diff --git a/src/app/components/browse/chart-sidebar/chart-sidebar.component.ts b/src/app/components/browse/chart-sidebar/chart-sidebar.component.ts index eedab30..499f716 100644 --- a/src/app/components/browse/chart-sidebar/chart-sidebar.component.ts +++ b/src/app/components/browse/chart-sidebar/chart-sidebar.component.ts @@ -128,8 +128,8 @@ export class ChartSidebarComponent { } onDownloadClicked() { - this.downloadService.addDownload({ - versionID: this.selectedVersion.versionID, + this.downloadService.addDownload( + this.selectedVersion.versionID, { avTagName: this.selectedVersion.avTagName, artist: this.songResult.artist, charter: this.selectedVersion.charters, diff --git a/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.html b/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.html index c2a0a9d..cdf28f8 100644 --- a/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.html +++ b/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.html @@ -1,9 +1,24 @@
-
+
+
{{download.title}}
+ +
{{download.header}}
{{download.description}}
diff --git a/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.scss b/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.scss index 4b97b25..ed744d7 100644 --- a/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.scss +++ b/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.scss @@ -4,4 +4,8 @@ .ui.progress { margin: 0; +} + +i.close.icon { + cursor: pointer; } \ No newline at end of file diff --git a/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.ts b/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.ts index b29c292..888d6d1 100644 --- a/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.ts +++ b/src/app/components/browse/status-bar/downloads-modal/downloads-modal.component.ts @@ -1,5 +1,5 @@ import { Component, ChangeDetectorRef } from '@angular/core' -import { Download } from '../../../../../electron/shared/interfaces/download.interface' +import { DownloadProgress } from '../../../../../electron/shared/interfaces/download.interface' import { DownloadService } from '../../../../core/services/download.service' @Component({ @@ -9,13 +9,15 @@ import { DownloadService } from '../../../../core/services/download.service' }) export class DownloadsModalComponent { - downloads: Download[] = [] + downloads: DownloadProgress[] = [] - constructor(downloadService: DownloadService, ref: ChangeDetectorRef) { + constructor(private downloadService: DownloadService, ref: ChangeDetectorRef) { downloadService.onDownloadUpdated(download => { const index = this.downloads.findIndex(thisDownload => thisDownload.versionID == download.versionID) if (index == -1) { this.downloads.push(download) + } else if (download.type == 'cancel') { + this.downloads.splice(index, 1) } else { this.downloads[index] = download } @@ -23,7 +25,28 @@ export class DownloadsModalComponent { }) } - trackByVersionID(_index: number, item: Download) { + trackByVersionID(_index: number, item: DownloadProgress) { return item.versionID } + + cancelDownload(versionID: number) { + this.downloadService.cancelDownload(versionID) + } + + retryDownload(versionID: number) { + this.downloadService.retryDownload(versionID) + } + + continueDownload(versionID: number) { + // TODO: test this + this.downloadService.continueDownload(versionID) + } + + getBackgroundColor(download: DownloadProgress) { + switch(download.type) { + case 'good': return 'unset' + case 'warning': return 'yellow' + case 'error': return 'indianred' + } + } } \ No newline at end of file diff --git a/src/app/core/services/download.service.ts b/src/app/core/services/download.service.ts index d7be43d..d5c22c1 100644 --- a/src/app/core/services/download.service.ts +++ b/src/app/core/services/download.service.ts @@ -1,6 +1,6 @@ import { Injectable, EventEmitter } from '@angular/core' import { ElectronService } from './electron.service' -import { Download, NewDownload } from '../../../electron/shared/interfaces/download.interface' +import { NewDownload, DownloadProgress } from '../../../electron/shared/interfaces/download.interface' import * as _ from 'underscore' @Injectable({ @@ -8,12 +8,24 @@ import * as _ from 'underscore' }) export class DownloadService { - private downloadUpdatedEmitter = new EventEmitter() - private downloads: Download[] = [] + private downloadUpdatedEmitter = new EventEmitter() + private downloads: DownloadProgress[] = [] constructor(private electronService: ElectronService) { } - addDownload(newDownload: NewDownload) { + get downloadCount() { + return this.downloads.length + } + + get totalPercent() { + let total = 0 + for (const download of this.downloads) { + total += download.percent + } + return total / this.downloads.length + } + + addDownload(versionID: number, newDownload: NewDownload) { this.electronService.receiveIPC('download-updated', result => { this.downloadUpdatedEmitter.emit(result) @@ -25,28 +37,26 @@ export class DownloadService { this.downloads[thisDownloadIndex] = result } }) - this.electronService.sendIPC('add-download', newDownload) + this.electronService.sendIPC('download', { action: 'add', versionID, data: newDownload }) } - onDownloadUpdated(callback: (download: Download) => void) { + onDownloadUpdated(callback: (download: DownloadProgress) => void) { this.downloadUpdatedEmitter.subscribe(_.throttle(callback, 30)) } - get downloadCount() { - return this.downloads.length - } - - removeDownload(versionID: number) { + cancelDownload(versionID: number) { const removedDownload = this.downloads.find(download => download.versionID == versionID) this.downloads = this.downloads.filter(download => download.versionID != versionID) + removedDownload.type = 'cancel' this.downloadUpdatedEmitter.emit(removedDownload) + this.electronService.sendIPC('download', { action: 'cancel', versionID }) } - get totalPercent() { - let total = 0 - for (const download of this.downloads) { - total += download.percent - } - return total / this.downloads.length + retryDownload(versionID: number) { + this.electronService.sendIPC('download', { action: 'retry', versionID }) + } + + continueDownload(versionID: number) { + this.electronService.sendIPC('download', { action: 'continue', versionID }) } } \ No newline at end of file diff --git a/src/electron/ipc/download/AddDownloadHandler.ts b/src/electron/ipc/download/DownloadHandler.ts similarity index 69% rename from src/electron/ipc/download/AddDownloadHandler.ts rename to src/electron/ipc/download/DownloadHandler.ts index d86d6d3..46d1b44 100644 --- a/src/electron/ipc/download/AddDownloadHandler.ts +++ b/src/electron/ipc/download/DownloadHandler.ts @@ -4,7 +4,7 @@ import { createHash, randomBytes as _randomBytes } from 'crypto' import { tempPath } from '../../shared/Paths' import { promisify } from 'util' import { join } from 'path' -import { Download, NewDownload } from '../../shared/interfaces/download.interface' +import { Download, NewDownload, DownloadProgress } from '../../shared/interfaces/download.interface' import { emitIPCEvent } from '../../main' import { mkdir as _mkdir } from 'fs' import { FileExtractor } from './FileExtractor' @@ -13,16 +13,29 @@ import { sanitizeFilename, interpolate } from '../../shared/UtilFunctions' const randomBytes = promisify(_randomBytes) const mkdir = promisify(_mkdir) -export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { - event: 'add-download' = 'add-download' +export class DownloadHandler implements IPCEmitHandler<'download'> { + event: 'download' = 'download' - async handler(data: NewDownload) { - const download: Download = { + // TODO: replace needle with got (for cancel() method) (if before-headers event is possible?) + + downloadCallbacks: { [versionID: number]: { cancel: () => void, retry: () => void, continue: () => void } } = {} + + async handler(data: Download) { + switch (data.action) { + case 'cancel': this.downloadCallbacks[data.versionID].cancel(); return + case 'retry': this.downloadCallbacks[data.versionID].retry(); return + case 'continue': this.downloadCallbacks[data.versionID].continue(); return + case 'add': this.downloadCallbacks[data.versionID] = { cancel: () => { }, retry: () => { }, continue: () => { } } + } + + // data.action == add; data.data should be defined + const download: DownloadProgress = { versionID: data.versionID, - title: `${data.avTagName} - ${data.artist}`, + title: `${data.data.avTagName} - ${data.data.artist}`, header: '', description: '', - percent: 0 + percent: 0, + type: 'good' } const randomString = (await randomBytes(5)).toString('hex') const chartPath = join(tempPath, `chart_${randomString}`) @@ -30,17 +43,19 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { let allFilesProgress = 0 // Only iterate over the keys in data.links that have link values (not hashes) - const fileKeys = Object.keys(data.links).filter(link => data.links[link].includes('.')) + const fileKeys = Object.keys(data.data.links).filter(link => data.data.links[link].includes('.')) const individualFileProgressPortion = 80 / fileKeys.length for (let i = 0; i < fileKeys.length; i++) { - const typeHash = createHash('md5').update(data.links[fileKeys[i]]).digest('hex') - const downloader = new FileDownloader(data.links[fileKeys[i]], chartPath, data.links[typeHash]) + const typeHash = createHash('md5').update(data.data.links[fileKeys[i]]).digest('hex') + const downloader = new FileDownloader(data.data.links[fileKeys[i]], chartPath, data.data.links[typeHash]) + this.downloadCallbacks[data.versionID].cancel = () => downloader.cancelDownload() // Make cancel button cancel this download let fileProgress = 0 let waitTime: number downloader.on('wait', (_waitTime) => { download.header = `[${fileKeys[i]}] (file ${i + 1}/${fileKeys.length})` download.description = `Waiting for Google rate limit... (${_waitTime}s)` + download.type = 'good' waitTime = _waitTime }) @@ -48,6 +63,7 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { download.description = `Waiting for Google rate limit... (${secondsRemaining}s)` fileProgress = interpolate(secondsRemaining, waitTime, 0, 0, individualFileProgressPortion / 2) download.percent = allFilesProgress + fileProgress + download.type = 'good' emitIPCEvent('download-updated', download) }) @@ -55,13 +71,15 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { download.description = `Sending request...` fileProgress = individualFileProgressPortion / 2 download.percent = allFilesProgress + fileProgress + download.type = 'good' emitIPCEvent('download-updated', download) }) downloader.on('warning', (continueAnyway) => { download.description = 'WARNING' + this.downloadCallbacks[data.versionID].continue = continueAnyway + download.type = 'warning' emitIPCEvent('download-updated', download) - //TODO: continue anyway }) let filesize = -1 @@ -73,6 +91,7 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { } else { download.description = `Downloading... (0 MB)` } + download.type = 'good' emitIPCEvent('download-updated', download) }) @@ -85,14 +104,16 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { download.description = `Downloading... (${Math.round(bytesDownloaded / 1e+5) / 10} MB)` download.percent = allFilesProgress + fileProgress } + download.type = 'good' emitIPCEvent('download-updated', download) }) downloader.on('error', (error, retry) => { download.header = error.header download.description = error.body + download.type = 'error' + this.downloadCallbacks[data.versionID].retry = retry emitIPCEvent('download-updated', download) - // TODO: retry }) // Wait for the 'complete' event before moving on to another file download @@ -107,14 +128,16 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { }) } - const destinationFolderName = sanitizeFilename(`${data.artist} - ${data.avTagName} (${data.charter})`) + const destinationFolderName = sanitizeFilename(`${data.data.artist} - ${data.data.avTagName} (${data.data.charter})`) const extractor = new FileExtractor(chartPath, fileKeys.includes('archive'), destinationFolderName) + this.downloadCallbacks[data.versionID].cancel = () => extractor.cancelExtract() let archive = '' extractor.on('extract', (filename) => { archive = filename download.header = `[${archive}]` download.description = `Extracting...` + download.type = 'good' emitIPCEvent('download-updated', download) }) @@ -122,6 +145,7 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { download.header = `[${archive}] (${filecount} file${filecount == 1 ? '' : 's'} extracted)` download.description = `Extracting... (${percent}%)` download.percent = interpolate(percent, 0, 100, 80, 95) + download.type = 'good' emitIPCEvent('download-updated', download) }) @@ -129,6 +153,7 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { download.header = `Moving files to library folder...` download.description = filepath download.percent = 95 + download.type = 'good' emitIPCEvent('download-updated', download) }) @@ -136,14 +161,16 @@ export class AddDownloadHandler implements IPCEmitHandler<'add-download'> { download.header = `Download complete.` download.description = filepath download.percent = 100 + download.type = 'good' emitIPCEvent('download-updated', download) }) extractor.on('error', (error, retry) => { download.header = error.header download.description = error.body + download.type = 'error' + this.downloadCallbacks[data.versionID].retry = retry emitIPCEvent('download-updated', download) - // TODO: retry }) extractor.beginExtract() diff --git a/src/electron/ipc/download/FileDownloader.ts b/src/electron/ipc/download/FileDownloader.ts index 8b337b6..bfd2719 100644 --- a/src/electron/ipc/download/FileDownloader.ts +++ b/src/electron/ipc/download/FileDownloader.ts @@ -19,12 +19,13 @@ export type DownloadError = { header: string, body: string } export class FileDownloader { private RATE_LIMIT_DELAY: number - private readonly RETRY_MAX = 3 + private readonly RETRY_MAX = 2 private static waitTime = 0 private static clock: NodeJS.Timer private callbacks = {} as Callbacks private retryCount: number + private wasCanceled = false constructor(private url: string, private destinationFolder: string, private expectedHash?: string) { if (FileDownloader.clock == undefined) { @@ -60,6 +61,7 @@ export class FileDownloader { } this.callbacks.wait(waitTime) const clock = setInterval(() => { + if (this.wasCanceled) { clearInterval(clock); return } // CANCEL POINT waitTime-- this.callbacks.waitProgress(waitTime) if (waitTime <= 0) { @@ -75,10 +77,12 @@ export class FileDownloader { * @param cookieHeader the "cookie=" header to include this request. */ private requestDownload(cookieHeader?: string) { + if (this.wasCanceled) { return } // CANCEL POINT this.callbacks.request() let uuid = generateUUID() const req = needle.get(this.url, { follow_max: 10, + open_timeout: 5000, headers: Object.assign({ 'User-Agent': 'PostmanRuntime/7.22.0', 'Referer': this.url, @@ -99,12 +103,12 @@ export class FileDownloader { } }) - req.on('err', (err) => { - // TODO: this is called on timeout; if there are other cases where this can fail, they should be printed correctly - // this.callbacks.error({ header: 'Error', description: `${err}` }, () => this.beginDownload()) + req.on('err', (err: Error) => { + this.callbacks.error({ header: 'Connection Error', body: `${err.name}: ${err.message}` }, () => this.beginDownload()) }) req.on('header', (statusCode, headers: Headers) => { + if (this.wasCanceled) { return } // CANCEL POINT if (statusCode != 200) { this.callbacks.error({ header: 'Connection failed', body: `Server returned status code: ${statusCode}` }, () => this.beginDownload()) return @@ -117,10 +121,10 @@ export class FileDownloader { const fileName = this.getDownloadFileName(headers) const downloadHash = this.getDownloadHash(headers) if (this.expectedHash !== undefined && downloadHash !== this.expectedHash) { + req.pause() this.callbacks.warning(() => { - //TODO: check if this will actually work (or will the data get lost in the time before the button is clicked?) - // Maybe show the message at the end, and ask if they want to keep it. this.handleDownloadResponse(req, fileName, headers['content-length']) + req.resume() }) } else { this.handleDownloadResponse(req, fileName, headers['content-length']) @@ -220,4 +224,8 @@ export class FileDownloader { return headers['x-goog-hash'] } } + + cancelDownload() { + this.wasCanceled = true + } } \ No newline at end of file diff --git a/src/electron/ipc/download/FileExtractor.ts b/src/electron/ipc/download/FileExtractor.ts index cb7d80b..9aedfe1 100644 --- a/src/electron/ipc/download/FileExtractor.ts +++ b/src/electron/ipc/download/FileExtractor.ts @@ -29,6 +29,7 @@ export class FileExtractor { private callbacks = {} as Callbacks private libraryFolder: string + private wasCanceled = false constructor(private sourceFolder: string, private isArchive: boolean, private destinationFolderName: string) { } /** @@ -58,6 +59,7 @@ export class FileExtractor { * @param filename The name of the archive file. */ private extract(filename: string) { + if (this.wasCanceled) { return } // CANCEL POINT this.callbacks.extract(filename) const source = join(this.sourceFolder, filename) @@ -93,6 +95,7 @@ export class FileExtractor { * Deletes the archive at , then transfers the extracted chart to . */ private async transfer(archiveFilepath?: string) { + if (this.wasCanceled) { return } // CANCEL POINT try { // Create destiniation folder if it doesn't exist @@ -117,6 +120,8 @@ export class FileExtractor { files = await readdir(this.sourceFolder) } + if (this.wasCanceled) { return } // CANCEL POINT + // Copy the files from the temporary directory to the destination for (const file of files) { await copyFile(join(this.sourceFolder, file), join(destinationFolder, file)) @@ -133,4 +138,8 @@ export class FileExtractor { this.callbacks.error({ header: 'Transfer Failed', body: `Unable to transfer downloaded files to the library folder: ${e.name}` }, undefined) } } + + cancelExtract() { + this.wasCanceled = true + } } \ No newline at end of file diff --git a/src/electron/shared/Database.ts b/src/electron/shared/Database.ts index a7fe8f1..11d832b 100644 --- a/src/electron/shared/Database.ts +++ b/src/electron/shared/Database.ts @@ -37,6 +37,7 @@ export default class Database { } }) + // TODO: make this error message more user-friendly (retry option?) return new Promise((resolve, reject) => { this.conn.connect(err => { if (err) { diff --git a/src/electron/shared/IPCHandler.ts b/src/electron/shared/IPCHandler.ts index a704e67..82a69a5 100644 --- a/src/electron/shared/IPCHandler.ts +++ b/src/electron/shared/IPCHandler.ts @@ -3,8 +3,8 @@ import { VersionResult, AlbumArtResult } from './interfaces/songDetails.interfac import SearchHandler from '../ipc/SearchHandler.ipc' import SongDetailsHandler from '../ipc/SongDetailsHandler.ipc' import AlbumArtHandler from '../ipc/AlbumArtHandler.ipc' -import { Download, NewDownload } from './interfaces/download.interface' -import { AddDownloadHandler } from '../ipc/download/AddDownloadHandler' +import { Download, NewDownload, DownloadProgress } from './interfaces/download.interface' +import { DownloadHandler } from '../ipc/download/DownloadHandler' import { Settings } from './Settings' import InitSettingsHandler from '../ipc/InitSettingsHandler.ipc' @@ -51,13 +51,13 @@ export interface IPCInvokeHandler { export function getIPCEmitHandlers(): IPCEmitHandler[]{ return [ - new AddDownloadHandler() + new DownloadHandler() ] } export type IPCEmitEvents = { - 'add-download': NewDownload - 'download-updated': Download + 'download': Download + 'download-updated': DownloadProgress } export interface IPCEmitHandler { diff --git a/src/electron/shared/interfaces/download.interface.ts b/src/electron/shared/interfaces/download.interface.ts index dacc64b..38e7547 100644 --- a/src/electron/shared/interfaces/download.interface.ts +++ b/src/electron/shared/interfaces/download.interface.ts @@ -1,8 +1,13 @@ +export interface Download { + action: 'add' | 'retry' | 'continue' | 'cancel' + versionID: number + data ?: NewDownload +} + /** * Contains the data required to start downloading a single chart */ export interface NewDownload { - versionID: number avTagName: string artist: string charter: string @@ -12,10 +17,11 @@ export interface NewDownload { /** * Represents the download progress of a single chart */ -export interface Download { +export interface DownloadProgress { versionID: number title: string header: string description: string percent: number + type: 'good' | 'warning' | 'error' | 'cancel' } \ No newline at end of file