Add a toggle switch for image capture to gallery

This commit is contained in:
Julian Stirling 2026-05-23 19:29:58 +01:00
parent 2bcc98094f
commit af18850c41
3 changed files with 190 additions and 40 deletions

View file

@ -0,0 +1,123 @@
<template>
<div>
<p v-if="labelText !== undefined" class="toggle-label uk-form-label">{{ labelText }}</p>
<div class="toggle-switch" :class="{ checked: modelValue }" @click="toggle" />
<p v-if="showStateLabel" class="toggle-state-label">{{ stateLabelText }}</p>
</div>
</template>
<script>
export default {
name: "ToggleSwitch",
props: {
modelValue: {
required: true,
type: Boolean,
},
labelText: {
required: false,
type: String,
default: undefined,
},
offLabel: {
required: false,
type: String,
default: undefined,
},
onLabel: {
required: false,
type: String,
default: undefined,
},
},
emits: ["update:modelValue"],
computed: {
showStateLabel() {
return this.onLabel !== undefined && this.offLabel !== undefined;
},
stateLabelText() {
return this.modelValue ? this.onLabel : this.offLabel;
},
},
methods: {
toggle() {
this.$emit("update:modelValue", !this.modelValue);
},
},
};
</script>
<style lang="less" scoped>
@import url("../../assets/less/variables.less");
.toggle-label {
margin-bottom: 0.2rem;
}
.toggle-state-label {
margin-top: 0.2rem;
font-style: italic;
}
.toggle-switch {
background: #ddd;
border-radius: 12px;
box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.08);
cursor: pointer;
flex: none;
height: 24px;
position: relative;
transition: background-color 150ms;
width: 48px;
}
.toggle-switch::before {
background: #fff;
background-image: radial-gradient(
circle at 6px 6px,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0.05) 16px
);
border-radius: 10px;
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.08);
content: "";
display: block;
height: 20px;
left: 2px;
position: absolute;
top: 2px;
transition: left 150ms;
width: 20px;
will-change: left;
}
.checked {
background-color: @global-primary-background;
}
.checked::before {
background-image: radial-gradient(
circle at 6px 6px,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0.05) 16px
);
left: 26px;
}
.toggle-switch:hover {
box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.2);
}
.toggle-switch:hover::before {
background-image: radial-gradient(
circle at 6px 6px,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0.1375) 16px
);
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
}
</style>

View file

@ -0,0 +1,64 @@
<template>
<div id="captureControl">
<p><b>Image Capture</b></p>
<toggle-switch
v-model="saveToGallery"
label-text="Save to Gallery?"
on-label="Saving"
off-label="Downloading"
/>
<div class="uk-margin">
<action-button
thing="camera"
action="capture"
:submit-data="{ capture_mode: 'standard' }"
submit-label="Capture"
:submit-on-event="'globalCaptureEvent'"
@response="handleCaptureResponse"
@error="modalError"
/>
</div>
</div>
</template>
<script>
import axios from "axios";
import toggleSwitch from "@/components/genericComponents/toggleSwitch.vue";
import ActionButton from "@/components/labThingsComponents/actionButton.vue";
export default {
name: "CaptureControl",
components: {
toggleSwitch,
ActionButton,
},
data: function () {
return {
saveToGallery: true,
};
},
methods: {
handleCaptureResponse: async function (response) {
// Retrieve the captured image and save it
let imageUri = response.output.href;
if (!imageUri) {
this.modalError("No image URI returned from capture task.");
return;
}
// To save the returned data, we make a virtual link and click it
let imageResponse = await axios.get(imageUri, { responseType: "blob" });
const url = window.URL.createObjectURL(new Blob([imageResponse.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", `OFM_${new Date().toISOString()}.jpeg`);
document.body.appendChild(link);
link.click();
},
},
};
</script>

View file

@ -2,34 +2,20 @@
<div id="paneControl" class="uk-padding-small">
<positionControl v-if="stageAvailable" />
<autofocusControl v-if="autofocusAvailable" />
<p>Image Capture</p>
<div class="uk-margin">
<action-button
thing="camera"
action="capture"
:submit-data="{ capture_mode: 'standard' }"
submit-label="Capture"
:submit-on-event="'globalCaptureEvent'"
@response="handleCaptureResponse"
@error="modalError"
/>
</div>
<captureControl />
</div>
</template>
<script>
import axios from "axios";
import ActionButton from "../../labThingsComponents/actionButton.vue";
import captureControl from "./captureControl.vue";
import positionControl from "./positionControl.vue";
import autofocusControl from "./autofocusControl.vue";
import { eventBus } from "../../../eventBus.js";
export default {
name: "PaneControl",
components: {
ActionButton,
captureControl,
positionControl,
autofocusControl,
},
@ -42,28 +28,5 @@ export default {
return this.thingAvailable("autofocus");
},
},
methods: {
handleCaptureResponse: async function (response) {
// Retrieve the captured image and save it
let imageUri = response.output.href;
if (!imageUri) {
this.modalError("No image URI returned from capture task.");
return;
}
// Emit flash capture stream animation
eventBus.emit("globalFlashStream");
// To save the returned data, we make a virtual link and click it
let imageResponse = await axios.get(imageUri, { responseType: "blob" });
const url = window.URL.createObjectURL(new Blob([imageResponse.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", `OFM_${new Date().toISOString()}.jpeg`);
document.body.appendChild(link);
link.click();
},
},
};
</script>