-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[Fix] Add deeplinks for pause/resume recording and hardware switching #1810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,6 +25,15 @@ pub enum DeepLinkAction { | |||||||||||||||||||||||||
| capture_system_audio: bool, | ||||||||||||||||||||||||||
| mode: RecordingMode, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| PauseRecording, | ||||||||||||||||||||||||||
| ResumeRecording, | ||||||||||||||||||||||||||
| TogglePauseRecording, | ||||||||||||||||||||||||||
| SetMicrophone { | ||||||||||||||||||||||||||
| mic_label: Option<String>, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| SetCamera { | ||||||||||||||||||||||||||
| camera: Option<DeviceOrModelID>, | ||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||
| StopRecording, | ||||||||||||||||||||||||||
| OpenEditor { | ||||||||||||||||||||||||||
| project_path: PathBuf, | ||||||||||||||||||||||||||
|
|
@@ -107,6 +116,8 @@ impl TryFrom<&Url> for DeepLinkAction { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| impl DeepLinkAction { | ||||||||||||||||||||||||||
| pub async fn execute(self, app: &AppHandle) -> Result<(), String> { | ||||||||||||||||||||||||||
| let state = app.state::<ArcLock<App>>(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| match self { | ||||||||||||||||||||||||||
| DeepLinkAction::StartRecording { | ||||||||||||||||||||||||||
| capture_mode, | ||||||||||||||||||||||||||
|
|
@@ -115,8 +126,6 @@ impl DeepLinkAction { | |||||||||||||||||||||||||
| capture_system_audio, | ||||||||||||||||||||||||||
| mode, | ||||||||||||||||||||||||||
| } => { | ||||||||||||||||||||||||||
| let state = app.state::<ArcLock<App>>(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| crate::set_camera_input(app.clone(), state.clone(), camera, None).await?; | ||||||||||||||||||||||||||
| crate::set_mic_input(state.clone(), mic_label).await?; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -144,8 +153,23 @@ impl DeepLinkAction { | |||||||||||||||||||||||||
| .await | ||||||||||||||||||||||||||
| .map(|_| ()) | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::PauseRecording => { | ||||||||||||||||||||||||||
| crate::recording::pause_recording(app.clone(), state.clone()).await | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::ResumeRecording => { | ||||||||||||||||||||||||||
| crate::recording::resume_recording(app.clone(), state.clone()).await | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::TogglePauseRecording => { | ||||||||||||||||||||||||||
| crate::recording::toggle_pause_recording(app.clone(), state.clone()).await | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::SetMicrophone { mic_label } => { | ||||||||||||||||||||||||||
| crate::set_mic_input(state.clone(), mic_label).await | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::SetCamera { camera } => { | ||||||||||||||||||||||||||
| crate::set_camera_input(app.clone(), state.clone(), camera, None).await | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::StopRecording => { | ||||||||||||||||||||||||||
| crate::recording::stop_recording(app.clone(), app.state()).await | ||||||||||||||||||||||||||
| crate::recording::stop_recording(app.clone(), state).await | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| DeepLinkAction::OpenEditor { project_path } => { | ||||||||||||||||||||||||||
| crate::open_project_from_path(Path::new(&project_path), app.clone()) | ||||||||||||||||||||||||||
|
|
@@ -156,3 +180,68 @@ impl DeepLinkAction { | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #[cfg(test)] | ||||||||||||||||||||||||||
| mod tests { | ||||||||||||||||||||||||||
| use super::{ActionParseFromUrlError, DeepLinkAction}; | ||||||||||||||||||||||||||
| use cap_recording::{RecordingMode, feeds::camera::DeviceOrModelID}; | ||||||||||||||||||||||||||
| use tauri::Url; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| fn parse_action(url: &str) -> Result<DeepLinkAction, ActionParseFromUrlError> { | ||||||||||||||||||||||||||
| let url = Url::parse(url).expect("valid url"); | ||||||||||||||||||||||||||
| DeepLinkAction::try_from(&url) | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||
| fn parses_pause_resume_toggle_actions() { | ||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| parse_action("cap://action?value=%7B%22pause_recording%22%3Anull%7D"), | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::PauseRecording) | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| parse_action("cap://action?value=%7B%22resume_recording%22%3Anull%7D"), | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::ResumeRecording) | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| parse_action("cap://action?value=%7B%22toggle_pause_recording%22%3Anull%7D"), | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::TogglePauseRecording) | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||
| fn parses_hardware_switch_actions() { | ||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| parse_action( | ||||||||||||||||||||||||||
| "cap://action?value=%7B%22set_microphone%22%3A%7B%22mic_label%22%3A%22Shure%20MV7%22%7D%7D" | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::SetMicrophone { mic_label }) if mic_label.as_deref() == Some("Shure MV7") | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| parse_action( | ||||||||||||||||||||||||||
| "cap://action?value=%7B%22set_camera%22%3A%7B%22camera%22%3A%7B%22id%22%3A%22123%22%7D%7D" | ||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::SetCamera { camera: Some(DeviceOrModelID::Id(id)) }) if id == "123" | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
|
Comment on lines
+220
to
+225
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The test pattern-matches on Prompt To Fix With AIThis is a comment left during a code review.
Path: apps/desktop/src-tauri/src/deeplink_actions.rs
Line: 220-225
Comment:
**Non-existent enum variant `DeviceOrModelID::Id` used in test**
The test pattern-matches on `DeviceOrModelID::Id(id)`, but the actual enum (in `crates/recording/src/feeds/camera.rs`) only has `DeviceID(String)` and `ModelID(...)` variants — there is no `Id` variant. This causes a compile-time error when running `cargo test`. Additionally, the JSON embedded in the test URL decodes to `{"set_camera":{"camera":{"id":"123"}}` (note: only two closing braces at the end), which is malformed JSON (missing the final `}`), and even if braces were balanced, `{"id":"123"}` is not the serde representation of `DeviceOrModelID::DeviceID` — that serialises as `{"DeviceID":"123"}`. These three issues together mean the test was never actually compiled or run.
How can I resolve this? If you propose a fix, please make it concise.
Comment on lines
+220
to
+225
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||||
| fn parses_existing_start_and_stop_actions() { | ||||||||||||||||||||||||||
| let start = parse_action( | ||||||||||||||||||||||||||
| "cap://action?value=%7B%22start_recording%22%3A%7B%22capture_mode%22%3A%7B%22screen%22%3A%22Built-in%20Display%22%7D%2C%22camera%22%3Anull%2C%22mic_label%22%3Anull%2C%22capture_system_audio%22%3Atrue%2C%22mode%22%3A%22studio%22%7D%7D" | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| start, | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::StartRecording { | ||||||||||||||||||||||||||
| mode: RecordingMode::Studio, | ||||||||||||||||||||||||||
| capture_system_audio: true, | ||||||||||||||||||||||||||
| .. | ||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
| assert!(matches!( | ||||||||||||||||||||||||||
| parse_action("cap://action?value=%7B%22stop_recording%22%3Anull%7D"), | ||||||||||||||||||||||||||
| Ok(DeepLinkAction::StopRecording) | ||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This URL decodes to
{"set_camera":{"camera":{"id":"123"}}(missing the final}), so the test should currently fail. Might just need one more%7D.