@@ -181,6 +181,16 @@ func _on_menu_item_pressed(id: int) -> void:
181181 menu_button .get_popup ().set_item_checked (0 , show_all )
182182 _load_root ()
183183
184+ func _show_save_as_dialog (remote_path : String , is_dir : bool ) -> void :
185+ var file_dialog = EditorFileDialog .new ()
186+ file_dialog .access = FileDialog .ACCESS_FILESYSTEM
187+ file_dialog .file_mode = FileDialog .FILE_MODE_OPEN_DIR if is_dir else FileDialog .FILE_MODE_SAVE_FILE
188+ file_dialog .current_file = remote_path .get_file ()
189+ file_dialog .file_selected .connect (_pull_single_file .bind (remote_path ))
190+ file_dialog .dir_selected .connect (_pull_dir .bind (remote_path ))
191+ add_child (file_dialog )
192+ file_dialog .popup_file_dialog ()
193+
184194
185195# ADB Handling--------------------------------------------------------------------------------------
186196
@@ -192,6 +202,7 @@ func _run_adb(p_args: PackedStringArray) -> String:
192202
193203 var output := []
194204 OS .execute (ADB_PATH , args , output , true )
205+ # print(output)
195206 return output [0 ] if output .size () > 0 else ""
196207
197208
@@ -224,6 +235,49 @@ func _list_dir(path: String) -> Array:
224235 return files
225236
226237
238+ func _pull_dir (local_path : String , remote_path : String ) -> void :
239+ if not remote_path .begins_with (DATA_ROOT ):
240+ _run_adb (["pull" , remote_path , local_path ])
241+ return
242+
243+ # special handling for app's private data dir
244+ var ls_cmd = "ls -1 -F '%s '" % remote_path
245+ var output = _run_adb (["shell" , "run-as" , PACKAGE_NAME , ls_cmd ])
246+
247+ local_path = local_path .path_join (remote_path .get_file ()) # Create the base directory in local path
248+ if not DirAccess .dir_exists_absolute (local_path ):
249+ DirAccess .make_dir_recursive_absolute (local_path )
250+
251+ for line in output .split ("\n " ):
252+ line = line .strip_edges ()
253+ if line == "" or line .begins_with ("total" ): continue
254+
255+ var is_dir = line .ends_with ("/" )
256+ var item_name = line .trim_suffix ("/" )
257+ var item_remote_path = remote_path .path_join (item_name )
258+ var item_local_path = local_path .path_join (item_name )
259+
260+ if is_dir :
261+ _pull_dir (item_local_path , item_remote_path )
262+ else :
263+ _pull_single_file (item_local_path , item_remote_path )
264+
265+
266+ func _pull_single_file (local_path : String , remote_path : String ) -> void :
267+ if not remote_path .begins_with (DATA_ROOT ):
268+ _run_adb (["pull" , remote_path , local_path ])
269+ return
270+
271+ # special handling for app's private data dir
272+ var temp_name = "temp_" + str (Time .get_ticks_usec ())
273+ var temp_path = PULL_PUSH_TEMP .path_join (temp_name )
274+
275+ _run_adb (["shell" , "touch" , temp_path ])
276+ var cp_cmd = "cp '%s ' '%s '" % [remote_path , temp_path ]
277+ _run_adb (["shell" , "run-as" , PACKAGE_NAME , cp_cmd ])
278+ _run_adb (["pull" , temp_path , local_path ])
279+ _run_adb (["shell" , "rm" , temp_path ])
280+
227281# ---------------------------------------------------------------------------------------------------
228282
229283func _get_icon_for_ext (path : String ) -> String :
@@ -270,5 +324,8 @@ func create_context_menu() -> void:
270324func _on_context_menu_item_pressed (id : int ) -> void :
271325 var item = tree .get_selected ()
272326 if not item : return
273- print ("context menu pressed: " , id )
327+ match id :
328+ ContextMenu .SAVE_AS :
329+ var meta = item .get_metadata (0 )
330+ _show_save_as_dialog (meta .path , meta .is_dir )
274331
0 commit comments