feat(ui): recording player + live per-item sync progress bars
This commit is contained in:
1 parent
3b0f27f5d9
commit
d08d03077c
1 file changed
+55
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
// Right pane: LLM summary, action items, participants (Phase 5/6, FR-LLM-*/FR-CAL-*).
|
||||
import { onMount } from "svelte";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { meetings } from "../stores/meetings.svelte";
|
||||
import { calendar } from "../stores/calendar.svelte";
|
||||
import { settings } from "../stores/settings.svelte";
|
||||
@@ -26,6 +27,26 @@
|
||||
|
||||
onMount(() => calendar.load());
|
||||
|
||||
// ---- Recording playback (FR-REC-4) ----
|
||||
let audioSrc = $state<string | null>(null);
|
||||
let audioError = $state<string | null>(null);
|
||||
$effect(() => {
|
||||
const m = meetings.selected;
|
||||
audioSrc = null;
|
||||
audioError = null;
|
||||
if (m?.recorded) {
|
||||
const id = m.id;
|
||||
api
|
||||
.recordingPlaybackPath(id)
|
||||
.then((p) => {
|
||||
if (meetings.selected?.id === id) audioSrc = convertFileSrc(p);
|
||||
})
|
||||
.catch((e) => {
|
||||
if (meetings.selected?.id === id) audioError = errorMessage(e);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ---- Summary + action items (T5.4/T5.5/T5.6, FR-LLM-2/3/4) ----
|
||||
let llmStatus = $state<LlmStatus | null>(null);
|
||||
onMount(async () => {
|
||||
@@ -233,6 +254,18 @@
|
||||
</script>
|
||||
|
||||
<div class="wrap">
|
||||
{#if meetings.selected?.recorded}
|
||||
<h3><Mic2 size={14} aria-hidden="true" /> Recording</h3>
|
||||
{#if audioSrc}
|
||||
<!-- svelte-ignore a11y_media_has_caption -- a meeting recording has no caption track -->
|
||||
<audio class="player" controls src={audioSrc}></audio>
|
||||
{:else if audioError}
|
||||
<p class="muted">{audioError}</p>
|
||||
{:else}
|
||||
<p class="muted">Loading recording…</p>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if meetings.selected && settings.settings.sync_enabled}
|
||||
<h3><UploadCloud size={14} aria-hidden="true" /> Sync</h3>
|
||||
<button
|
||||
@@ -252,6 +285,7 @@
|
||||
<span class="artifact">{job.artifact}</span>
|
||||
<span class="job-status {job.status}">{job.status}</span>
|
||||
{#if job.status === "uploading" && job.bytesTotal}
|
||||
<progress class="job-bar" max={job.bytesTotal} value={job.bytesSent}></progress>
|
||||
<span class="muted">{Math.round((100 * job.bytesSent) / job.bytesTotal)}%</span>
|
||||
{/if}
|
||||
{#if job.status === "failed"}
|
||||
@@ -683,6 +717,27 @@
|
||||
.artifact {
|
||||
min-width: 5rem;
|
||||
}
|
||||
.job-bar {
|
||||
flex: 1;
|
||||
height: 0.4rem;
|
||||
min-width: 3rem;
|
||||
border: none;
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
accent-color: var(--accent, #2563eb);
|
||||
}
|
||||
.job-bar::-webkit-progress-bar {
|
||||
background: var(--bg-hover);
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
.job-bar::-webkit-progress-value {
|
||||
background: var(--accent, #2563eb);
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
.player {
|
||||
width: 100%;
|
||||
margin: 0.2rem 0 0.6rem;
|
||||
}
|
||||
.job-status {
|
||||
text-transform: capitalize;
|
||||
color: var(--muted);
|
||||
|
||||
Reference in new issue
Block a user