diff --git a/src/common/models/toast.ts b/src/common/models/toast.ts index 9427b2bb56..8e42c48df6 100644 --- a/src/common/models/toast.ts +++ b/src/common/models/toast.ts @@ -8,4 +8,5 @@ export enum ToastType { DownloadComplete = "download-complete", DownloadStarted = "download-started", + DownloadFailed = "download-failed", } diff --git a/src/main/api/publication.ts b/src/main/api/publication.ts index 81c80c7771..cfbfca8caf 100644 --- a/src/main/api/publication.ts +++ b/src/main/api/publication.ts @@ -5,6 +5,7 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== +import * as debug_ from "debug"; import { inject, injectable } from "inversify"; import { ToastType } from "readium-desktop/common/models/toast"; import { open } from "readium-desktop/common/redux/actions/toast"; @@ -19,6 +20,9 @@ import { Store } from "redux"; import { downloadActions } from "readium-desktop/common/redux/actions"; import { ImportState } from "readium-desktop/common/redux/states/import"; +// Logger +const debug = debug_("readium-desktop:main#services/catalog"); + @injectable() export class PublicationApi { @inject("publication-repository") @@ -122,8 +126,16 @@ export class PublicationApi { const newDocs = []; for (const path of paths) { - const newDoc = await this.catalogService.importFile(path); - newDocs.push(newDoc); + try { + const newDoc = await this.catalogService.importFile(path); + if (newDoc) { + newDocs.push(newDoc); + } + } catch (error) { + debug(`Import file - FAIL : ${path}`, error); + this.dispatchToastRequest(ToastType.DownloadFailed, + this.translator.translate("message.import.fail", {path})); + } } return newDocs.map((doc) => { diff --git a/src/main/services/catalog.ts b/src/main/services/catalog.ts index 3766b62974..81f6ceed23 100644 --- a/src/main/services/catalog.ts +++ b/src/main/services/catalog.ts @@ -59,11 +59,13 @@ export class CatalogService { public async importFile(filePath: string, isLcpFile?: boolean): Promise { const ext = path.extname(filePath); + debug("Import File - START"); if (ext === ".lcpl" || (ext === ".part" && isLcpFile)) { return this.importLcplFile(filePath); } else if (/\.epub[3]?$/.test(ext) || (ext === ".part" && !isLcpFile)) { return this.importEpubFile(filePath); } + debug("Import File - END"); return null; } diff --git a/src/renderer/assets/styles/toast.css b/src/renderer/assets/styles/toast.css index 4efa2e6d02..5044503917 100644 --- a/src/renderer/assets/styles/toast.css +++ b/src/renderer/assets/styles/toast.css @@ -21,6 +21,14 @@ animation-name: start; animation-duration: 0.5s; + &.error { + background: rgba(255, 0, 0, 0.1); + } + + &.success { + background: rgba(0, 255, 0, 0.1); + } + & p { margin: 0; flex: 1; diff --git a/src/renderer/components/toast/Toast.tsx b/src/renderer/components/toast/Toast.tsx index 6abd16b915..a7efc12872 100644 --- a/src/renderer/components/toast/Toast.tsx +++ b/src/renderer/components/toast/Toast.tsx @@ -16,6 +16,13 @@ import { TranslatorProps, withTranslator } from "../utils/translator"; import * as styles from "readium-desktop/renderer/assets/styles/toast.css"; +export enum ToastType { + Error, + Default, + Success, + +} + interface Props extends TranslatorProps { close: (id: string) => void; className?: string; @@ -23,6 +30,7 @@ interface Props extends TranslatorProps { icon?: any; message?: string; displaySystemNotification: boolean; + type?: ToastType; } interface State { @@ -61,12 +69,29 @@ export class Toast extends React.Component { } public render(): React.ReactElement<{}> { - const { icon } = this.props; + const { icon, type } = this.props; const { willLeave, toRemove } = this.state; + + let typeClassName: string; + switch (type) { + case ToastType.Error: + typeClassName = styles.error; + break; + case ToastType.Success: + typeClassName = styles.success; + break; + default: + break; + } return (
this.ref = ref} - className={classNames(styles.toast, willLeave && styles.leave, toRemove && styles.toRemove)} + className={classNames( + styles.toast, + willLeave && styles.leave, + toRemove && styles.toRemove, + typeClassName, + )} > { icon && }

{ this.props.message }

diff --git a/src/renderer/components/toast/ToastManager.tsx b/src/renderer/components/toast/ToastManager.tsx index 3bbb8e961e..fc8ab96c11 100644 --- a/src/renderer/components/toast/ToastManager.tsx +++ b/src/renderer/components/toast/ToastManager.tsx @@ -15,7 +15,7 @@ import { ToastState } from "readium-desktop/common/redux/states/toast"; import { RootState } from "readium-desktop/renderer/redux/states"; -import Toast from "./Toast"; +import Toast, {ToastType as CompToastType} from "./Toast"; import * as DownloadIcon from "readium-desktop/renderer/assets/icons/download.svg"; @@ -67,6 +67,8 @@ export class ToastManager extends React.Component { return this.buildFileImportToast(toast, id); case ToastType.DownloadStarted: return this.buildFileImportStartToast(toast, id); + case ToastType.DownloadFailed: + return this.buildFileImportFailToast(toast, id); default: return (<>); } @@ -99,6 +101,18 @@ export class ToastManager extends React.Component { ); } + private buildFileImportFailToast(toast: ToastState, id: string) { + return ( + this.close(id) } + type={CompToastType.Error} + /> + ); + } + private close(id: string) { const { toastList } = this.state; toastList[id] = undefined; diff --git a/src/resources/locales/de.json b/src/resources/locales/de.json index 2b3c20f3d0..f9ac9bc8c4 100644 --- a/src/resources/locales/de.json +++ b/src/resources/locales/de.json @@ -94,7 +94,8 @@ "success": "Der Download von {{- title}} wurde abgeschlossen" }, "import": { - "success": "" + "fail": "Der Import von {{- path}} ist fehlgeschlagen. Stellen Sie sicher, dass die Datei gültig ist", + "success": "Der Import von {{- title}} ist abgeschlossen." } }, "opds": { diff --git a/src/resources/locales/en.json b/src/resources/locales/en.json index c37b8e0582..21efef7f42 100644 --- a/src/resources/locales/en.json +++ b/src/resources/locales/en.json @@ -94,6 +94,7 @@ "success": "The download of {{- title}} is finished." }, "import": { + "fail": "The import of {{- path}} failed. Verify that the file is valid", "success": "The import of {{- title}} is finished." } }, diff --git a/src/resources/locales/fr.json b/src/resources/locales/fr.json index 878a49b7fa..28843eef30 100644 --- a/src/resources/locales/fr.json +++ b/src/resources/locales/fr.json @@ -94,6 +94,7 @@ "success": "Le téléchargement de {{- title}} est terminé." }, "import": { + "fail": "L'importation de {{- path}} a échoué. Vérifier que le fichier est valide", "success": "L'import de {{- title}} est terminé." } }, diff --git a/src/typings/en.translation.d.ts b/src/typings/en.translation.d.ts index c3360a185f..cf3efb2dd5 100644 --- a/src/typings/en.translation.d.ts +++ b/src/typings/en.translation.d.ts @@ -174,12 +174,13 @@ declare namespace typed_i18n { readonly "start": string, readonly "success": string }, - readonly "import": { readonly "success": string } + readonly "import": { readonly "fail": string, readonly "success": string } }; (_: "message.download", __?: {}): { readonly "start": string, readonly "success": string }; (_: "message.download.start", __?: {}): string; (_: "message.download.success", __?: {}): string; - (_: "message.import", __?: {}): { readonly "success": string }; + (_: "message.import", __?: {}): { readonly "fail": string, readonly "success": string }; + (_: "message.import.fail", __?: {}): string; (_: "message.import.success", __?: {}): string; (_: "opds", __?: {}): { readonly "addForm": {