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;
}
}
}