Add Explorer Workbench with hierarchical, off-UI Storage analysis.
Storage queries run in the background with cancellation and covering indexes so switching views no longer freezes the UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
75
src/Explorer.Presentation/ViewModels/FolderItemViewModel.cs
Normal file
75
src/Explorer.Presentation/ViewModels/FolderItemViewModel.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Explorer.Domain;
|
||||
|
||||
namespace Explorer.Presentation;
|
||||
|
||||
public sealed partial class FolderItemViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty] private bool _isSelected;
|
||||
|
||||
public FolderItemViewModel(FileSystemItem item, bool sizeFromIndex)
|
||||
{
|
||||
Item = item;
|
||||
SizeFromIndex = sizeFromIndex;
|
||||
}
|
||||
|
||||
public FileSystemItem Item { get; }
|
||||
public bool SizeFromIndex { get; }
|
||||
public string Name => Item.Name;
|
||||
public string FullPath => Item.FullPath;
|
||||
public bool IsDirectory => Item.IsDirectory;
|
||||
public string TypeLabel => Item.IsDirectory ? "File folder" : (Item.ExtensionDisplay());
|
||||
public string SizeLabel => Item.IsDirectory && !SizeFromIndex && Item.SizeBytes == 0
|
||||
? ""
|
||||
: Formatters.Size(Item.SizeBytes);
|
||||
public string ModifiedLabel => Formatters.Date(Item.ModifiedUtc);
|
||||
public string CreatedLabel => Formatters.Date(Item.CreatedUtc);
|
||||
public string IconGlyph => Item.IsDirectory ? "\uE8B7" : "\uE8A5";
|
||||
public bool IsImage => !Item.IsDirectory && MediaKinds.IsImage(Item.Name);
|
||||
public bool IsVideo => !Item.IsDirectory && MediaKinds.IsVideo(Item.Name);
|
||||
public bool MayHydrateOnRead => Item.Cloud?.MayHydrateOnRead == true
|
||||
|| AttributeFlags.MayHydrateOnRead(Item.Attributes);
|
||||
public string CloudStatus => Item.Cloud?.StatusText ?? "";
|
||||
public bool HasCloudStatus => !string.IsNullOrEmpty(CloudStatus);
|
||||
public string SizeTooltip
|
||||
{
|
||||
get
|
||||
{
|
||||
var logical = SizeLabel;
|
||||
var allocated = Item.AllocatedSizeBytes ?? Item.Cloud?.AllocatedSizeBytes;
|
||||
if (allocated is long disk && disk != Item.SizeBytes && !Item.IsDirectory)
|
||||
{
|
||||
return string.IsNullOrEmpty(CloudStatus)
|
||||
? $"Size {logical} · On disk {Formatters.Size(disk)}"
|
||||
: $"{CloudStatus} · Size {logical} · On disk {Formatters.Size(disk)}";
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(CloudStatus) ? logical : $"{CloudStatus} · {logical}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class MediaKinds
|
||||
{
|
||||
private static readonly HashSet<string> Images = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".tif", ".tiff", ".ico", ".jfif"
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> Videos = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
".mp4", ".mkv", ".avi", ".mov", ".wmv", ".webm", ".m4v", ".mpg", ".mpeg"
|
||||
};
|
||||
|
||||
public static bool IsImage(string name) => Images.Contains(Path.GetExtension(name));
|
||||
public static bool IsVideo(string name) => Videos.Contains(Path.GetExtension(name));
|
||||
}
|
||||
|
||||
file static class ItemExt
|
||||
{
|
||||
public static string ExtensionDisplay(this FileSystemItem item)
|
||||
{
|
||||
var ext = NameNormalizer.Extension(item.Name);
|
||||
return string.IsNullOrEmpty(ext) ? "File" : ext.ToUpperInvariant() + " file";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user