feature: move webcams to new db namespace (#401)
* refactor: create store for seperate webcam namespace Signed-off-by: Stefan Dej <meteyou@gmail.com> * refactor: update settings webcam and webcam panel to new namespace / store modules Signed-off-by: Stefan Dej <meteyou@gmail.com> * fix: types in webcam namespace Signed-off-by: Stefan Dej <meteyou@gmail.com> * feat: hide webcam panel, if no webcam is in the db Signed-off-by: Stefan Dej <meteyou@gmail.com> * refactor: remove debug output in settings webcam tab Signed-off-by: Stefan Dej <meteyou@gmail.com> * fix: margin between DependenciesPanel.vue and next panel Signed-off-by: Stefan Dej <meteyou@gmail.com>
This commit is contained in:
parent
e8583181e1
commit
0338efd914
@ -127,7 +127,7 @@ export default class TheSidebar extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
get boolNaviWebcam(): boolean {
|
||||
return this.$store.state.gui.webcam.boolNavi
|
||||
return this.$store.state.gui.webcamSettings.boolNavi
|
||||
}
|
||||
|
||||
get moonrakerComponents(): string[] {
|
||||
|
@ -6,7 +6,6 @@
|
||||
:collapsible="true"
|
||||
card-class="dependencies-panel"
|
||||
toolbar-color="orange darken-2"
|
||||
class="mb-6 mb-md-9"
|
||||
>
|
||||
<v-card-text :class="index > 0 ? 'py-0' : 'pt-3 pb-0'" v-for="(dependency, index) in dependencies" v-bind:key="index">
|
||||
<v-divider class="my-2" v-if="index"></v-divider>
|
||||
|
@ -20,7 +20,7 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list dense class="py-0">
|
||||
<v-list-item link @click="currentCamName = 'all'">
|
||||
<v-list-item link @click="currentCamId = 'all'">
|
||||
<v-list-item-icon class="mr-0">
|
||||
<v-icon small>mdi-view-grid</v-icon>
|
||||
</v-list-item-icon>
|
||||
@ -28,7 +28,7 @@
|
||||
<v-list-item-title>{{ $t('Panels.WebcamPanel.All') }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item v-for="webcam of webcams" v-bind:key="webcam.name" link @click="currentCamName = webcam.name">
|
||||
<v-list-item v-for="webcam of webcams" v-bind:key="webcam.id" link @click="currentCamId = webcam.id">
|
||||
<v-list-item-icon class="mr-0">
|
||||
<v-icon small>{{ webcam.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
@ -42,19 +42,19 @@
|
||||
<v-card-text class="px-0 py-0 content d-inline-block">
|
||||
<v-row>
|
||||
<v-col class="pb-0" style="position: relative;">
|
||||
<template v-if="'service' in this.currentCam && this.currentCam.service === 'grid'">
|
||||
<template v-if="this.currentCam.service === 'grid'">
|
||||
<webcam-grid :webcams="this.webcams"></webcam-grid>
|
||||
</template>
|
||||
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'mjpegstreamer'">
|
||||
<template v-else-if="this.currentCam.service === 'mjpegstreamer'">
|
||||
<webcam-mjpegstreamer :cam-settings="this.currentCam"></webcam-mjpegstreamer>
|
||||
</template>
|
||||
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'mjpegstreamer-adaptive'">
|
||||
<template v-else-if="this.currentCam.service === 'mjpegstreamer-adaptive'">
|
||||
<webcam-mjpegstreamer-adaptive :cam-settings="this.currentCam"></webcam-mjpegstreamer-adaptive>
|
||||
</template>
|
||||
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'uv4l-mjpeg'">
|
||||
<template v-else-if="this.currentCam.service === 'uv4l-mjpeg'">
|
||||
<webcam-uv4l-mjpeg :cam-settings="this.currentCam"></webcam-uv4l-mjpeg>
|
||||
</template>
|
||||
<template v-else-if="'service' in this.currentCam && this.currentCam.service === 'ipstream'">
|
||||
<template v-else-if="this.currentCam.service === 'ipstream'">
|
||||
<webcam-ipstreamer :cam-settings="this.currentCam"></webcam-ipstreamer>
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -73,10 +73,10 @@ import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
||||
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
||||
import WebcamGrid from '@/components/webcams/WebcamGrid.vue'
|
||||
import Component from 'vue-class-component'
|
||||
import {Mixins} from 'vue-property-decorator'
|
||||
import {Mixins, Prop} from 'vue-property-decorator'
|
||||
import BaseMixin from '../mixins/base'
|
||||
import {GuiStateWebcam} from '@/store/gui/types'
|
||||
import Panel from '@/components/ui/Panel.vue'
|
||||
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -89,39 +89,35 @@ import Panel from '@/components/ui/Panel.vue'
|
||||
}
|
||||
})
|
||||
export default class WebcamPanel extends Mixins(BaseMixin) {
|
||||
@Prop({ default: 'dashboard' }) viewport?: string
|
||||
|
||||
get webcams(): GuiStateWebcam[] {
|
||||
return this.$store.getters['gui/getWebcams']
|
||||
get webcams(): GuiWebcamStateWebcam[] {
|
||||
return this.$store.getters['gui/webcam/getWebcams']
|
||||
}
|
||||
|
||||
get currentCamName(): string {
|
||||
let currentCamName = this.$store.state.gui.webcam.selectedCam
|
||||
if (currentCamName !== undefined && this.webcams.findIndex((webcam: GuiStateWebcam) => webcam.name === currentCamName) !== -1)
|
||||
return currentCamName
|
||||
get currentCamId(): string {
|
||||
if (this.webcams.length === 1) return this.webcams[0].id ?? 'all'
|
||||
|
||||
if (currentCamName !== undefined && Array.isArray(this.webcams) && this.webcams.length === 1)
|
||||
return this.webcams[0].name
|
||||
|
||||
return 'all'
|
||||
let currentCamId = this.$store.state.gui.webcamSettings.currentCam[this.viewport ?? ''] ?? 'all'
|
||||
if (this.webcams.findIndex((webcam: GuiWebcamStateWebcam) => webcam.id === currentCamId) !== -1)
|
||||
return currentCamId
|
||||
else if (currentCamId !== undefined && this.webcams.length === 1)
|
||||
return this.webcams[0].id ?? ''
|
||||
else return 'all'
|
||||
}
|
||||
|
||||
set currentCamName(newVal: string) {
|
||||
this.$store.dispatch('gui/saveSetting', { name: 'webcam.selectedCam', value: newVal })
|
||||
set currentCamId(newVal: string) {
|
||||
this.$store.dispatch('gui/setCurrentWebcam', { viewport: this.viewport, value: newVal })
|
||||
}
|
||||
|
||||
get currentCam(): any {
|
||||
if (this.currentCamName === 'all') {
|
||||
return {
|
||||
name: this.$t('Panels.WebcamPanel.All'),
|
||||
service: 'grid',
|
||||
icon: 'mdi-view-grid',
|
||||
}
|
||||
} else {
|
||||
const currentCam = this.webcams.findIndex((webcam: GuiStateWebcam) => webcam.name === this.currentCamName)
|
||||
if (currentCam !== -1) return this.webcams[currentCam]
|
||||
}
|
||||
const cam = this.webcams.find((cam: GuiWebcamStateWebcam) => cam.id === this.currentCamId)
|
||||
|
||||
return {}
|
||||
return cam ?? {
|
||||
name: this.$t('Panels.WebcamPanel.All'),
|
||||
service: 'grid',
|
||||
icon: 'mdi-view-grid',
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -40,6 +40,10 @@
|
||||
<v-switch v-model="boolBigThumbnail" hide-details class="mt-0"></v-switch>
|
||||
</settings-row>
|
||||
<v-divider class="my-2"></v-divider>
|
||||
<settings-row :title="$t('Settings.UiSettingsTab.ShowWebcamInNavigation')">
|
||||
<v-switch v-model="boolWebcamInNavigation" hide-details class="mt-0"></v-switch>
|
||||
</settings-row>
|
||||
<v-divider class="my-2"></v-divider>
|
||||
<settings-row :title="$t('Settings.UiSettingsTab.DisplayCANCEL_PRINT')" :sub-title="$t('Settings.UiSettingsTab.DisplayCANCEL_PRINTDescription')" :dynamicSlotWidth="true">
|
||||
<v-switch v-model="displayCancelPrint" hide-details class="mt-0"></v-switch>
|
||||
</settings-row>
|
||||
@ -99,6 +103,14 @@ export default class SettingsUiSettingsTab extends Mixins(BaseMixin) {
|
||||
this.$store.dispatch('gui/saveSetting', {name: 'dashboard.boolBigThumbnail', value: newVal })
|
||||
}
|
||||
|
||||
get boolWebcamInNavigation() {
|
||||
return this.$store.state.gui.webcamSettings.boolNavi ?? false
|
||||
}
|
||||
|
||||
set boolWebcamInNavigation(newVal) {
|
||||
this.$store.dispatch('gui/saveSetting', { name: 'webcamSettings.boolNavi', value: newVal })
|
||||
}
|
||||
|
||||
get displayCancelPrint() {
|
||||
return this.$store.state.gui.general.displayCancelPrint
|
||||
}
|
||||
|
@ -2,16 +2,14 @@
|
||||
<div>
|
||||
<v-card flat v-if="!form.bool">
|
||||
<v-card-text>
|
||||
<settings-row :title="$t('Settings.WebcamTab.ShowInNavigation')">
|
||||
<v-switch v-model="boolNavi" hide-details class="mt-0"></v-switch>
|
||||
</settings-row>
|
||||
<div v-for="(webcam) in this.webcams" v-bind:key="webcam.index">
|
||||
<h3 class="text-h5 mb-3">{{ $t('Settings.WebcamTab.Webcams') }}</h3>
|
||||
<div v-for="(webcam) in webcams" v-bind:key="webcam.id">
|
||||
<v-divider class="my-2"></v-divider>
|
||||
<settings-row :title="webcam.name" :icon="webcam.icon" :sub-title="getSubtitle(webcam)">
|
||||
<v-btn small outlined @click="editWebcam(webcam)">
|
||||
<v-icon small left>mdi-pencil</v-icon> {{ $t('Settings.Edit') }}
|
||||
</v-btn>
|
||||
<v-btn small outlined @click="deleteWebcam(webcam.index)" class="ml-3 minwidth-0 px-2" color="error">
|
||||
<v-btn small outlined @click="deleteWebcam(webcam.id)" class="ml-3 minwidth-0 px-2" color="error">
|
||||
<v-icon small>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</settings-row>
|
||||
@ -24,7 +22,7 @@
|
||||
<v-card flat v-else>
|
||||
<v-form v-model="form.valid" @submit.prevent="saveWebcam">
|
||||
<v-card-title>
|
||||
{{ form.index === null ? $t("Settings.WebcamTab.CreateWebcam") : $t("Settings.WebcamTab.EditWebcam") }}
|
||||
{{ form.id === null ? $t("Settings.WebcamTab.CreateWebcam") : $t("Settings.WebcamTab.EditWebcam") }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
@ -64,13 +62,23 @@
|
||||
<v-row>
|
||||
<v-col class="py-1">
|
||||
<v-text-field
|
||||
v-model="form.url"
|
||||
:label="$t('Settings.WebcamTab.WebcamURL')"
|
||||
v-model="form.urlStream"
|
||||
:label="$t('Settings.WebcamTab.UrlStream')"
|
||||
hide-details="auto"
|
||||
:rules="[rules.required]"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col class="py-1">
|
||||
<v-text-field
|
||||
v-model="form.urlSnapshot"
|
||||
:label="$t('Settings.WebcamTab.UrlSnapshot')"
|
||||
hide-details="auto"
|
||||
:rules="[rules.requiredMjpegAdaptive]"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col class="py-1">
|
||||
<v-select
|
||||
@ -113,14 +121,14 @@
|
||||
</v-col>
|
||||
<v-col class="col-12 col-sm-6 text-center" align-self="center">
|
||||
<vue-load-image v-if="['mjpegstreamer', 'mjpegstreamer-adaptive', 'uv4l-mjpeg'].includes(form.service)">
|
||||
<img slot="image" :src="form.url" alt="Preview" :style="webcamStyle" class="webcamImage" />
|
||||
<img slot="image" :src="form.service === 'mjpegstreamer-adaptive' ? form.urlSnapshot : form.urlStream" alt="Preview" :style="webcamStyle" class="webcamImage" />
|
||||
<v-progress-circular slot="preloader" indeterminate color="primary"></v-progress-circular>
|
||||
<template slot="error">
|
||||
<v-icon x-large>mdi-webcam-off</v-icon>
|
||||
<div class="subtitle-1 mt-2">{{ $t('Settings.WebcamTab.UrlNotAvailable') }}</div>
|
||||
</template>
|
||||
</vue-load-image>
|
||||
<video v-if="['ipstream'].includes(form.service)" :src="form.url" autoplay :style="webcamStyle" />
|
||||
<video v-if="['ipstream'].includes(form.service)" :src="form.urlStream" autoplay :style="webcamStyle" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
@ -136,7 +144,7 @@
|
||||
text
|
||||
type="submit"
|
||||
>
|
||||
{{ form.index === null ? $t("Settings.WebcamTab.SaveWebcam") : $t("Settings.WebcamTab.UpdateWebcam") }}
|
||||
{{ form.id === null ? $t("Settings.WebcamTab.SaveWebcam") : $t("Settings.WebcamTab.UpdateWebcam") }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
@ -149,17 +157,18 @@
|
||||
import {Component, Mixins} from 'vue-property-decorator'
|
||||
import BaseMixin from '../mixins/base'
|
||||
import SettingsRow from '@/components/settings/SettingsRow.vue'
|
||||
import {GuiStateWebcam} from '@/store/gui/types'
|
||||
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
|
||||
|
||||
interface webcamForm {
|
||||
bool: boolean
|
||||
index: number | null
|
||||
id: string | null
|
||||
valid: boolean
|
||||
name: string
|
||||
icon: string
|
||||
service: string
|
||||
targetFps: number
|
||||
url: string
|
||||
urlStream: string
|
||||
urlSnapshot: string
|
||||
flipX: boolean
|
||||
flipY: boolean
|
||||
}
|
||||
@ -171,40 +180,26 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
|
||||
|
||||
private form: webcamForm = {
|
||||
bool: false,
|
||||
index: null,
|
||||
id: null,
|
||||
valid: false,
|
||||
name: '',
|
||||
icon: '',
|
||||
service: '',
|
||||
targetFps: 15,
|
||||
url: '',
|
||||
urlStream: '',
|
||||
urlSnapshot: '',
|
||||
flipX: false,
|
||||
flipY: false,
|
||||
}
|
||||
|
||||
private rules = {
|
||||
required: (value: string) => value !== '' || this.$t('Settings.WebcamTab.Required'),
|
||||
requiredMjpegAdaptive: (value: string) => (value !== '' && this.form.service === 'mjpegstreamer-adaptive') || this.$t('Settings.WebcamTab.Required'),
|
||||
unique: (value: string) => !this.existsWebcamName(value) || this.$t('Settings.WebcamTab.NameAlreadyExists'),
|
||||
}
|
||||
|
||||
get webcams() {
|
||||
return this.$store.getters['gui/getWebcams'] ?? []
|
||||
}
|
||||
|
||||
get boolDashboard() {
|
||||
return this.$store.state.gui.webcam.boolDashboard ?? false
|
||||
}
|
||||
|
||||
set boolDashboard(newVal) {
|
||||
this.$store.dispatch('gui/saveSetting', { name: 'webcam.boolDashboard', value: newVal })
|
||||
}
|
||||
|
||||
get boolNavi() {
|
||||
return this.$store.state.gui.webcam.boolNavi ?? false
|
||||
}
|
||||
|
||||
set boolNavi(newVal) {
|
||||
this.$store.dispatch('gui/saveSetting', { name: 'webcam.boolNavi', value: newVal })
|
||||
return this.$store.getters['gui/webcam/getWebcams'] ?? []
|
||||
}
|
||||
|
||||
get iconItems() {
|
||||
@ -240,12 +235,12 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
|
||||
return ''
|
||||
}
|
||||
|
||||
getSubtitle(webcam: GuiStateWebcam) {
|
||||
return webcam.url
|
||||
getSubtitle(webcam: GuiWebcamStateWebcam) {
|
||||
return 'URL: '+ (webcam.service === 'mjpegstreamer-adaptive' ? webcam.urlSnapshot : webcam.urlStream)
|
||||
}
|
||||
|
||||
existsWebcamName(name: string) {
|
||||
return (this.webcams.findIndex((webcam: GuiStateWebcam) => webcam.name === name && webcam.index !== this.form.index) !== -1)
|
||||
return (this.webcams.findIndex((webcam: GuiWebcamStateWebcam) => webcam.name === name && webcam.id !== this.form.id) !== -1)
|
||||
}
|
||||
|
||||
createWebcam() {
|
||||
@ -254,13 +249,14 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
|
||||
this.form.bool = true
|
||||
}
|
||||
|
||||
editWebcam(webcam: GuiStateWebcam) {
|
||||
this.form.index = webcam.index ?? null
|
||||
editWebcam(webcam: GuiWebcamStateWebcam) {
|
||||
this.form.id = webcam.id ?? null
|
||||
this.form.name = webcam.name
|
||||
this.form.icon = webcam.icon
|
||||
this.form.service = webcam.service
|
||||
this.form.targetFps = webcam.targetFps
|
||||
this.form.url = webcam.url
|
||||
this.form.urlStream = webcam.urlStream
|
||||
this.form.urlSnapshot = webcam.urlSnapshot
|
||||
this.form.flipX = webcam.flipX
|
||||
this.form.flipY = webcam.flipY
|
||||
|
||||
@ -270,25 +266,37 @@ export default class SettingsWebcamTab extends Mixins(BaseMixin) {
|
||||
|
||||
saveWebcam() {
|
||||
if (this.form.valid) {
|
||||
if (this.form.index !== null) this.$store.dispatch('gui/updateWebcam', {...this.form})
|
||||
else this.$store.dispatch('gui/addWebcam', {...this.form})
|
||||
const values = {
|
||||
name: this.form.name,
|
||||
icon: this.form.icon,
|
||||
service: this.form.service,
|
||||
targetFps: this.form.targetFps,
|
||||
urlStream: this.form.urlStream,
|
||||
urlSnapshot: this.form.urlSnapshot,
|
||||
flipX: this.form.flipX,
|
||||
flipY: this.form.flipY,
|
||||
}
|
||||
|
||||
if (this.form.id !== null) this.$store.dispatch('gui/webcam/update', { id: this.form.id, values: values })
|
||||
else this.$store.dispatch('gui/webcam/store', { values })
|
||||
|
||||
this.clearDialog()
|
||||
}
|
||||
}
|
||||
|
||||
deleteWebcam(index: number) {
|
||||
this.$store.dispatch('gui/deleteWebcam', { index: index })
|
||||
deleteWebcam(id: string) {
|
||||
this.$store.dispatch('gui/webcam/delete', id)
|
||||
}
|
||||
|
||||
clearDialog() {
|
||||
this.form.bool = false
|
||||
this.form.index = null
|
||||
this.form.id = null
|
||||
this.form.name = ''
|
||||
this.form.icon = 'mdi-webcam'
|
||||
this.form.service = 'mjpegstreamer-adaptive'
|
||||
this.form.targetFps = 15
|
||||
this.form.url = '/webcam/?action=stream'
|
||||
this.form.urlStream = '/webcam/?action=stream'
|
||||
this.form.urlSnapshot = '/webcam/?action=snapshot'
|
||||
this.form.flipX = false
|
||||
this.form.flipY = false
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ export default class Ipstreamer extends Mixins(BaseMixin) {
|
||||
get url() {
|
||||
if (!this.isVisible) return ''
|
||||
|
||||
return this.camSettings.url || ''
|
||||
return this.camSettings.urlStream || ''
|
||||
}
|
||||
|
||||
get webcamStyle() {
|
||||
|
@ -40,7 +40,7 @@ export default class Mjpegstreamer extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
get url() {
|
||||
const baseUrl = this.camSettings.url
|
||||
const baseUrl = this.camSettings.urlStream
|
||||
const url = new URL(baseUrl, this.printerUrl === undefined ? this.hostUrl.toString() : this.printerUrl)
|
||||
url.searchParams.append('bypassCache', this.refresh.toString())
|
||||
|
||||
|
@ -98,11 +98,10 @@ export default class MjpegstreamerAdaptive extends Mixins(BaseMixin) {
|
||||
}
|
||||
|
||||
async setFrame() {
|
||||
const baseUrl = this.camSettings.url
|
||||
const baseUrl = this.camSettings.urlSnapshot
|
||||
const url = new URL(baseUrl, this.printerUrl === undefined ? this.hostUrl.toString() : this.printerUrl)
|
||||
|
||||
url.searchParams.append('bypassCache', this.refresh.toString())
|
||||
url.searchParams.set('action', 'snapshot')
|
||||
|
||||
this.request_start_time = performance.now()
|
||||
this.currentFPS = (this.time > 0) ? Math.round(1000 / this.time) : 0
|
||||
|
@ -20,18 +20,18 @@
|
||||
<script lang="ts">
|
||||
import {Component, Mixins, Prop} from 'vue-property-decorator'
|
||||
import BaseMixin from '@/components/mixins/base'
|
||||
import {GuiStateWebcam} from '@/store/gui/types'
|
||||
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
|
||||
|
||||
@Component
|
||||
export default class Uv4lMjpeg extends Mixins(BaseMixin) {
|
||||
private isVisible = true
|
||||
|
||||
@Prop({ required: true }) readonly camSettings!: GuiStateWebcam
|
||||
@Prop({ required: true }) readonly camSettings!: GuiWebcamStateWebcam
|
||||
|
||||
@Prop({ default: null }) readonly printerUrl!: string | null
|
||||
|
||||
get url() {
|
||||
const baseUrl = this.camSettings.url
|
||||
const baseUrl = this.camSettings.urlStream
|
||||
const url = new URL(baseUrl, this.printerUrl === null ? this.hostUrl.toString() : this.printerUrl)
|
||||
|
||||
return decodeURIComponent(url.toString())
|
||||
|
@ -7,19 +7,19 @@
|
||||
<v-row dense>
|
||||
<v-col
|
||||
v-for="webcam in webcams"
|
||||
:key="webcam.name"
|
||||
:key="webcam.id"
|
||||
cols="6"
|
||||
>
|
||||
<template v-if="'service' in webcam && webcam.service === 'mjpegstreamer'">
|
||||
<template v-if="webcam.service === 'mjpegstreamer'">
|
||||
<webcam-mjpegstreamer :cam-settings="webcam"></webcam-mjpegstreamer>
|
||||
</template>
|
||||
<template v-else-if="'service' in webcam && webcam.service === 'mjpegstreamer-adaptive'">
|
||||
<template v-else-if="webcam.service === 'mjpegstreamer-adaptive'">
|
||||
<webcam-mjpegstreamer-adaptive :cam-settings="webcam"></webcam-mjpegstreamer-adaptive>
|
||||
</template>
|
||||
<template v-else-if="'service' in webcam && webcam.service === 'uv4l-mjpeg'">
|
||||
<template v-else-if="webcam.service === 'uv4l-mjpeg'">
|
||||
<webcam-uv4l-mjpeg :cam-settings="webcam"></webcam-uv4l-mjpeg>
|
||||
</template>
|
||||
<template v-else-if="'service' in webcam && webcam.service === 'ipstream'">
|
||||
<template v-else-if="webcam.service === 'ipstream'">
|
||||
<webcam-ipstreamer :cam-settings="webcam"></webcam-ipstreamer>
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -37,7 +37,7 @@ import Mjpegstreamer from '@/components/webcams/Mjpegstreamer.vue'
|
||||
import MjpegstreamerAdaptive from '@/components/webcams/MjpegstreamerAdaptive.vue'
|
||||
import Uv4lMjpeg from '@/components/webcams/Uv4lMjpeg.vue'
|
||||
import Ipstreamer from '@/components/webcams/Ipstreamer.vue'
|
||||
import {GuiStateWebcam} from '@/store/gui/types'
|
||||
import {GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@ -49,6 +49,6 @@ import {GuiStateWebcam} from '@/store/gui/types'
|
||||
})
|
||||
export default class WebcamGrid extends Mixins(BaseMixin) {
|
||||
|
||||
@Prop() readonly webcams!: GuiStateWebcam[]
|
||||
@Prop() readonly webcams!: GuiWebcamStateWebcam[]
|
||||
}
|
||||
</script>
|
@ -526,7 +526,6 @@
|
||||
},
|
||||
"WebcamTab": {
|
||||
"Webcams": "Webcams",
|
||||
"ShowInNavigation": "Show in navigation",
|
||||
"AddWebcam": "add webcam",
|
||||
"CreateWebcam": "Create Webcam",
|
||||
"EditWebcam": "Edit Webcam",
|
||||
@ -552,7 +551,8 @@
|
||||
"UrlNotAvailable": "URL not available",
|
||||
|
||||
"Name": "Name",
|
||||
"WebcamURL": "Webcam URL",
|
||||
"UrlStream": "URL Stream",
|
||||
"UrlSnapshot": "URL Snapshot",
|
||||
"Service": "Service",
|
||||
"TargetFPS": "Target FPS",
|
||||
"FlipHorizontally": "Flip webcam horizontally",
|
||||
@ -666,6 +666,7 @@
|
||||
"GcodeThumbnails": "Gcode thumbnails",
|
||||
"GcodeThumbnailsDescription": "Click on the button to get to the instructions.",
|
||||
"Guide": "Guide",
|
||||
"ShowWebcamInNavigation": "Show Webcam in navigation",
|
||||
"BoolBigThumbnail": "Large thumbnail",
|
||||
"BoolBigThumbnailDescription": "Display a large thumbnail in the status panel during a print.",
|
||||
"DisplayCANCEL_PRINT": "Display CANCEL_PRINT",
|
||||
|
@ -6,7 +6,7 @@
|
||||
<div>
|
||||
<v-row>
|
||||
<v-col col-12>
|
||||
<webcam-panel></webcam-panel>
|
||||
<webcam-panel viewport="page"></webcam-panel>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@ export const actions: ActionTree<GuiState, RootState> = {
|
||||
},
|
||||
|
||||
init({ commit, dispatch, rootState }, payload) {
|
||||
window.console.debug('init gui')
|
||||
if (
|
||||
payload.value.dashboard?.control !== undefined &&
|
||||
'useCross' in payload.value.dashboard?.control
|
||||
@ -20,25 +21,34 @@ export const actions: ActionTree<GuiState, RootState> = {
|
||||
delete payload.value.dashboard?.control.useCross
|
||||
}
|
||||
|
||||
if (payload.value.webcam) {
|
||||
window.console.debug('convert old webcam')
|
||||
|
||||
if (payload.value.webcam.configs && payload.value.webcam.configs.length) {
|
||||
payload.value.webcam.configs.forEach((oldWebcam: any) => {
|
||||
const newWebcam = {...oldWebcam, urlStream: oldWebcam.url, urlSnapshot: oldWebcam.url.replace('action=stream', 'action=snapshot')}
|
||||
delete newWebcam.url
|
||||
dispatch('webcam/store', { values: newWebcam })
|
||||
})
|
||||
}
|
||||
|
||||
commit('saveSetting', { name: 'webcamSettings.boolNavi', value: payload.value.webcam.boolNavi })
|
||||
Vue.$socket.emit('server.database.delete_item', { namespace: 'mainsail', key: 'webcam' })
|
||||
}
|
||||
|
||||
commit('setData', payload.value)
|
||||
|
||||
// init remote printers, when remoteMode is off
|
||||
if (!rootState.socket?.remoteMode) dispatch('farm/readStoredPrinters', {}, { root: true })
|
||||
|
||||
dispatch('gui/webcam/init', null, { root: true })
|
||||
dispatch('printer/init', null, { root: true })
|
||||
},
|
||||
|
||||
updateDataFromDB({ commit }, payload) {
|
||||
commit('saveSetting', {
|
||||
name: payload.key,
|
||||
value: payload.value
|
||||
})
|
||||
},
|
||||
|
||||
saveSetting({ commit }, payload) {
|
||||
commit('saveSetting', payload)
|
||||
|
||||
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: payload.name, value: payload.value }, { action: 'gui/updateDataFromDB' })
|
||||
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: payload.name, value: payload.value })
|
||||
},
|
||||
|
||||
updateSettings(_, payload) {
|
||||
@ -51,7 +61,7 @@ export const actions: ActionTree<GuiState, RootState> = {
|
||||
!Array.isArray(payload.value[keyName])
|
||||
) newState = Object.assign(payload.value[keyName], {...newState})
|
||||
|
||||
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: keyName, value: newState }, { action: 'gui/updateDataFromDB' })
|
||||
Vue.$socket.emit('server.database.post_item', { namespace: 'mainsail', key: keyName, value: newState })
|
||||
},
|
||||
|
||||
setGcodefilesMetadata({ commit, dispatch, state }, data) {
|
||||
@ -70,6 +80,14 @@ export const actions: ActionTree<GuiState, RootState> = {
|
||||
})
|
||||
},
|
||||
|
||||
setCurrentWebcam({ commit, dispatch, state }, payload) {
|
||||
commit('setCurrentWebcam', payload)
|
||||
dispatch('updateSettings', {
|
||||
keyName: 'webcamSettings.currentCam',
|
||||
newVal: state.webcamSettings.currentCam
|
||||
})
|
||||
},
|
||||
|
||||
addPreset({ commit, dispatch, state }, payload) {
|
||||
commit('addPreset', payload)
|
||||
dispatch('updateSettings', {
|
||||
@ -118,30 +136,6 @@ export const actions: ActionTree<GuiState, RootState> = {
|
||||
})
|
||||
},
|
||||
|
||||
addWebcam({ commit, dispatch, state }, payload) {
|
||||
commit('addWebcam', payload)
|
||||
dispatch('updateSettings', {
|
||||
keyName: 'webcam.configs',
|
||||
newVal: state.webcam.configs
|
||||
})
|
||||
},
|
||||
|
||||
updateWebcam({ commit, dispatch, state }, payload) {
|
||||
commit('updateWebcam', payload)
|
||||
dispatch('updateSettings', {
|
||||
keyName: 'webcam.configs',
|
||||
newVal: state.webcam.configs
|
||||
})
|
||||
},
|
||||
|
||||
deleteWebcam({ commit, dispatch, state }, payload) {
|
||||
commit('deleteWebcam', payload)
|
||||
dispatch('updateSettings', {
|
||||
keyName: 'webcam.configs',
|
||||
newVal: state.webcam.configs
|
||||
})
|
||||
},
|
||||
|
||||
setTempchartDatasetAdditionalSensorSetting({ commit, dispatch, state }, payload) {
|
||||
commit('setTempchartDatasetAdditionalSensorSetting', payload)
|
||||
dispatch('updateSettings', {
|
||||
|
@ -42,16 +42,6 @@ export const getters: GetterTree<GuiState, any> = {
|
||||
return output
|
||||
},
|
||||
|
||||
getWebcams:(state) => {
|
||||
const output = []
|
||||
|
||||
for (const [key, webcam] of Object.entries(state.webcam.configs)) {
|
||||
output.push(Object.assign({}, webcam, { index: key }))
|
||||
}
|
||||
|
||||
return caseInsensitiveSort(output, 'name')
|
||||
},
|
||||
|
||||
getDatasetValue: (state) => (payload: { name: string, type: string }) => {
|
||||
if (
|
||||
payload.name in state.tempchart.datasetSettings &&
|
||||
@ -133,6 +123,10 @@ export const getters: GetterTree<GuiState, any> = {
|
||||
}
|
||||
}
|
||||
|
||||
if (getters['webcam/getWebcams'].length === 0) {
|
||||
panels = panels.filter((element: any) => element.name !== 'webcam')
|
||||
}
|
||||
|
||||
return panels
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ import { mutations } from '@/store/gui/mutations'
|
||||
import { getters } from '@/store/gui/getters'
|
||||
import {defaultLogoColor, defaultPrimaryColor} from '@/store/variables'
|
||||
|
||||
// load modules
|
||||
import { webcam } from '@/store/gui/webcam'
|
||||
|
||||
export const getDefaultState = (): GuiState => {
|
||||
return {
|
||||
general: {
|
||||
@ -98,19 +101,12 @@ export const getDefaultState = (): GuiState => {
|
||||
],
|
||||
nonExpandPanels: []
|
||||
},
|
||||
webcam: {
|
||||
selectedCam: '',
|
||||
boolDashboard: false,
|
||||
webcamSettings: {
|
||||
currentCam: {
|
||||
dashboard: 'all',
|
||||
page: 'all'
|
||||
},
|
||||
boolNavi: false,
|
||||
configs: [{
|
||||
name: 'Default',
|
||||
icon: 'mdi-webcam',
|
||||
service: 'mjpegstreamer-adaptive',
|
||||
targetFps: 15,
|
||||
url: '/webcam/?action=stream',
|
||||
flipX: false,
|
||||
flipY: false,
|
||||
}],
|
||||
},
|
||||
tempchart: {
|
||||
autoscale: false,
|
||||
@ -209,5 +205,8 @@ export const gui: Module<GuiState, any> = {
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations
|
||||
mutations,
|
||||
modules: {
|
||||
webcam
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export const mutations: MutationTree<GuiState> = {
|
||||
|
||||
saveSetting(state, payload) {
|
||||
// eslint-disable-next-line
|
||||
const deepSet = (obj:any, is:string[] | string, value:any):any => {
|
||||
const deepSet = (obj:any, is:string[] | string, value:any):any => {
|
||||
if (is !== undefined && typeof is === 'string')
|
||||
return deepSet(obj,is.split('.'), value)
|
||||
else if (is.length==1 && value !== undefined)
|
||||
@ -62,6 +62,10 @@ export const mutations: MutationTree<GuiState> = {
|
||||
Vue.set(state.gcodefiles, 'showHiddenFiles', value)
|
||||
},
|
||||
|
||||
setCurrentWebcam(state, payload) {
|
||||
Vue.set(state.webcamSettings.currentCam, payload.viewport, payload.value)
|
||||
},
|
||||
|
||||
addPreset(state, payload) {
|
||||
state.presets.push({
|
||||
name: payload.name,
|
||||
@ -106,43 +110,6 @@ export const mutations: MutationTree<GuiState> = {
|
||||
}
|
||||
},
|
||||
|
||||
addWebcam(state, payload) {
|
||||
const newWebcam = {
|
||||
name: payload.name,
|
||||
icon: payload.icon,
|
||||
service: payload.service,
|
||||
targetFps: payload.targetFps,
|
||||
url: payload.url,
|
||||
flipX: payload.flipX,
|
||||
flipY: payload.flipY,
|
||||
}
|
||||
|
||||
state.webcam.configs.push(newWebcam)
|
||||
},
|
||||
|
||||
updateWebcam(state, payload) {
|
||||
if (state.webcam.configs[payload.index]) {
|
||||
const webcam = {...state.webcam}
|
||||
webcam.configs[payload.index] = {
|
||||
name: payload.name,
|
||||
icon: payload.icon,
|
||||
service: payload.service,
|
||||
targetFps: payload.targetFps,
|
||||
url: payload.url,
|
||||
flipX: payload.flipX,
|
||||
flipY: payload.flipY,
|
||||
}
|
||||
|
||||
Vue.set(state, 'webcam', webcam)
|
||||
}
|
||||
},
|
||||
|
||||
deleteWebcam(state, payload) {
|
||||
if (state.webcam.configs[payload.index]) {
|
||||
state.webcam.configs.splice(payload.index, 1)
|
||||
}
|
||||
},
|
||||
|
||||
setHistoryColumns(state, data) {
|
||||
if (data.value && state.history.hideColums.includes(data.name)) {
|
||||
state.history.hideColums.splice(state.history.hideColums.indexOf(data.name), 1)
|
||||
|
@ -1,25 +1,15 @@
|
||||
export interface GuiState {
|
||||
webcam: {
|
||||
selectedCam: string
|
||||
boolDashboard: boolean,
|
||||
boolNavi: boolean,
|
||||
configs: GuiStateWebcam[]
|
||||
webcamSettings: {
|
||||
currentCam: {
|
||||
dashboard: string
|
||||
page: string
|
||||
}
|
||||
boolNavi: boolean
|
||||
}
|
||||
presets: GuiStatePreset[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface GuiStateWebcam {
|
||||
index?: number | null
|
||||
name: string
|
||||
icon: string
|
||||
service: 'mjpegstreamer' | 'mjpegstreamer-adaptive' | 'uv4l-mjpeg' | 'ipstream'
|
||||
targetFps: number
|
||||
url: string
|
||||
flipX: boolean
|
||||
flipY: boolean
|
||||
}
|
||||
|
||||
export interface GuiStatePreset {
|
||||
index?: number | null
|
||||
name: string
|
||||
|
48
src/store/gui/webcam/actions.ts
Normal file
48
src/store/gui/webcam/actions.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { ActionTree } from 'vuex'
|
||||
import {RootState} from '@/store/types'
|
||||
import {GuiWebcamState} from '@/store/gui/webcam/types'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import Vue from 'vue'
|
||||
|
||||
export const actions: ActionTree<GuiWebcamState, RootState> = {
|
||||
reset({ commit }) {
|
||||
commit('reset')
|
||||
},
|
||||
|
||||
init() {
|
||||
window.console.debug('init gui/webcam')
|
||||
Vue.$socket.emit('server.database.get_item', { namespace: 'webcams' }, { action: 'gui/webcam/initStore' })
|
||||
},
|
||||
|
||||
initStore({ commit }, payload) {
|
||||
commit('reset')
|
||||
commit('initStore', payload)
|
||||
},
|
||||
|
||||
upload(_, payload) {
|
||||
Vue.$socket.emit('server.database.post_item', { namespace: 'webcams', key: payload.id, value: payload.value })
|
||||
},
|
||||
|
||||
store({ commit, dispatch, state }, payload) {
|
||||
const id = uuidv4()
|
||||
|
||||
commit('store', { id, values: payload.values })
|
||||
dispatch('upload', {
|
||||
id,
|
||||
value: state.webcams[id]
|
||||
})
|
||||
},
|
||||
|
||||
update({ commit, dispatch, state }, payload) {
|
||||
commit('update', payload)
|
||||
dispatch('upload', {
|
||||
id: payload.id,
|
||||
value: state.webcams[payload.id]
|
||||
})
|
||||
},
|
||||
|
||||
delete({ commit }, payload) {
|
||||
commit('delete', payload)
|
||||
Vue.$socket.emit('server.database.delete_item', { namespace: 'webcams', key: payload })
|
||||
},
|
||||
}
|
15
src/store/gui/webcam/getters.ts
Normal file
15
src/store/gui/webcam/getters.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { GetterTree } from 'vuex'
|
||||
import {GuiWebcamState, GuiWebcamStateWebcam} from '@/store/gui/webcam/types'
|
||||
|
||||
// eslint-disable-next-line
|
||||
export const getters: GetterTree<GuiWebcamState, any> = {
|
||||
getWebcams:(state) => {
|
||||
const webcams: GuiWebcamStateWebcam[] = []
|
||||
|
||||
Object.keys(state.webcams).forEach((id: string) => {
|
||||
webcams.push({...state.webcams[id], id})
|
||||
})
|
||||
|
||||
return webcams
|
||||
},
|
||||
}
|
23
src/store/gui/webcam/index.ts
Normal file
23
src/store/gui/webcam/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Module } from 'vuex'
|
||||
import { actions } from '@/store/gui/webcam/actions'
|
||||
import { mutations } from '@/store/gui/webcam/mutations'
|
||||
import { getters } from '@/store/gui/webcam/getters'
|
||||
import {GuiWebcamState} from '@/store/gui/webcam/types'
|
||||
|
||||
export const getDefaultState = (): GuiWebcamState => {
|
||||
return {
|
||||
webcams: {}
|
||||
}
|
||||
}
|
||||
|
||||
// initial state
|
||||
const state = getDefaultState()
|
||||
|
||||
// eslint-disable-next-line
|
||||
export const webcam: Module<GuiWebcamState, any> = {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations
|
||||
}
|
33
src/store/gui/webcam/mutations.ts
Normal file
33
src/store/gui/webcam/mutations.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { getDefaultState } from './index'
|
||||
import {MutationTree} from 'vuex'
|
||||
import {GuiWebcamState} from '@/store/gui/webcam/types'
|
||||
import Vue from 'vue'
|
||||
|
||||
export const mutations: MutationTree<GuiWebcamState> = {
|
||||
reset(state) {
|
||||
Object.assign(state, getDefaultState())
|
||||
},
|
||||
|
||||
initStore(state, payload) {
|
||||
Vue.set(state, 'webcams', payload.value)
|
||||
},
|
||||
|
||||
store(state, payload) {
|
||||
Vue.set(state.webcams, payload.id, payload.values)
|
||||
},
|
||||
|
||||
update(state, payload) {
|
||||
if (payload.id in state.webcams) {
|
||||
const webcam = {...state.webcams[payload.id]}
|
||||
Object.assign(webcam, payload.values)
|
||||
|
||||
Vue.set(state.webcams, payload.id, webcam)
|
||||
}
|
||||
},
|
||||
|
||||
delete(state, payload) {
|
||||
if (payload in state.webcams) {
|
||||
Vue.delete(state.webcams, payload)
|
||||
}
|
||||
},
|
||||
}
|
17
src/store/gui/webcam/types.ts
Normal file
17
src/store/gui/webcam/types.ts
Normal file
@ -0,0 +1,17 @@
|
||||
export interface GuiWebcamState {
|
||||
webcams: {
|
||||
[key: string]: GuiWebcamStateWebcam
|
||||
},
|
||||
}
|
||||
|
||||
export interface GuiWebcamStateWebcam {
|
||||
id?: string
|
||||
name: string
|
||||
icon: string
|
||||
service: 'mjpegstreamer' | 'mjpegstreamer-adaptive' | 'uv4l-mjpeg' | 'ipstream'
|
||||
targetFps: number
|
||||
urlStream: string
|
||||
urlSnapshot: string
|
||||
flipX: boolean
|
||||
flipY: boolean
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user