feature: add snackbar for display the downloading gcode file and option to cancel it

Signed-off-by: Stefan Dej <meteyou@gmail.com>
This commit is contained in:
Stefan Dej 2021-09-18 23:00:15 +02:00
parent 1c1ce285bd
commit 2c38aad7fd
2 changed files with 78 additions and 11 deletions

View File

@ -88,13 +88,19 @@
</div> </div>
<v-progress-linear class="mt-2" :value="loadingPercent"></v-progress-linear> <v-progress-linear class="mt-2" :value="loadingPercent"></v-progress-linear>
<template v-slot:action="{ attrs }"> <template v-slot:action="{ attrs }">
<v-btn <v-btn color="red" text v-bind="attrs" style="min-width: auto;" @click="cancelRendering()">
color="red" <v-icon class="0">mdi-close</v-icon>
text </v-btn>
v-bind="attrs" </template>
style="min-width: auto;" </v-snackbar>
@click="cancelRendering()" <v-snackbar v-model="downloadSnackbar.status" :timeout="-1" :value="true" fixed right bottom dark>
> <div>
{{ $t('GCodeViewer.Downloading') }} - {{ Math.round(downloadSnackbar.percent) }} % @ {{ formatFilesize(Math.round(downloadSnackbar.speed)) }}/s<br />
<strong>{{ downloadSnackbar.filename }}</strong>
</div>
<v-progress-linear class="mt-2" :value="downloadSnackbar.percent"></v-progress-linear>
<template v-slot:action="{ attrs }">
<v-btn color="red" text v-bind="attrs" @click="cancelDownload" style="min-width: auto;" >
<v-icon class="0">mdi-close</v-icon> <v-icon class="0">mdi-close</v-icon>
</v-btn> </v-btn>
</template> </template>
@ -108,11 +114,27 @@ import BaseMixin from '../mixins/base'
// @ts-ignore // @ts-ignore
import GCodeViewer from '@sindarius/gcodeviewer' import GCodeViewer from '@sindarius/gcodeviewer'
import {Debounce} from 'vue-debounce-decorator' import {Debounce} from 'vue-debounce-decorator'
import axios from 'axios'
import {formatFilesize} from '@/plugins/helpers'
interface downloadSnackbar {
status: boolean
filename: string
percent: number
speed: number
total: number
cancelTokenSource: any
lastProgress: {
time: number
loaded: number
}
}
let viewer: any = null let viewer: any = null
@Component @Component
export default class Viewer extends Mixins(BaseMixin) { export default class Viewer extends Mixins(BaseMixin) {
formatFilesize = formatFilesize
private isBusy = false private isBusy = false
private loading = false private loading = false
private loadingPercent = 0 private loadingPercent = 0
@ -127,6 +149,19 @@ export default class Viewer extends Mixins(BaseMixin) {
private zSlicerHeight = 100 private zSlicerHeight = 100
private renderQuality = this.renderQualities[2] private renderQuality = this.renderQualities[2]
private downloadSnackbar: downloadSnackbar = {
status: false,
filename: '',
percent: 0,
speed: 0,
total: 0,
cancelTokenSource: {},
lastProgress: {
time: 0,
loaded: 0
}
}
@Prop({type: String, default: '', required: false}) filename!: string @Prop({type: String, default: '', required: false}) filename!: string
@Ref('fileInput') fileInput!: HTMLInputElement @Ref('fileInput') fileInput!: HTMLInputElement
//@Ref('viewerCanvasContainer') viewerCanvasContainer!: HTMLElement //@Ref('viewerCanvasContainer') viewerCanvasContainer!: HTMLElement
@ -194,7 +229,7 @@ export default class Viewer extends Mixins(BaseMixin) {
if (this.$route.query?.filename && this.loadedFile !== this.$route.query?.filename?.toString()) { if (this.$route.query?.filename && this.loadedFile !== this.$route.query?.filename?.toString()) {
//TODO: test without sleep //TODO: test without sleep
await this.sleep(2000) //Give the store a chance to initializ before loading the file. await this.sleep(1000) //Give the store a chance to initializ before loading the file.
await this.loadFile(this.$route.query.filename.toString()) await this.loadFile(this.$route.query.filename.toString())
} }
@ -284,14 +319,45 @@ export default class Viewer extends Mixins(BaseMixin) {
} }
async loadFile(filename: string) { async loadFile(filename: string) {
let response = await fetch(this.apiUrl + '/server/files/' + encodeURI(filename)) this.downloadSnackbar.status = true
let text = await response.text() this.downloadSnackbar.speed = 0
this.downloadSnackbar.lastProgress.time = 0
this.downloadSnackbar.filename = filename.startsWith('gcodes/') ? filename.slice(7) : filename
const CancelToken = axios.CancelToken
this.downloadSnackbar.cancelTokenSource = CancelToken.source()
const text = await axios.get(this.apiUrl + '/server/files/' + encodeURI(filename), {
cancelToken: this.downloadSnackbar.cancelTokenSource.token,
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
this.downloadSnackbar.percent = (progressEvent.loaded * 100) / progressEvent.total
if (this.downloadSnackbar.lastProgress.time) {
const time = progressEvent.timeStamp - this.downloadSnackbar.lastProgress.time
const data = progressEvent.loaded - this.downloadSnackbar.lastProgress.loaded
if (time > 1000 || this.downloadSnackbar.speed === 0) {
this.downloadSnackbar.speed = data / (time / 1000)
this.downloadSnackbar.lastProgress.time = progressEvent.timeStamp
this.downloadSnackbar.lastProgress.loaded = progressEvent.loaded
}
} else this.downloadSnackbar.lastProgress.time = progressEvent.timeStamp
this.downloadSnackbar.total = progressEvent.total
}
}).then(res => res.data.text()).catch((e) => {
window.console.error(e.message)
})
this.downloadSnackbar.status = false
viewer.updateRenderQuality(this.renderQuality.value) viewer.updateRenderQuality(this.renderQuality.value)
await viewer.processFile(text) await viewer.processFile(text)
this.loadingPercent = 100 this.loadingPercent = 100
this.finishLoad() this.finishLoad()
} }
cancelDownload() {
this.downloadSnackbar.cancelTokenSource.cancel('User canceled download gcode file')
}
async sleep(ms: number) { async sleep(ms: number) {
await new Promise((resolve) => setTimeout(resolve, ms)) await new Promise((resolve) => setTimeout(resolve, ms))
} }

View File

@ -614,6 +614,7 @@
"ReloadRequired" : "Reload required", "ReloadRequired" : "Reload required",
"TrackPrint": "Track Print", "TrackPrint": "Track Print",
"ZClip" : "Z Clipping", "ZClip" : "Z Clipping",
"Rendering" : "Rendering" "Rendering" : "Rendering",
"Downloading" : "Downloading"
} }
} }