0.1
This commit is contained in:
145
frontend/main.ts
Normal file
145
frontend/main.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
const startAudioBtn = document.querySelector<HTMLButtonElement>("#start-audio-btn");
|
||||
const stopAudioBtn = document.querySelector<HTMLButtonElement>("#stop-audio-btn");
|
||||
const audioStatus = document.querySelector<HTMLElement>("#audio-status");
|
||||
|
||||
const startVideoBtn = document.querySelector<HTMLButtonElement>("#start-video-btn");
|
||||
const stopVideoBtn = document.querySelector<HTMLButtonElement>("#stop-video-btn");
|
||||
const videoStatus = document.querySelector<HTMLElement>("#video-status");
|
||||
const videoPreview = document.querySelector<HTMLImageElement>("#video-preview");
|
||||
|
||||
if (
|
||||
startAudioBtn === null ||
|
||||
stopAudioBtn === null ||
|
||||
audioStatus === null ||
|
||||
startVideoBtn === null ||
|
||||
stopVideoBtn === null ||
|
||||
videoStatus === null ||
|
||||
videoPreview === null
|
||||
) {
|
||||
throw new Error("missing UI elements");
|
||||
}
|
||||
|
||||
let previewTimer: number | null = null;
|
||||
let previewRequestInFlight = false;
|
||||
|
||||
function setAudioStatus(message: string): void {
|
||||
if (audioStatus)
|
||||
audioStatus.textContent = message;
|
||||
}
|
||||
|
||||
function setAudioButtons(isRecording: boolean): void {
|
||||
if (startAudioBtn)
|
||||
startAudioBtn.disabled = isRecording;
|
||||
if (stopAudioBtn)
|
||||
stopAudioBtn.disabled = !isRecording;
|
||||
}
|
||||
|
||||
function setVideoStatus(message: string): void {
|
||||
if (videoStatus)
|
||||
videoStatus.textContent = message;
|
||||
}
|
||||
|
||||
function setVideoButtons(isRecording: boolean): void {
|
||||
if (startVideoBtn)
|
||||
startVideoBtn.disabled = isRecording;
|
||||
if (stopVideoBtn)
|
||||
stopVideoBtn.disabled = !isRecording;
|
||||
}
|
||||
|
||||
async function refreshPreviewFrame(): Promise<void> {
|
||||
if (previewRequestInFlight) {
|
||||
return;
|
||||
}
|
||||
|
||||
previewRequestInFlight = true;
|
||||
|
||||
try {
|
||||
const encoded = await invoke<string | null>("get_video_preview_frame_base64");
|
||||
|
||||
if (encoded !== null && encoded.length > 0 && videoPreview) {
|
||||
videoPreview.src = `data:image/jpeg;base64,${encoded}`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("preview refresh failed", error);
|
||||
} finally {
|
||||
previewRequestInFlight = false;
|
||||
}
|
||||
}
|
||||
|
||||
function startPreviewPolling(): void {
|
||||
if (previewTimer !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
previewTimer = window.setInterval(() => {
|
||||
void refreshPreviewFrame();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function stopPreviewPolling(): void {
|
||||
if (previewTimer !== null) {
|
||||
window.clearInterval(previewTimer);
|
||||
previewTimer = null;
|
||||
}
|
||||
|
||||
previewRequestInFlight = false;
|
||||
if (videoPreview)
|
||||
videoPreview.removeAttribute("src");
|
||||
}
|
||||
|
||||
startAudioBtn.addEventListener("click", async () => {
|
||||
startAudioBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const path = await invoke<string>("start_audio_recording");
|
||||
setAudioStatus(`Audio recording started.\nOutput: ${path}`);
|
||||
setAudioButtons(true);
|
||||
} catch (error) {
|
||||
setAudioStatus(`Start audio failed.\n${String(error)}`);
|
||||
setAudioButtons(false);
|
||||
}
|
||||
});
|
||||
|
||||
stopAudioBtn.addEventListener("click", async () => {
|
||||
stopAudioBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const path = await invoke<string>("stop_audio_recording");
|
||||
setAudioStatus(`Audio recording stopped.\nSaved file: ${path}`);
|
||||
setAudioButtons(false);
|
||||
} catch (error) {
|
||||
setAudioStatus(`Stop audio failed.\n${String(error)}`);
|
||||
setAudioButtons(true);
|
||||
}
|
||||
});
|
||||
|
||||
startVideoBtn.addEventListener("click", async () => {
|
||||
startVideoBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const path = await invoke<string>("start_video_recording");
|
||||
setVideoStatus(`Video recording started.\nOutput: ${path}`);
|
||||
setVideoButtons(true);
|
||||
startPreviewPolling();
|
||||
} catch (error) {
|
||||
setVideoStatus(`Start video failed.\n${String(error)}`);
|
||||
setVideoButtons(false);
|
||||
stopPreviewPolling();
|
||||
}
|
||||
});
|
||||
|
||||
stopVideoBtn.addEventListener("click", async () => {
|
||||
stopVideoBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const path = await invoke<string>("stop_video_recording");
|
||||
setVideoStatus(`Video recording stopped.\nSaved file: ${path}`);
|
||||
setVideoButtons(false);
|
||||
stopPreviewPolling();
|
||||
} catch (error) {
|
||||
setVideoStatus(`Stop video failed.\n${String(error)}`);
|
||||
setVideoButtons(true);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user