Fix RootDriveInfo not show every drive

This commit is contained in:
2023-09-06 09:29:29 +02:00
parent 0e6c0c5cd5
commit 67484ba56b
9 changed files with 82 additions and 70 deletions

View File

@@ -7,7 +7,6 @@ namespace FileTime.GuiApp.App.ViewModels;
public interface IGuiAppState : IAppState
{
ObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
IReadOnlyList<PlaceInfo> Places { get; set; }
ObservableCollection<string> PopupTexts { get; }
IObservable<GuiPanel> ActivePanel { get; }

View File

@@ -6,6 +6,7 @@ using FileTime.App.Core.ViewModels.Timeline;
using FileTime.App.FrequencyNavigation.Services;
using FileTime.GuiApp.App.CloudDrives;
using FileTime.GuiApp.App.Services;
using FileTime.Providers.Local;
using FileTime.Providers.LocalAdmin;
namespace FileTime.GuiApp.App.ViewModels;
@@ -23,6 +24,7 @@ public interface IMainWindowViewModel : IMainWindowViewModelBase
ITimelineViewModel TimelineViewModel { get; }
IPossibleCommandsViewModel PossibleCommands { get; }
ICloudDriveService CloudDriveService { get; }
IRootDriveInfoService RootDriveInfoService { get; }
Action? ShowWindow { get; set; }
Thickness IconStatusPanelMargin { get; }
Task RunOrOpenItem(IItemViewModel itemViewModel);

View File

@@ -45,6 +45,7 @@ namespace FileTime.GuiApp.App.ViewModels;
[Inject(typeof(IPossibleCommandsViewModel), PropertyName = "PossibleCommands", PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(IInstanceMessageHandler), PropertyName = "_instanceMessageHandler")]
[Inject(typeof(ICloudDriveService), PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(IRootDriveInfoService), PropertyAccessModifier = AccessModifier.Public)]
public partial class MainWindowViewModel : IMainWindowViewModel
{
public bool Loading => false;

View File

@@ -128,12 +128,13 @@
<ItemsRepeater
Grid.Row="1"
ItemsSource="{Binding AppState.RootDriveInfos}">
ItemsSource="{Binding RootDriveInfoService.RootDriveInfos}">
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="local1:RootDriveInfo">
<Grid
Classes="SidebarContainerPresenter"
PointerPressed="OnHasContainerPointerPressed">
PointerPressed="OnHasContainerPointerPressed"
ToolTip.Tip="{Binding FullName}">
<Grid
Margin="10,5"
ColumnDefinitions="Auto,*,Auto"
@@ -147,6 +148,7 @@
Source="{SvgImage /Assets/material/folder.svg}" />
<StackPanel
Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
@@ -155,7 +157,7 @@
<TextBlock
Margin="5,0,0,0"
VerticalAlignment="Center"
Text="{Binding FullName}" />
Text="{Binding Name}" />
<TextBlock
Margin="5,0,0,0"

View File

@@ -13,17 +13,14 @@ public partial class GuiAppState : AppStateBase, IGuiAppState, IDisposable
{
private readonly BehaviorSubject<GuiPanel> _activePanel = new(GuiPanel.FileBrowser);
[Notify] private ObservableCollection<RootDriveInfo> _rootDriveInfos;
[Notify] private IReadOnlyList<PlaceInfo> _places = new List<PlaceInfo>();
public ObservableCollection<string> PopupTexts { get; } = new();
public IObservable<GuiPanel> ActivePanel { get; }
public GuiAppState(IRootDriveInfoService rootDriveInfoService)
public GuiAppState()
{
ActivePanel = _activePanel.AsObservable();
_rootDriveInfos = rootDriveInfoService.RootDriveInfos;
}
public void SetActivePanel(GuiPanel newPanel)

View File

@@ -5,5 +5,6 @@ namespace FileTime.Providers.Local;
public interface IRootDriveInfoService : IExitHandler
{
ObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
ReadOnlyObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
ReadOnlyObservableCollection<DriveInfo> AllDrives { get; set; }
}

View File

@@ -31,14 +31,7 @@ public partial class RootDriveInfo
_name = container.Name;
_fullName = _name;
try
{
_fullName = container.FullName?.Path[(container.Provider.FullName!.Path.Length + 1)..] ?? _fullName;
}
catch
{
}
_fullName = driveInfo.Name;
Path = container.FullName ?? throw new NullReferenceException($"Container does not have a {nameof(FullName)}");

View File

@@ -14,7 +14,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IContentProviderRegistry _contentProviderRegistry;
private readonly bool _isCaseInsensitive;
private readonly Lazy<ObservableCollection<RootDriveInfo>> _rootDriveInfos;
private readonly Lazy<IRootDriveInfoService> _rootDriveInfo;
public LocalContentProvider(
ITimelessContentProvider timelessContentProvider,
@@ -26,7 +26,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
_contentProviderRegistry = contentProviderRegistry;
_isCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
_rootDriveInfos = new Lazy<ObservableCollection<RootDriveInfo>>(() => serviceProvider.GetRequiredService<IRootDriveInfoService>().RootDriveInfos);
_rootDriveInfo = new Lazy<IRootDriveInfoService>(serviceProvider.GetRequiredService<IRootDriveInfoService>);
SupportsContentStreams = true;
@@ -68,12 +68,26 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
public override ValueTask<VolumeSizeInfo?> GetVolumeSizeInfoAsync(FullName path)
{
var rootDriveInfos = _rootDriveInfos.Value;
var rootDriveInfo = rootDriveInfos.FirstOrDefault(d => path.Path.StartsWith(d.Path.Path));
var nativePath = GetNativePath(path);
var possibleRootDrives = _rootDriveInfo.Value.AllDrives.Where(d => nativePath.Path.StartsWith(d.RootDirectory.FullName)).ToArray();
var rootDrive = possibleRootDrives.Length == 0
? null
: possibleRootDrives.MaxBy(d => d.RootDirectory.FullName.Length);
return rootDrive is null
? ValueTask.FromResult<VolumeSizeInfo?>(null)
: ValueTask.FromResult<VolumeSizeInfo?>(new VolumeSizeInfo(rootDrive.TotalSize, rootDrive.AvailableFreeSpace));
/*var rootDriveInfos = _rootDriveInfo.Value;
var possibleRootDriveInfo = rootDriveInfos.RootDriveInfos.Where(d => path.Path.StartsWith(d.Path.Path)).ToArray();
var rootDriveInfo = possibleRootDriveInfo.Length == 0
? null
: possibleRootDriveInfo.MaxBy(d => d.FullName.Length);
if (rootDriveInfo is null) return ValueTask.FromResult<VolumeSizeInfo?>(null);
return ValueTask.FromResult<VolumeSizeInfo?>(new VolumeSizeInfo(rootDriveInfo.Size, rootDriveInfo.Free));
return ValueTask.FromResult<VolumeSizeInfo?>(new VolumeSizeInfo(rootDriveInfo.Size, rootDriveInfo.Free));*/
}
public override async Task<IItem> GetItemByNativePathAsync(NativePath nativePath,
@@ -103,7 +117,8 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
return FileToElement(new FileInfo(path), pointInTime);
}
var pathParts = path.Split(Path.DirectorySeparatorChar).SelectMany(p => p.Split(Constants.SeparatorChar)).ToArray();
var pathParts = path.Split(Path.DirectorySeparatorChar).SelectMany(p => p.Split(Constants.SeparatorChar))
.ToArray();
for (var i = pathParts.Length - 1; i > 0; i--)
{
@@ -116,7 +131,8 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
var subPath = string.Join(Constants.SeparatorChar, pathParts.Skip(i));
var resolvedItem = await subContentProvider.GetItemByFullNameAsync(element, new FullName(subPath), pointInTime, forceResolvePathType, itemInitializationSettings);
var resolvedItem = await subContentProvider.GetItemByFullNameAsync(element, new FullName(subPath),
pointInTime, forceResolvePathType, itemInitializationSettings);
if (resolvedItem is not null)
{
@@ -155,7 +171,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
AbsolutePathType.Container => CreateEmptyContainer(
nativePath,
pointInTime,
new List<Exception> {innerException}
new List<Exception> { innerException }
),
AbsolutePathType.Element => CreateEmptyElement(nativePath),
_ => throw new Exception(
@@ -167,7 +183,8 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
public override ValueTask<NativePath?> GetSupportedPathPart(NativePath nativePath)
{
var path = nativePath.Path;
var pathParts = path.Split(Path.DirectorySeparatorChar).SelectMany(p => p.Split(Constants.SeparatorChar)).ToArray();
var pathParts = path.Split(Path.DirectorySeparatorChar).SelectMany(p => p.Split(Constants.SeparatorChar))
.ToArray();
for (var i = pathParts.Length - 1; i > 0; i--)
{
@@ -440,7 +457,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
var finalSize = size switch
{
> int.MaxValue => int.MaxValue,
_ => (int) size
_ => (int)size
};
var buffer = new byte[finalSize];
var realSize = await reader.ReadAsync(buffer.AsMemory(0, finalSize), cancellationToken);

View File

@@ -1,6 +1,7 @@
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
using ObservableComputations;
namespace FileTime.Providers.Local;
@@ -8,66 +9,65 @@ namespace FileTime.Providers.Local;
public class RootDriveInfoService : IRootDriveInfoService
{
private readonly ILocalContentProvider _localContentProvider;
private readonly List<DriveInfo> _rootDrives = new();
private readonly ObservableCollection<DriveInfo> _rootDrives = new();
private readonly ObservableCollection<DriveInfo> _allDrives = new();
private readonly OcConsumer _rootDriveInfosConsumer = new();
public ObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
public ReadOnlyObservableCollection<DriveInfo> AllDrives { get; set; }
public ReadOnlyObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
public RootDriveInfoService(ILocalContentProvider localContentProvider)
{
_localContentProvider = localContentProvider;
InitRootDrives();
var (rootDrives, allDrives) = GetRootDrives();
var rootDriveInfos = localContentProvider.Items.Selecting<AbsolutePath, (AbsolutePath Path, DriveInfo? Drive)>(
i => MatchRootDrive(i)
)
.Filtering(t => IsNotNull(t.Drive))
.Selecting(t => Resolve(t))
.Filtering(t => t.Item is IContainer)
.Selecting(t => new RootDriveInfo(t.Drive, (IContainer) t.Item!))
.Ordering(d => d.Name);
rootDriveInfos.For(_rootDriveInfosConsumer);
RootDriveInfos = rootDriveInfos;
void InitRootDrives()
foreach (var driveInfo in rootDrives)
{
var drives = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Fixed)
: DriveInfo.GetDrives().Where(d =>
d.DriveType == DriveType.Fixed
_rootDrives.Add(driveInfo);
}
foreach (var driveInfo in allDrives)
{
_allDrives.Add(driveInfo);
}
var rootDriveInfos = _rootDrives.Selecting(r => GetContainer(r))
.Filtering(t => t.Item != null)
.Selecting(t => new RootDriveInfo(t.Drive, t.Item!))
.Ordering(d => d.Name)
.For(_rootDriveInfosConsumer);
RootDriveInfos = new ReadOnlyObservableCollection<RootDriveInfo>(rootDriveInfos);
AllDrives = new ReadOnlyObservableCollection<DriveInfo>(_allDrives);
(DriveInfo[] RootDrives, DriveInfo[] AllDrives) GetRootDrives()
{
var allDrives = DriveInfo.GetDrives();
var drives = DriveInfo.GetDrives().Where(d => d.DriveType is not DriveType.Unknown and not DriveType.Ram);
drives = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? drives
: drives.Where(d =>
d.TotalSize != 0
&& d.DriveFormat != "pstorefs"
&& d.DriveFormat != "bpf_fs"
&& d.DriveFormat != "tracefs"
&& d.DriveFormat != "rpc_pipefs"
&& !d.RootDirectory.FullName.StartsWith("/snap/"));
_rootDrives.Clear();
_rootDrives.AddRange(drives);
return (drives.ToArray(), allDrives);
}
}
private static bool IsNotNull(object? obj) => obj is not null;
private static (IItem? Item, DriveInfo Drive) Resolve((AbsolutePath Path, DriveInfo? Drive) tuple)
private (DriveInfo Drive, IContainer? Item) GetContainer(DriveInfo rootDriveInfo)
{
var t = Task.Run(async () => await tuple.Path.ResolveAsyncSafe());
t.Wait();
return (Item: t.Result, Drive: tuple.Drive!);
}
var task = Task.Run(
async () => await _localContentProvider.GetItemByNativePathAsync(
new NativePath(rootDriveInfo.RootDirectory.FullName),
PointInTime.Present)
);
task.Wait();
private (AbsolutePath Path, DriveInfo? Drive) MatchRootDrive(AbsolutePath sourceItem)
{
var rootDrive = _rootDrives.FirstOrDefault(d =>
{
var containerPath = _localContentProvider.GetNativePath(sourceItem.Path).Path;
var drivePath = d.Name.TrimEnd(Path.DirectorySeparatorChar);
return containerPath == drivePath
|| (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && containerPath == "/" &&
d.Name == "/");
});
return (Path: sourceItem, Drive: rootDrive);
return (rootDriveInfo, task.Result as IContainer);
}
public Task ExitAsync(CancellationToken token = default)