Add component NotificationFrame & CaptureAudio parts for testing (#36081)
Adds component NotificationFrame. It implements a subset of MessageNotification as a Component and refactors MessageNotification to use NotificationFrame. Having some notification UI Component is nice as it allows us to easily build new types of notifications. Uses the new NotificationFrame component for CaptureAudioNotification. Adds a CaptureAudio action in the dev namespace (not meant for end-users). It records 10 seconds of audio and saves that to a wav file. Release Notes: - N/A --------- Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
parent
a3dcc76687
commit
4f0b00b0d9
13 changed files with 448 additions and 127 deletions
|
@ -82,6 +82,7 @@ inspector_ui.workspace = true
|
|||
install_cli.workspace = true
|
||||
jj_ui.workspace = true
|
||||
journal.workspace = true
|
||||
livekit_client.workspace = true
|
||||
language.workspace = true
|
||||
language_extension.workspace = true
|
||||
language_model.workspace = true
|
||||
|
|
|
@ -56,6 +56,7 @@ use settings::{
|
|||
initial_local_debug_tasks_content, initial_project_settings_content, initial_tasks_content,
|
||||
update_settings_file,
|
||||
};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
path::{Path, PathBuf},
|
||||
|
@ -69,13 +70,17 @@ use util::markdown::MarkdownString;
|
|||
use util::{ResultExt, asset_str};
|
||||
use uuid::Uuid;
|
||||
use vim_mode_setting::VimModeSetting;
|
||||
use workspace::notifications::{NotificationId, dismiss_app_notification, show_app_notification};
|
||||
use workspace::notifications::{
|
||||
NotificationId, SuppressEvent, dismiss_app_notification, show_app_notification,
|
||||
};
|
||||
use workspace::{
|
||||
AppState, NewFile, NewWindow, OpenLog, Toast, Workspace, WorkspaceSettings,
|
||||
create_and_open_local_file, notifications::simple_message_notification::MessageNotification,
|
||||
open_new,
|
||||
};
|
||||
use workspace::{CloseIntent, CloseWindow, RestoreBanner, with_active_or_new_workspace};
|
||||
use workspace::{
|
||||
CloseIntent, CloseWindow, NotificationFrame, RestoreBanner, with_active_or_new_workspace,
|
||||
};
|
||||
use workspace::{Pane, notifications::DetachAndPromptErr};
|
||||
use zed_actions::{
|
||||
OpenAccountSettings, OpenBrowser, OpenDocs, OpenServerSettings, OpenSettings, OpenZedUrl, Quit,
|
||||
|
@ -117,6 +122,14 @@ actions!(
|
|||
]
|
||||
);
|
||||
|
||||
actions!(
|
||||
dev,
|
||||
[
|
||||
/// Record 10s of audio from your current microphone
|
||||
CaptureAudio
|
||||
]
|
||||
);
|
||||
|
||||
pub fn init(cx: &mut App) {
|
||||
#[cfg(target_os = "macos")]
|
||||
cx.on_action(|_: &Hide, cx| cx.hide());
|
||||
|
@ -897,7 +910,11 @@ fn register_actions(
|
|||
.detach();
|
||||
}
|
||||
}
|
||||
})
|
||||
.register_action(|workspace, _: &CaptureAudio, window, cx| {
|
||||
capture_audio(workspace, window, cx);
|
||||
});
|
||||
|
||||
if workspace.project().read(cx).is_via_ssh() {
|
||||
workspace.register_action({
|
||||
move |workspace, _: &OpenServerSettings, window, cx| {
|
||||
|
@ -1806,6 +1823,107 @@ fn open_settings_file(
|
|||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
fn capture_audio(workspace: &mut Workspace, _: &mut Window, cx: &mut Context<Workspace>) {
|
||||
#[derive(Default)]
|
||||
enum State {
|
||||
Recording(livekit_client::CaptureInput),
|
||||
Failed(String),
|
||||
Finished(PathBuf),
|
||||
// Used during state switch. Should never occur naturally.
|
||||
#[default]
|
||||
Invalid,
|
||||
}
|
||||
|
||||
struct CaptureAudioNotification {
|
||||
focus_handle: gpui::FocusHandle,
|
||||
start_time: Instant,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl gpui::EventEmitter<DismissEvent> for CaptureAudioNotification {}
|
||||
impl gpui::EventEmitter<SuppressEvent> for CaptureAudioNotification {}
|
||||
impl gpui::Focusable for CaptureAudioNotification {
|
||||
fn focus_handle(&self, _cx: &App) -> gpui::FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
impl workspace::notifications::Notification for CaptureAudioNotification {}
|
||||
|
||||
const AUDIO_RECORDING_TIME_SECS: u64 = 10;
|
||||
|
||||
impl Render for CaptureAudioNotification {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let elapsed = self.start_time.elapsed().as_secs();
|
||||
let message = match &self.state {
|
||||
State::Recording(capture) => format!(
|
||||
"Recording {} seconds of audio from input: '{}'",
|
||||
AUDIO_RECORDING_TIME_SECS - elapsed,
|
||||
capture.name,
|
||||
),
|
||||
State::Failed(e) => format!("Error capturing audio: {e}"),
|
||||
State::Finished(path) => format!("Audio recorded to {}", path.display()),
|
||||
State::Invalid => "Error invalid state".to_string(),
|
||||
};
|
||||
|
||||
NotificationFrame::new()
|
||||
.with_title(Some("Recording Audio"))
|
||||
.show_suppress_button(false)
|
||||
.on_close(cx.listener(|_, _, _, cx| {
|
||||
cx.emit(DismissEvent);
|
||||
}))
|
||||
.with_content(message)
|
||||
}
|
||||
}
|
||||
|
||||
impl CaptureAudioNotification {
|
||||
fn finish(&mut self) {
|
||||
let state = std::mem::take(&mut self.state);
|
||||
self.state = if let State::Recording(capture) = state {
|
||||
match capture.finish() {
|
||||
Ok(path) => State::Finished(path),
|
||||
Err(e) => State::Failed(e.to_string()),
|
||||
}
|
||||
} else {
|
||||
state
|
||||
};
|
||||
}
|
||||
|
||||
fn new(cx: &mut Context<Self>) -> Self {
|
||||
cx.spawn(async move |this, cx| {
|
||||
for _ in 0..10 {
|
||||
cx.background_executor().timer(Duration::from_secs(1)).await;
|
||||
this.update(cx, |_, cx| {
|
||||
cx.notify();
|
||||
})?;
|
||||
}
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.finish();
|
||||
cx.notify();
|
||||
})?;
|
||||
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
let state = match livekit_client::CaptureInput::start() {
|
||||
Ok(capture_input) => State::Recording(capture_input),
|
||||
Err(err) => State::Failed(format!("Error starting audio capture: {}", err)),
|
||||
};
|
||||
|
||||
Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
start_time: Instant::now(),
|
||||
state,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
workspace.show_notification(NotificationId::unique::<CaptureAudio>(), cx, |cx| {
|
||||
cx.new(CaptureAudioNotification::new)
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue