using System; using System.Collections.Generic; using System.IO; using static UnityEngine.Networking.UnityWebRequest; namespace TriLibCore.SFB { /// /// Provides a platform-specific file browser interface for opening and saving files and folders /// using native dialogs. This static class delegates file browsing operations to an underlying platform‐ /// specific implementation of . /// /// /// The StandaloneFileBrowser class wraps various native file dialog implementations based on the /// target platform (e.g., Unity Editor, Windows, Mac, Linux, Android, iOS, WebGL, UWP). At compile time, /// the appropriate platform-specific implementation is assigned to the internal _platformWrapper field. /// If no implementation is available for the target platform, the file browsing operations will not function. /// /// The class exposes both synchronous and asynchronous methods for opening files, opening folders, and saving files, /// with support for extension filters to limit file types. Asynchronous methods use callbacks to return user selections. /// public class StandaloneFileBrowser { #if UNITY_EDITOR private static IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserEditor(); #else #if UNITY_WSA private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserWinRT(); #elif UNITY_ANDROID private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserAndroid(); #elif UNITY_WEBGL private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserWebGL(); #elif UNITY_STANDALONE_OSX private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserMac(); #elif UNITY_IOS private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserIOS(); #elif UNITY_STANDALONE_WIN private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserWindows(); #elif UNITY_STANDALONE_LINUX private static readonly IStandaloneFileBrowser _platformWrapper = new StandaloneFileBrowserLinux(); #else private static readonly IStandaloneFileBrowser _platformWrapper = null; #endif #endif /// /// Opens a native file dialog for selecting files. /// /// The title of the dialog window. /// The initial directory to display. /// A string representing the allowed file extension (e.g., "png"). /// If true, allows multiple files to be selected; otherwise, only one file. /// /// An containing the selected items, or an empty list if the dialog is cancelled. /// public static IList OpenFilePanel(string title, string directory, string extension, bool multiselect) { var extensions = string.IsNullOrEmpty(extension) ? null : new[] { new ExtensionFilter("", extension) }; return OpenFilePanel(title, directory, extensions, multiselect); } /// /// Opens a native file dialog for selecting files. /// /// The title of the dialog window. /// The initial directory to display. /// /// An array of objects specifying allowed file types (e.g., /// new ExtensionFilter("Image Files", "jpg", "png")). /// /// If true, allows multiple files to be selected; otherwise, only one file. /// /// An containing the selected items, or an empty list if the dialog is cancelled. /// public static IList OpenFilePanel(string title, string directory, ExtensionFilter[] extensions, bool multiselect) { return _platformWrapper.OpenFilePanel(title, directory, extensions, multiselect); } /// /// Opens a native file dialog asynchronously for selecting files. /// /// The title of the dialog window. /// The initial directory to display. /// A string representing the allowed file extension (e.g., "png"). /// If true, allows multiple files to be selected. /// /// A callback action to be invoked with the list of selected items (or an empty list if cancelled). /// public static void OpenFilePanelAsync(string title, string directory, string extension, bool multiselect, Action> cb) { var extensions = string.IsNullOrEmpty(extension) ? null : new[] { new ExtensionFilter("", extension) }; OpenFilePanelAsync(title, directory, extensions, multiselect, cb); } /// /// Opens a native file dialog asynchronously for selecting files. /// /// The title of the dialog window. /// The initial directory to display. /// /// An array of objects specifying allowed file types. /// /// If true, allows multiple files to be selected. /// /// A callback action to be invoked with the list of selected items (or an empty list if cancelled). /// public static void OpenFilePanelAsync(string title, string directory, ExtensionFilter[] extensions, bool multiselect, Action> cb) { _platformWrapper.OpenFilePanelAsync(title, directory, extensions, multiselect, cb); } /// /// Opens a native folder dialog for selecting a folder. /// /// The title of the folder dialog. /// The initial directory to display. /// If true, allows multiple folder selections; otherwise, only one folder can be selected. /// /// An containing the selected folder(s), or an empty list if cancelled. /// public static IList OpenFolderPanel(string title, string directory, bool multiselect) { return _platformWrapper.OpenFolderPanel(title, directory, multiselect); } /// /// Opens a native folder dialog asynchronously for selecting a folder. /// /// The title of the folder dialog. /// The initial directory to display. /// If true, allows multiple folder selections; otherwise, only one folder can be selected. /// /// A callback action to be invoked with the list of selected folder items (or an empty list if cancelled). /// public static void OpenFolderPanelAsync(string title, string directory, bool multiselect, Action> cb) { _platformWrapper.OpenFolderPanelAsync(title, directory, multiselect, cb); } /// /// Opens a native save file dialog. /// /// The title of the save dialog. /// The initial directory to display. /// The default file name to pre-populate in the dialog. /// A string representing the allowed file extension (e.g., "txt"). /// /// An representing the chosen file, or null if the dialog was cancelled. /// public static ItemWithStream SaveFilePanel(string title, string directory, string defaultName, string extension) { var extensions = string.IsNullOrEmpty(extension) ? null : new[] { new ExtensionFilter("", extension) }; return SaveFilePanel(title, directory, defaultName, extensions); } /// /// Opens a native save file dialog. /// /// The title of the save dialog. /// The initial directory to display. /// The default file name to pre-populate in the dialog. /// /// An array of objects specifying allowed file types. /// /// /// An representing the chosen file, or null if cancelled. /// public static ItemWithStream SaveFilePanel(string title, string directory, string defaultName, ExtensionFilter[] extensions) { return _platformWrapper.SaveFilePanel(title, directory, defaultName, extensions); } /// /// Opens a native save file dialog asynchronously. /// /// The title of the save file dialog. /// The initial directory to display. /// The default file name to pre-populate in the dialog. /// A string representing the allowed file extension. /// /// A callback action that is invoked with the selected file item, or null if cancelled. /// /// /// Optional data to be saved (used on WebGL platform). /// public static void SaveFilePanelAsync(string title, string directory, string defaultName, string extension, Action cb, byte[] data = null) { var extensions = string.IsNullOrEmpty(extension) ? null : new[] { new ExtensionFilter("", extension) }; SaveFilePanelAsync(title, directory, defaultName, extensions, cb, data); } /// /// Opens a native save file dialog asynchronously. /// /// The title of the save file dialog. /// The initial directory to display. /// The default file name to pre-populate in the dialog. /// /// An array of objects specifying allowed file types. /// /// /// A callback action that is invoked with the selected file item, or null if cancelled. /// /// /// Optional data to be saved (used on WebGL platform). /// public static void SaveFilePanelAsync(string title, string directory, string defaultName, ExtensionFilter[] extensions, Action cb, byte[] data = null) { #if UNITY_WEBGL && !UNITY_EDITOR if (_platformWrapper is StandaloneFileBrowserWebGL standaloneFileBrowserWebGL) { standaloneFileBrowserWebGL.Data = data; } #endif _platformWrapper.SaveFilePanelAsync(title, directory, defaultName, extensions, cb); } internal static ItemWithStream BuildItemFromSingleFilename(IList filenames) { if (filenames?.Count > 0) { return new ItemWithStream() { Name = filenames[0] }; } return null; } internal static IList BuildItemsFromFilenames(IList filenames) { if (filenames?.Count > 0) { var results = new ItemWithStream[filenames.Count]; for (var i = 0; i < filenames.Count; i++) { results[i] = new ItemWithStream() { Name = filenames[i] }; } return results; } return null; } internal static IList BuildItemsFromFolderContents(string filename) { if (Directory.Exists(filename)) { var directoryFilenames = Directory.GetFiles(filename); return BuildItemsFromFilenames(directoryFilenames); } return null; } } }