@@ -25,7 +25,11 @@ pub enum DeepLinkAction {
2525 capture_system_audio : bool ,
2626 mode : RecordingMode ,
2727 } ,
28+ PauseRecording ,
29+ ResumeRecording ,
30+ TogglePauseRecording ,
2831 StopRecording ,
32+ TakeScreenshot ,
2933 OpenEditor {
3034 project_path : PathBuf ,
3135 } ,
@@ -34,44 +38,8 @@ pub enum DeepLinkAction {
3438 } ,
3539}
3640
37- pub fn handle ( app_handle : & AppHandle , urls : Vec < Url > ) {
38- trace ! ( "Handling deep actions for: {:?}" , & urls) ;
39-
40- let actions: Vec < _ > = urls
41- . into_iter ( )
42- . filter ( |url| !url. as_str ( ) . is_empty ( ) )
43- . filter_map ( |url| {
44- DeepLinkAction :: try_from ( & url)
45- . map_err ( |e| match e {
46- ActionParseFromUrlError :: ParseFailed ( msg) => {
47- eprintln ! ( "Failed to parse deep link \" {}\" : {}" , & url, msg)
48- }
49- ActionParseFromUrlError :: Invalid => {
50- eprintln ! ( "Invalid deep link format \" {}\" " , & url)
51- }
52- // Likely login action, not handled here.
53- ActionParseFromUrlError :: NotAction => { }
54- } )
55- . ok ( )
56- } )
57- . collect ( ) ;
58-
59- if actions. is_empty ( ) {
60- return ;
61- }
62-
63- let app_handle = app_handle. clone ( ) ;
64- tauri:: async_runtime:: spawn ( async move {
65- for action in actions {
66- if let Err ( e) = action. execute ( & app_handle) . await {
67- eprintln ! ( "Failed to handle deep link action: {e}" ) ;
68- }
69- }
70- } ) ;
71- }
72-
7341pub enum ActionParseFromUrlError {
74- ParseFailed ( String ) ,
42+ ParseFailed ,
7543 Invalid ,
7644 NotAction ,
7745}
@@ -80,35 +48,74 @@ impl TryFrom<&Url> for DeepLinkAction {
8048 type Error = ActionParseFromUrlError ;
8149
8250 fn try_from ( url : & Url ) -> Result < Self , Self :: Error > {
83- #[ cfg( target_os = "macos" ) ]
84- if url. scheme ( ) == "file" {
85- return url
86- . to_file_path ( )
87- . map ( |project_path| Self :: OpenEditor { project_path } )
88- . map_err ( |_| ActionParseFromUrlError :: Invalid ) ;
51+ if url. scheme ( ) != "cap-desktop" {
52+ return Err ( ActionParseFromUrlError :: NotAction ) ;
8953 }
9054
9155 match url. domain ( ) {
92- Some ( v) if v != "action" => Err ( ActionParseFromUrlError :: NotAction ) ,
93- _ => Err ( ActionParseFromUrlError :: Invalid ) ,
94- } ?;
95-
96- let params = url
97- . query_pairs ( )
98- . collect :: < std:: collections:: HashMap < _ , _ > > ( ) ;
99- let json_value = params
100- . get ( "value" )
101- . ok_or ( ActionParseFromUrlError :: Invalid ) ?;
102- let action: Self = serde_json:: from_str ( json_value)
103- . map_err ( |e| ActionParseFromUrlError :: ParseFailed ( e. to_string ( ) ) ) ?;
104- Ok ( action)
56+ Some ( "pause" ) => Ok ( Self :: PauseRecording ) ,
57+ Some ( "resume" ) => Ok ( Self :: ResumeRecording ) ,
58+ Some ( "toggle-pause" ) => Ok ( Self :: TogglePauseRecording ) ,
59+ Some ( "stop" ) => Ok ( Self :: StopRecording ) ,
60+ Some ( "screenshot" ) => Ok ( Self :: TakeScreenshot ) ,
61+ _ => {
62+ if url. domain ( ) == Some ( "action" ) {
63+ let params = url. query_pairs ( ) . collect :: < std:: collections:: HashMap < _ , _ > > ( ) ;
64+ let json_value = params. get ( "value" ) . ok_or ( ActionParseFromUrlError :: Invalid ) ?;
65+ let action: Self = serde_json:: from_str ( json_value)
66+ . map_err ( |_| ActionParseFromUrlError :: ParseFailed ) ?;
67+ Ok ( action)
68+ } else {
69+ Err ( ActionParseFromUrlError :: Invalid )
70+ }
71+ }
72+ }
10573 }
10674}
10775
10876impl DeepLinkAction {
10977 pub async fn execute ( self , app : & AppHandle ) -> Result < ( ) , String > {
78+ trace ! ( "Executing deep link action: {:?}" , self ) ;
79+
11080 match self {
111- DeepLinkAction :: StartRecording {
81+ Self :: PauseRecording => {
82+ let state = app. state :: < ArcLock < App > > ( ) ;
83+ crate :: recording:: pause_recording ( app. clone ( ) , state. clone ( ) ) . await ?;
84+ let _ = ShowCapWindow :: Main { init_target_mode : None } . show ( app) . await ;
85+ Ok ( ( ) )
86+ }
87+ Self :: ResumeRecording => {
88+ let state = app. state :: < ArcLock < App > > ( ) ;
89+ crate :: recording:: resume_recording ( app. clone ( ) , state. clone ( ) ) . await ?;
90+ let _ = ShowCapWindow :: Main { init_target_mode : None } . show ( app) . await ;
91+ Ok ( ( ) )
92+ }
93+ Self :: TogglePauseRecording => {
94+ let state = app. state :: < ArcLock < App > > ( ) ;
95+ crate :: recording:: toggle_pause_recording ( app. clone ( ) , state. clone ( ) ) . await ?;
96+ let _ = ShowCapWindow :: Main { init_target_mode : None } . show ( app) . await ;
97+ Ok ( ( ) )
98+ }
99+ Self :: StopRecording => {
100+ let state = app. state :: < ArcLock < App > > ( ) ;
101+ crate :: recording:: stop_recording ( app. clone ( ) , state. clone ( ) ) . await ?;
102+ let _ = ShowCapWindow :: Main { init_target_mode : None } . show ( app) . await ;
103+ Ok ( ( ) )
104+ }
105+ Self :: TakeScreenshot => {
106+ use scap_targets:: Display ;
107+ let display = Display :: get_containing_cursor ( ) . unwrap_or_else ( Display :: primary) ;
108+ let target = ScreenCaptureTarget :: Display { id : display. id ( ) } ;
109+
110+ match crate :: recording:: take_screenshot ( app. clone ( ) , target) . await {
111+ Ok ( path) => {
112+ let _ = ShowCapWindow :: ScreenshotEditor { path } . show ( app) . await ;
113+ Ok ( ( ) )
114+ }
115+ Err ( e) => Err ( format ! ( "Failed to take screenshot: {e}" ) ) ,
116+ }
117+ }
118+ Self :: StartRecording {
112119 capture_mode,
113120 camera,
114121 mic_label,
@@ -117,42 +124,77 @@ impl DeepLinkAction {
117124 } => {
118125 let state = app. state :: < ArcLock < App > > ( ) ;
119126
120- crate :: set_camera_input ( app. clone ( ) , state. clone ( ) , camera, None ) . await ?;
121- crate :: set_mic_input ( state. clone ( ) , mic_label) . await ?;
122-
123- let capture_target: ScreenCaptureTarget = match capture_mode {
124- CaptureMode :: Screen ( name) => cap_recording:: screen_capture:: list_displays ( )
127+ let capture_target = match capture_mode {
128+ CaptureMode :: Screen ( name) => cap_recording:: sources:: screen_capture:: list_displays ( )
125129 . into_iter ( )
126- . find ( |( s, _) | s. name == name)
130+ . find ( |( s, _) | s. name == * name)
127131 . map ( |( s, _) | ScreenCaptureTarget :: Display { id : s. id } )
128132 . ok_or ( format ! ( "No screen with name \" {}\" " , & name) ) ?,
129- CaptureMode :: Window ( name) => cap_recording:: screen_capture:: list_windows ( )
133+ CaptureMode :: Window ( name) => cap_recording:: sources :: screen_capture:: list_windows ( )
130134 . into_iter ( )
131- . find ( |( w, _) | w. name == name)
135+ . find ( |( w, _) | w. name == * name)
132136 . map ( |( w, _) | ScreenCaptureTarget :: Window { id : w. id } )
133137 . ok_or ( format ! ( "No window with name \" {}\" " , & name) ) ?,
134138 } ;
135139
136140 let inputs = StartRecordingInputs {
137- mode,
138141 capture_target,
139142 capture_system_audio,
143+ mode,
140144 organization_id : None ,
141145 } ;
142146
143- crate :: recording:: start_recording ( app. clone ( ) , state, inputs)
147+ if let Some ( camera_id) = camera {
148+ crate :: set_camera_input ( app. clone ( ) , state. clone ( ) , Some ( camera_id. clone ( ) ) , None )
149+ . await
150+ . map_err ( |e| e. to_string ( ) ) ?;
151+ }
152+
153+ if let Some ( mic) = mic_label {
154+ crate :: set_mic_input ( state. clone ( ) , Some ( mic. clone ( ) ) )
155+ . await
156+ . map_err ( |e| e. to_string ( ) ) ?;
157+ }
158+
159+ crate :: recording:: start_recording ( app. clone ( ) , state. clone ( ) , inputs)
144160 . await
145- . map ( |_| ( ) )
146- }
147- DeepLinkAction :: StopRecording => {
148- crate :: recording:: stop_recording ( app. clone ( ) , app. state ( ) ) . await
161+ . map_err ( |e| e. to_string ( ) ) ?;
162+ Ok ( ( ) )
149163 }
150- DeepLinkAction :: OpenEditor { project_path } => {
164+ Self :: OpenEditor { project_path } => {
151165 crate :: open_project_from_path ( Path :: new ( & project_path) , app. clone ( ) )
166+ . map_err ( |e| e. to_string ( ) ) ?;
167+ Ok ( ( ) )
152168 }
153- DeepLinkAction :: OpenSettings { page } => {
154- crate :: show_window ( app. clone ( ) , ShowCapWindow :: Settings { page } ) . await
169+ Self :: OpenSettings { page } => {
170+ crate :: show_window ( app. clone ( ) , ShowCapWindow :: Settings { page : page. clone ( ) } )
171+ . await
172+ . map_err ( |e| e. to_string ( ) ) ?;
173+ Ok ( ( ) )
155174 }
156175 }
157176 }
158177}
178+
179+ pub fn handle ( app_handle : & AppHandle , urls : Vec < Url > ) {
180+ trace ! ( "Handling deep actions for: {:?}" , & urls) ;
181+
182+ let actions: Vec < _ > = urls
183+ . into_iter ( )
184+ . filter ( |url| !url. as_str ( ) . is_empty ( ) )
185+ . filter_map ( |url| DeepLinkAction :: try_from ( & url) . ok ( ) )
186+ . collect ( ) ;
187+
188+ if actions. is_empty ( ) {
189+ return ;
190+ }
191+
192+ let app_handle = app_handle. clone ( ) ;
193+ tauri:: async_runtime:: spawn ( async move {
194+ for action in actions {
195+ if let Err ( e) = action. execute ( & app_handle) . await {
196+ trace ! ( "Failed to handle deep link action: {}" , e) ;
197+ }
198+ }
199+ } ) ;
200+ }
0 commit comments