Files
buzz/desktop/src-tauri/src/initial_window.rs
T
b29c8cdaa4 feat(desktop): redesign the Huddle experience (#4281)
## Summary

- open Huddles in a focused companion window with a clean handoff back
to the in-app drawer and backing channel
- redesign the participant film strip, sidebar control, transcript
surface, and themed shell treatment
- preserve microphone and device control across windows, start agent
voice on the first reply, and show agent speaking activity in the film
strip
- give each agent a distinct session voice, beginning with the
configured default, plus compact per-agent text-to-speech and voice
controls
- enroll only agents explicitly mentioned or deliberately added through
an agent panel into the live Huddle roster
- keep temporary Huddle channels out of the sidebar unless the user
explicitly brings one into the main app
- remove Huddle-only avatar policy badges and filter short silence or
noise segments before speech-to-text posts

## Why

The previous flow exposed the temporary channel as product UI, obscured
who was present or speaking, and split transcript and audio state
between the main and companion windows. This keeps backing channels as
implementation details unless a user explicitly brings a Huddle into the
app, while sharing the live conversation and audio lifecycle across both
surfaces. Agent participants now join only after an explicit invitation,
distinct voices make multi-agent Huddles easier to follow, and short
microphone noise no longer becomes stray transcript messages.

## Validation

- `pnpm check`
- `pnpm build:e2e`
- `pnpm exec playwright test tests/e2e/huddle-transcription.spec.ts
--project=smoke` (13 passed)
- Huddle sidebar visibility unit coverage (4 passed)
- focused managed-agent and persona-mention E2E coverage (2 passed)
- `pnpm test` (3,910 passed)
- `cargo clippy --manifest-path desktop/src-tauri/Cargo.toml
--all-targets -- -D warnings`
- `cargo test --manifest-path desktop/src-tauri/Cargo.toml` (2,093
passed, 14 ignored; 3 diagnostics passed)

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-03 17:16:09 -07:00

68 lines
2.5 KiB
Rust

//! First-frame window reveal helpers.
#[cfg(target_os = "macos")]
pub(crate) const INITIAL_RENDER_READY_EVENT: &str = "initial-render-ready";
pub(crate) fn reveal_initial_window<R: tauri::Runtime>(window: &tauri::Window<R>) {
if let Err(error) = window.show() {
eprintln!("buzz-desktop: failed to reveal main window: {error}");
return;
}
if let Err(error) = window.set_focus() {
eprintln!("buzz-desktop: failed to focus main window: {error}");
}
}
#[cfg(target_os = "macos")]
pub(crate) fn set_initial_window_backing<R: tauri::Runtime>(window: &tauri::Window<R>) {
// The window remains transparent at runtime for vibrancy. Use an opaque
// native backing only across the first visible frames so the previous app
// cannot show through before WebKit has submitted its first surface.
if let Err(error) = window.set_background_color(Some(tauri::window::Color(17, 21, 24, 255))) {
eprintln!("buzz-desktop: failed to set initial window backing: {error}");
}
}
#[cfg(target_os = "macos")]
pub(crate) async fn clear_initial_window_backing<R: tauri::Runtime>(window: &tauri::Window<R>) {
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
if let Err(error) = window.set_background_color(None) {
eprintln!("buzz-desktop: failed to clear initial window backing: {error}");
}
}
#[cfg(target_os = "macos")]
pub(crate) async fn wait_for_stable_initial_window_geometry<R: tauri::Runtime>(
window: &tauri::Window<R>,
) {
const MAX_POLLS: usize = 120;
const REQUIRED_STABLE_POLLS: usize = 4;
let mut previous_bounds = None;
let mut stable_polls = 0;
for _ in 0..MAX_POLLS {
// Accept whatever geometry the window-state plugin restores — maximized
// or a normal saved size. macOS applies the restore asynchronously, so
// consecutive identical outer bounds are enough to know it settled.
let bounds = match (window.outer_position(), window.outer_size()) {
(Ok(position), Ok(size)) => Some((position.x, position.y, size.width, size.height)),
_ => None,
};
if bounds.is_some() && bounds == previous_bounds {
stable_polls += 1;
if stable_polls >= REQUIRED_STABLE_POLLS {
return;
}
} else {
stable_polls = 0;
}
previous_bounds = bounds;
tokio::time::sleep(std::time::Duration::from_millis(16)).await;
}
eprintln!("buzz-desktop: initial window geometry did not settle before reveal timeout");
}