From 9c6db287590868c7555f9e5665480c5fdcb566e8 Mon Sep 17 00:00:00 2001 From: Andy Bradford Date: Sun, 24 Jan 2021 21:28:51 +0000 Subject: [PATCH] Adds a blocking dialog when sending a file to the printer. --- .../ directives/dragDropDirective.ts | 3 + src/electronApp/angularApp/app.module.ts | 4 +- .../components/print/print.component.html | 28 ++----- .../components/print/print.component.ts | 74 +++++++++++++------ ...rinting-confirmation-dialog.component.html | 2 +- .../transferring-dialog.component.css | 5 ++ .../transferring-dialog.component.html | 5 ++ .../transferring-dialog.component.ts | 16 ++++ .../angularApp/material/material.module.ts | 3 + .../angularApp/services/iPrinterService.ts | 4 +- .../angularApp/services/printerService.ts | 7 +- src/electronApp/core/PromiseWithProgress.ts | 36 +++++++++ src/electronApp/core/index.ts | 3 + src/electronApp/printerSdk/printer.ts | 19 ++++- 14 files changed, 158 insertions(+), 51 deletions(-) create mode 100644 src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.css create mode 100644 src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.html create mode 100644 src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.ts create mode 100644 src/electronApp/core/PromiseWithProgress.ts create mode 100644 src/electronApp/core/index.ts diff --git a/src/electronApp/angularApp/ directives/dragDropDirective.ts b/src/electronApp/angularApp/ directives/dragDropDirective.ts index 9235000..9854662 100644 --- a/src/electronApp/angularApp/ directives/dragDropDirective.ts +++ b/src/electronApp/angularApp/ directives/dragDropDirective.ts @@ -47,6 +47,9 @@ export class DragDropDirective { evt.preventDefault(); evt.stopPropagation(); + // Remove CSS class from element + this.elementClass = ''; + const files = evt.dataTransfer.files; if (files.length > 0) { // If multiple files were dropped, use only the first diff --git a/src/electronApp/angularApp/app.module.ts b/src/electronApp/angularApp/app.module.ts index 7e40495..5f2df30 100644 --- a/src/electronApp/angularApp/app.module.ts +++ b/src/electronApp/angularApp/app.module.ts @@ -16,6 +16,7 @@ import { DragDropDirective } from './ directives/dragDropDirective'; import { CameraComponent } from './components/camera/camera.component'; import { ConnectionErrorDialogComponent } from './components/connection-error-dialog/connection-error-dialog.component'; import { StopPrintingConfirmationDialogComponent } from './components/stop-printing-confirmation-dialog/stop-printing-confirmation-dialog.component'; +import { TransferringDialogComponent } from './components/transferring-dialog/transferring-dialog.component'; /** * The app module. @@ -32,7 +33,8 @@ import { StopPrintingConfirmationDialogComponent } from './components/stop-print DragDropDirective, CameraComponent, ConnectionErrorDialogComponent, - StopPrintingConfirmationDialogComponent + StopPrintingConfirmationDialogComponent, + TransferringDialogComponent ], imports: [ BrowserModule, diff --git a/src/electronApp/angularApp/components/print/print.component.html b/src/electronApp/angularApp/components/print/print.component.html index 95541e8..179b9dc 100644 --- a/src/electronApp/angularApp/components/print/print.component.html +++ b/src/electronApp/angularApp/components/print/print.component.html @@ -1,21 +1,7 @@ - - - - -
- {{ErrorMessage}} - File transferred successfully 🙂 - To print a .gx .gcode or .g file, drag it here or click to pick. - Drop file here to print it. - -
-
- - -
- -
- Transferring file to printer -
-
\ No newline at end of file +
+ {{ErrorMessage}} + File transferred successfully 🙂 + To print a .gx .gcode or .g file, drag it here or click to pick. + Drop file here to print it. + +
\ No newline at end of file diff --git a/src/electronApp/angularApp/components/print/print.component.ts b/src/electronApp/angularApp/components/print/print.component.ts index 1490de7..2e38153 100644 --- a/src/electronApp/angularApp/components/print/print.component.ts +++ b/src/electronApp/angularApp/components/print/print.component.ts @@ -1,6 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { PrinterService } from '../../services/printerService'; import { ErrorLogger } from 'electronApp/core/errorLogger'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { TransferringDialogComponent } from "../transferring-dialog/transferring-dialog.component" /** * The Print component for sending files to the printer. @@ -22,16 +24,21 @@ export class PrintComponent implements OnInit { public ErrorMessage: string; /** - * Gets a value indicating that a file transfer is in progress. + * Gets a value indicating that a file transfer was successful. */ - public SendInProgress = false; + public Success: boolean; /** - * Gets a value indicating that a file transfer was successful. + * Reference to the transferring dialog. */ - public Success: boolean; + private dialogRef: MatDialogRef = null; - constructor(private printerService: PrinterService) { + /** + * Initializes a new instance of the StatusComponent class. + * @param printerService Teh printer service. + * @param dialog A material dialog. + */ + constructor(private printerService: PrinterService, private dialog: MatDialog) { } @@ -41,32 +48,57 @@ export class PrintComponent implements OnInit { ngOnInit(): void { } + /** + * Invoked when the Angular component is destroyed. + */ + ngOnDestroy(): void { + if (this.dialogRef) { + this.dialogRef.close(); + } +} + /** * Sends a selected file to the printer/ * @param event The HTML event args. */ - public async uploadFile(event): Promise { + public uploadFile(event): void { const path = event[0].path; if (path){ - try{ - this.SendInProgress = true; - this.Success = false; - this.ErrorMessage = null; + const startTime = new Date().getTime(); - ErrorLogger.Trace("PrintComponent::uploadFile - Storing file"); - await this.printerService.StoreFileAsync(path) + // Show a dialog + this.dialogRef = this.dialog.open(TransferringDialogComponent); + this.dialogRef.disableClose = true; - ErrorLogger.Trace("PrintComponent::uploadFile - Printing file"); - await this.printerService.PrintFileAsync(event[0].name); - this.Success = true; - } - catch(e){ - ErrorLogger.NonFatalError(e); - this.ErrorMessage = 'Failed to send file to printer.'; - } + setImmediate(async () => { + try{ + this.Success = false; + this.ErrorMessage = null; + + ErrorLogger.Trace("PrintComponent::uploadFile - Storing file"); + await this.printerService.StoreFileAsync(path) + + ErrorLogger.Trace("PrintComponent::uploadFile - Printing file"); + await this.printerService.PrintFileAsync(event[0].name); + this.Success = true; + } + catch(e){ + ErrorLogger.NonFatalError(e); + this.ErrorMessage = 'Failed to send file to printer.'; + } + + // Introduce a small delay so that with small files + // the user gets to actually see the UI rather than a flicker + const endTime = new Date().getTime(); + const duration = endTime - startTime; + const delay = Math.max(0, 800 - duration); - this.SendInProgress = false; + setTimeout(() => { + this.dialogRef.close(); + this.dialogRef = null; + }, delay); + }); } } } diff --git a/src/electronApp/angularApp/components/stop-printing-confirmation-dialog/stop-printing-confirmation-dialog.component.html b/src/electronApp/angularApp/components/stop-printing-confirmation-dialog/stop-printing-confirmation-dialog.component.html index 553abb9..bc8b91a 100644 --- a/src/electronApp/angularApp/components/stop-printing-confirmation-dialog/stop-printing-confirmation-dialog.component.html +++ b/src/electronApp/angularApp/components/stop-printing-confirmation-dialog/stop-printing-confirmation-dialog.component.html @@ -1,7 +1,7 @@

Stop Printing

-
Are you sure you want to stop printing.
+
Are you sure you want to stop printing?
diff --git a/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.css b/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.css new file mode 100644 index 0000000..3124f2c --- /dev/null +++ b/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.css @@ -0,0 +1,5 @@ +.sendInProgress { + display: flex; + align-items: center; + flex-direction: column; +} \ No newline at end of file diff --git a/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.html b/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.html new file mode 100644 index 0000000..73dd81d --- /dev/null +++ b/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.html @@ -0,0 +1,5 @@ +
+ +
+ Please wait. Transferring file to printer. +
\ No newline at end of file diff --git a/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.ts b/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.ts new file mode 100644 index 0000000..ec38028 --- /dev/null +++ b/src/electronApp/angularApp/components/transferring-dialog/transferring-dialog.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit, Inject, ChangeDetectorRef, ApplicationRef, ViewChild, ElementRef } from '@angular/core'; + +@Component({ + selector: 'app-transferring-dialog', + templateUrl: './transferring-dialog.component.html', + styleUrls: ['./transferring-dialog.component.css'] +}) +export class TransferringDialogComponent implements OnInit { + + /** + * Invoked when the Angular component is initialized. + */ + ngOnInit(): void { + } + +} diff --git a/src/electronApp/angularApp/material/material.module.ts b/src/electronApp/angularApp/material/material.module.ts index 59d03e9..8488de9 100644 --- a/src/electronApp/angularApp/material/material.module.ts +++ b/src/electronApp/angularApp/material/material.module.ts @@ -10,6 +10,7 @@ import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {MatTableModule} from '@angular/material/table'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {MatDialogModule} from '@angular/material/dialog'; +import {MatProgressBarModule} from '@angular/material/progress-bar'; /** * Modulus containing the requires Angular material modules. @@ -26,6 +27,7 @@ import {MatDialogModule} from '@angular/material/dialog'; MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, + MatProgressBarModule, MatTableModule, MatCheckboxModule, MatDialogModule @@ -38,6 +40,7 @@ import {MatDialogModule} from '@angular/material/dialog'; MatFormFieldModule, MatInputModule, MatProgressSpinnerModule, + MatProgressBarModule, MatTableModule, MatCheckboxModule, MatDialogModule diff --git a/src/electronApp/angularApp/services/iPrinterService.ts b/src/electronApp/angularApp/services/iPrinterService.ts index c4899a2..a8a22d2 100644 --- a/src/electronApp/angularApp/services/iPrinterService.ts +++ b/src/electronApp/angularApp/services/iPrinterService.ts @@ -1,6 +1,6 @@ import { PrinterStatus, FirmwareVersionResponse, TemperatureResponse, PrinterDebugMonitor } from '../../printerSdk/entities'; import { PrinterCamera } from '../../printerSdk/printerCamera' -import { EventDispatcher } from '../../core/eventDispatcher'; +import { EventDispatcher, PromiseWithProgress } from '../../core'; /** * Interface fot the printer service. @@ -77,7 +77,7 @@ export interface IPrinterService { * will be renamed to .g. * @param filePath The path of the file to transferer. */ - StoreFileAsync(filePath: string): Promise; + StoreFileAsync(filePath: string): PromiseWithProgress; /** * Requests the firmware version info from the printer. diff --git a/src/electronApp/angularApp/services/printerService.ts b/src/electronApp/angularApp/services/printerService.ts index 83ebdef..06e95fb 100644 --- a/src/electronApp/angularApp/services/printerService.ts +++ b/src/electronApp/angularApp/services/printerService.ts @@ -1,10 +1,9 @@ import { Injectable } from '@angular/core'; import { IPrinterService } from './iPrinterService'; -import { PrinterStatus, TemperatureResponse, FirmwareVersionResponse, PrinterDebugMonitor } from '../../printerSdk/entities'; -import { EventDispatcher } from '../../core/eventDispatcher'; +import { PrinterStatus, TemperatureResponse, FirmwareVersionResponse, PrinterDebugMonitor, } from '../../printerSdk/entities'; import { Printer } from '../../printerSdk/printer'; -import { ErrorLogger } from '../../core/errorLogger'; import { PrinterCamera } from '../../printerSdk/printerCamera' +import { ErrorLogger, PromiseWithProgress, EventDispatcher } from '../../core'; const path = window.require('path'); @@ -154,7 +153,7 @@ export class PrinterService implements IPrinterService { } /** @inheritdoc */ - public StoreFileAsync(filePath: string): Promise { + public StoreFileAsync(filePath: string): PromiseWithProgress{ if (this.printer == null) { throw new Error('Cannot call this method before calling and awaiting ConnectAsnc()'); } diff --git a/src/electronApp/core/PromiseWithProgress.ts b/src/electronApp/core/PromiseWithProgress.ts new file mode 100644 index 0000000..e8b7fd2 --- /dev/null +++ b/src/electronApp/core/PromiseWithProgress.ts @@ -0,0 +1,36 @@ +import { EventDispatcher } from './eventDispatcher'; + +/** + * A wrapper around a promise, which also provides a progress update. + */ +export class PromiseWithProgress { + /** + * The promise to the completion of the operation. + */ + public readonly Promise: Promise; + + /** + * Event raised when there is an update to the progress. + */ + public readonly Progress = new EventDispatcher(); + + /** + * Initializes a new instance of the StatusComponent class. + * @param func The function to execute. + */ + constructor (func: (updateProgress: (value: number) => void) => Promise){ + this.Promise = func((value: number) => this.UpdateProgress(value)); + } + + /** + * Updates the current progress. + * @param value + */ + private UpdateProgress(value: number): void{ + if (value < 0 || value > 1){ + throw new Error("Value is out of range"); + } + + this.Progress.Invoke(value); + } +} diff --git a/src/electronApp/core/index.ts b/src/electronApp/core/index.ts new file mode 100644 index 0000000..8d5c5d7 --- /dev/null +++ b/src/electronApp/core/index.ts @@ -0,0 +1,3 @@ +export * from './errorLogger'; +export * from './eventDispatcher'; +export * from './PromiseWithProgress'; diff --git a/src/electronApp/printerSdk/printer.ts b/src/electronApp/printerSdk/printer.ts index 2097628..57644f6 100644 --- a/src/electronApp/printerSdk/printer.ts +++ b/src/electronApp/printerSdk/printer.ts @@ -6,6 +6,7 @@ import { PrinterResponseReader } from './printerResponseReader'; import { PrinterCamera } from './printerCamera' import { PrinterStatus, FirmwareVersionResponse, TemperatureResponse, IPrinterResponse, PrinterDebugMonitor } from './entities'; import { MachineCommands } from './machineCommands'; +import { PromiseWithProgress } from '../core/PromiseWithProgress' /** * Represents the printer. @@ -225,12 +226,24 @@ export class Printer { return this.WaitForPrinterAck(MachineCommands.PrintFileFromSd); } + /** + * Transfers a file to the printer's storage with a given name. + * @param filePath The path to the file to transfer. + * @param fileName The name of the file to store it as (without file extension) + */ + StoreFileAsync(filePath: string, fileName: string): PromiseWithProgress { + return new PromiseWithProgress((updateProgress: (value: number) => void) => { + return this.StoreFileAsyncInternal(filePath, fileName, updateProgress); + }); + } + /** * Transfers a file to the printer's storage with a given name. * @param filePath The path to the file to transfer. * @param fileName The name of the file to store it as (without file extension) + * @param updateProgress The function to cal with progress updates */ - async StoreFileAsync(filePath: string, fileName: string): Promise { + private async StoreFileAsyncInternal(filePath: string, fileName: string, updateProgress: (number: number) => void): Promise { this.ValidatePrinterReady(); // Load the file from disk @@ -303,6 +316,10 @@ export class Printer { // Send it to the printer this.SendBufferToPrinter(bufferToSend); + // Update the progress + const progress = offset / modelBytes.length; + updateProgress(progress); + offset += this.packetSizeBytes; ++count; }