using Cryville.Common; using Cryville.Crtr.Browsing.Actions; using Cryville.Crtr.UI; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security; namespace Cryville.Crtr.Browsing { internal class FileSystemResourceManager : IPathedResourceManager { DirectoryInfo _cd; FileSystemEntry[] _items = new FileSystemEntry[0]; FileSystemEntry[] _filteredItems = new FileSystemEntry[0]; string _filter = string.Empty; public FileSystemEntry this[int index] { get { return _filteredItems[index]; } } IResourceMeta IResourceManager.this[int index] { get { return this[index]; } } readonly List _dirParts = new(); readonly IList m_dirParts; public IList CurrentDirectory { get { return m_dirParts; } } public int Count { get { return _filteredItems.Length; } } public bool IsReadOnly { get { return true; } } public event Action DirectoryChanged; public event Action ItemChanged; readonly ISet _extFilter = ExtensionManager.GetSupportedFormats(); public FileSystemResourceManager() { m_dirParts = _dirParts.AsReadOnly(); OnDirectoryChange(); } void OnDirectoryChange() { if (_dirParts.Count == 0) { IEnumerable items; #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN items = Directory.GetLogicalDrives().Select(d => new FileSystemEntry(new DirectoryInfo(d))); #elif UNITY_ANDROID items = new FileSystemEntry[] { new FileSystemEntry("Storage", new DirectoryInfo("/sdcard")) }; #else #error No root path searching logic #endif items = items.Concat( ExtensionManager.GetLocalResourcePaths() .Select(p => new FileSystemEntry(p.Key, new DirectoryInfo(p.Value))) ); _items = items.ToArray(); ItemChanged?.Invoke(); } else { var path = string.Join(Path.DirectorySeparatorChar, _dirParts); #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN if (_dirParts.Count == 1) path += Path.DirectorySeparatorChar; #elif UNITY_ANDROID path += Path.DirectorySeparatorChar; #else #error No root path handling logic #endif _cd = new DirectoryInfo(path); try { _items = _cd.GetFileSystemInfos() .Where(i => i is DirectoryInfo || _extFilter.Contains(i.Extension)) .Select(i => new FileSystemEntry(i)).ToArray(); } catch (DirectoryNotFoundException ex) { Popup.CreateException(ex); return; } catch (SecurityException ex) { Popup.CreateException(ex); return; } catch (UnauthorizedAccessException ex) { Popup.CreateException(ex); return; } } ApplyFilter(); DirectoryChanged?.Invoke(); } public void Activate() { } public void Deactivate() { } public Uri GetItemUri(int index) { return new Uri(PlatformConfig.FileProtocolPrefix + _filteredItems[index].FileSystemInfo.FullName); } public void ChangeDirectory(IEnumerable dir) { _dirParts.Clear(); foreach (string dirPart in dir) _dirParts.Add(dirPart); OnDirectoryChange(); } public bool IsDirectory(int index) { return _filteredItems[index].FileSystemInfo is DirectoryInfo; } public void OpenDirectory(int index) { _dirParts.Clear(); foreach (string dirPart in _filteredItems[index].FileSystemInfo.FullName.Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries)) _dirParts.Add(dirPart); OnDirectoryChange(); } public void ReturnToDirectory(int index) { _dirParts.RemoveRange(index + 1, _dirParts.Count - index - 1); OnDirectoryChange(); } public void ApplyFilter(string filter) { _filter = filter; ApplyFilter(); } void ApplyFilter() { IEnumerable items = _items; foreach (var keyword in _filter.Split(' ', StringSplitOptions.RemoveEmptyEntries)) { items = items.Where(i => i.FileSystemInfo.Name.Contains(keyword, StringComparison.CurrentCultureIgnoreCase)); } _filteredItems = items.ToArray(); ItemChanged?.Invoke(); } public IResourceAction GetImportAction() { throw new NotSupportedException(); } public void RemoveAt(int index) { throw new NotSupportedException(); } } internal class FileSystemEntry : IResourceMeta { readonly string _name; public FileSystemInfo FileSystemInfo { get; private set; } public FileSystemEntry(FileSystemInfo fileSystemInfo) : this(fileSystemInfo.Name, fileSystemInfo) { } public FileSystemEntry(string name, FileSystemInfo fileSystemInfo) { _name = name; FileSystemInfo = fileSystemInfo; } public IEnumerable Properties { get { yield return new MetaProperty("Name", _name); if (FileSystemInfo is FileInfo file) { yield return new MetaProperty("Size", new Qualified(file.Length, "B")); } yield return new MetaProperty("Write.Time", FileSystemInfo.LastWriteTime); yield return new MetaProperty("Creation.Time", FileSystemInfo.CreationTime); yield return new MetaProperty("Access.Time", FileSystemInfo.LastAccessTime); } } } }