Parent's children, optimalizations
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Reactive.Concurrency;
|
||||||
|
|
||||||
|
namespace FileTime.App.Core.Services
|
||||||
|
{
|
||||||
|
public interface IRxSchedulerService
|
||||||
|
{
|
||||||
|
IScheduler GetWorkerScheduler();
|
||||||
|
IScheduler GetUIScheduler();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,5 +15,6 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
IObservable<IReadOnlyList<IItemViewModel>> CurrentItems { get; }
|
IObservable<IReadOnlyList<IItemViewModel>> CurrentItems { get; }
|
||||||
IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
||||||
IObservable<IReadOnlyList<IItemViewModel>?> SelectedsChildren { get; }
|
IObservable<IReadOnlyList<IItemViewModel>?> SelectedsChildren { get; }
|
||||||
|
IObservable<IReadOnlyList<IItemViewModel>?> ParentsChildren { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
|
using System.Reactive.Concurrency;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using FileTime.App.Core.Extensions;
|
using FileTime.App.Core.Extensions;
|
||||||
using FileTime.App.Core.Models.Enums;
|
|
||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using FileTime.Core.Enums;
|
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -15,6 +14,7 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IItemNameConverterService _itemNameConverterService;
|
private readonly IItemNameConverterService _itemNameConverterService;
|
||||||
private readonly IAppState _appState;
|
private readonly IAppState _appState;
|
||||||
|
private readonly IRxSchedulerService _rxSchedulerService;
|
||||||
private readonly BehaviorSubject<IEnumerable<FullName>> _markedItems = new(Enumerable.Empty<FullName>());
|
private readonly BehaviorSubject<IEnumerable<FullName>> _markedItems = new(Enumerable.Empty<FullName>());
|
||||||
private readonly List<IDisposable> _disposables = new();
|
private readonly List<IDisposable> _disposables = new();
|
||||||
private bool disposed;
|
private bool disposed;
|
||||||
@@ -29,11 +29,13 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
public IObservable<IReadOnlyList<IItemViewModel>> CurrentItems { get; private set; } = null!;
|
public IObservable<IReadOnlyList<IItemViewModel>> CurrentItems { get; private set; } = null!;
|
||||||
public IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
public IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
||||||
public IObservable<IReadOnlyList<IItemViewModel>?> SelectedsChildren { get; private set; } = null!;
|
public IObservable<IReadOnlyList<IItemViewModel>?> SelectedsChildren { get; private set; } = null!;
|
||||||
|
public IObservable<IReadOnlyList<IItemViewModel>?> ParentsChildren { get; private set; } = null!;
|
||||||
|
|
||||||
public TabViewModel(
|
public TabViewModel(
|
||||||
IServiceProvider serviceProvider,
|
IServiceProvider serviceProvider,
|
||||||
IItemNameConverterService itemNameConverterService,
|
IItemNameConverterService itemNameConverterService,
|
||||||
IAppState appState)
|
IAppState appState,
|
||||||
|
IRxSchedulerService rxSchedulerService)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_itemNameConverterService = itemNameConverterService;
|
_itemNameConverterService = itemNameConverterService;
|
||||||
@@ -41,6 +43,7 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
|
|
||||||
MarkedItems = _markedItems.Select(e => e.ToList()).AsObservable();
|
MarkedItems = _markedItems.Select(e => e.ToList()).AsObservable();
|
||||||
IsSelected = _appState.SelectedTab.Select(s => s == this);
|
IsSelected = _appState.SelectedTab.Select(s => s == this);
|
||||||
|
_rxSchedulerService = rxSchedulerService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(ITab tab, int tabNumber)
|
public void Init(ITab tab, int tabNumber)
|
||||||
@@ -49,7 +52,16 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
TabNumber = tabNumber;
|
TabNumber = tabNumber;
|
||||||
|
|
||||||
CurrentLocation = tab.CurrentLocation.AsObservable();
|
CurrentLocation = tab.CurrentLocation.AsObservable();
|
||||||
CurrentItems = tab.CurrentItems.Select(items => items.Select(MapItemToViewModel).ToList()).Publish(new List<IItemViewModel>()).RefCount();
|
CurrentItems = tab.CurrentItems
|
||||||
|
.Select(items =>
|
||||||
|
items == null
|
||||||
|
? new List<IItemViewModel>()
|
||||||
|
: items.Select(MapItemToViewModel).ToList())
|
||||||
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
|
.Publish(new List<IItemViewModel>())
|
||||||
|
.RefCount();
|
||||||
|
|
||||||
CurrentSelectedItem =
|
CurrentSelectedItem =
|
||||||
Observable.CombineLatest(
|
Observable.CombineLatest(
|
||||||
CurrentItems,
|
CurrentItems,
|
||||||
@@ -73,7 +85,36 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
currentSelectedItemThrottled
|
currentSelectedItemThrottled
|
||||||
.Where(c => c is null || c is not IContainerViewModel)
|
.Where(c => c is null || c is not IContainerViewModel)
|
||||||
.Select(_ => (IReadOnlyList<IItemViewModel>?)null)
|
.Select(_ => (IReadOnlyList<IItemViewModel>?)null)
|
||||||
);
|
)
|
||||||
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
|
.Publish(null)
|
||||||
|
.RefCount();
|
||||||
|
|
||||||
|
var parentThrottled = CurrentLocation
|
||||||
|
.Select(l => l?.Parent)
|
||||||
|
.DistinctUntilChanged()
|
||||||
|
.Publish(null)
|
||||||
|
.RefCount();
|
||||||
|
|
||||||
|
ParentsChildren = Observable.Merge(
|
||||||
|
parentThrottled
|
||||||
|
.Where(p => p is not null)
|
||||||
|
.Select(p => Observable.FromAsync(async () => (IContainer)await p!.ResolveAsync()))
|
||||||
|
.Switch()
|
||||||
|
.Select(p => p.Items)
|
||||||
|
.Switch()
|
||||||
|
.Select(items => Observable.FromAsync(async () => await Map(items)))
|
||||||
|
.Switch()
|
||||||
|
.Select(items => items?.Select(MapItemToViewModel).ToList()),
|
||||||
|
parentThrottled
|
||||||
|
.Where(p => p is null)
|
||||||
|
.Select(_ => (IReadOnlyList<IItemViewModel>?)null)
|
||||||
|
)
|
||||||
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
|
.Publish(null)
|
||||||
|
.RefCount();
|
||||||
|
|
||||||
tab.CurrentLocation.Subscribe((_) => _markedItems.OnNext(Enumerable.Empty<FullName>()));
|
tab.CurrentLocation.Subscribe((_) => _markedItems.OnNext(Enumerable.Empty<FullName>()));
|
||||||
|
|
||||||
@@ -83,7 +124,7 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
|
|
||||||
return await items
|
return await items
|
||||||
.ToAsyncEnumerable()
|
.ToAsyncEnumerable()
|
||||||
.SelectAwait(async i => await i.ResolveAsync(true))
|
.SelectAwait(async i => await i.ResolveAsync(forceResolve: true, itemInitializationSettings: new ItemInitializationSettings(true)))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace FileTime.Core.Models
|
|||||||
FullName Path { get; }
|
FullName Path { get; }
|
||||||
AbsolutePathType Type { get; }
|
AbsolutePathType Type { get; }
|
||||||
|
|
||||||
Task<IItem> ResolveAsync(bool forceResolve = false);
|
Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default);
|
||||||
Task<IItem?> ResolveAsyncSafe(bool forceResolve = false);
|
Task<IItem?> ResolveAsyncSafe(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace FileTime.Core.Models
|
||||||
|
{
|
||||||
|
public readonly struct ItemInitializationSettings
|
||||||
|
{
|
||||||
|
public readonly bool SkipChildInitialization;
|
||||||
|
|
||||||
|
public ItemInitializationSettings(bool skipChildInitialization)
|
||||||
|
{
|
||||||
|
SkipChildInitialization = skipChildInitialization;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,18 @@ namespace FileTime.Core.Services
|
|||||||
{
|
{
|
||||||
public interface IContentProvider : IContainer, IOnContainerEnter
|
public interface IContentProvider : IContainer, IOnContainerEnter
|
||||||
{
|
{
|
||||||
Task<IItem> GetItemByFullNameAsync(FullName fullName, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown);
|
Task<IItem> GetItemByFullNameAsync(
|
||||||
Task<IItem> GetItemByNativePathAsync(NativePath nativePath, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown);
|
FullName fullName,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
|
||||||
|
Task<IItem> GetItemByNativePathAsync(
|
||||||
|
NativePath nativePath,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
|
||||||
Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,17 +19,17 @@ namespace FileTime.Core.Models
|
|||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IItem> ResolveAsync(bool forceResolve = false)
|
public async Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
||||||
{
|
{
|
||||||
var provider = VirtualContentProvider ?? ContentProvider;
|
var provider = VirtualContentProvider ?? ContentProvider;
|
||||||
return await provider.GetItemByFullNameAsync(Path, forceResolve, Type);
|
return await provider.GetItemByFullNameAsync(Path, forceResolve, Type, itemInitializationSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IItem?> ResolveAsyncSafe(bool forceResolve = false)
|
public async Task<IItem?> ResolveAsyncSafe(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await ResolveAsync(forceResolve);
|
return await ResolveAsync(forceResolve, itemInitializationSettings);
|
||||||
}
|
}
|
||||||
catch { return null; }
|
catch { return null; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,17 @@ namespace FileTime.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task OnEnter() => Task.CompletedTask;
|
public virtual Task OnEnter() => Task.CompletedTask;
|
||||||
public virtual async Task<IItem> GetItemByFullNameAsync(FullName fullName, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown)
|
public virtual async Task<IItem> GetItemByFullNameAsync(
|
||||||
=> await GetItemByNativePathAsync(GetNativePath(fullName), forceResolve, forceResolvePathType);
|
FullName fullName,
|
||||||
public abstract Task<IItem> GetItemByNativePathAsync(NativePath nativePath, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown);
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
|
=> await GetItemByNativePathAsync(GetNativePath(fullName), forceResolve, forceResolvePathType, itemInitializationSettings);
|
||||||
|
public abstract Task<IItem> GetItemByNativePathAsync(
|
||||||
|
NativePath nativePath,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
public abstract Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
public abstract Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
||||||
public abstract NativePath GetNativePath(FullName fullName);
|
public abstract NativePath GetNativePath(FullName fullName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace FileTime.Core.Services
|
|||||||
|
|
||||||
public Tab()
|
public Tab()
|
||||||
{
|
{
|
||||||
CurrentLocation = _currentLocation.DistinctUntilChanged().Do(_ => {; }).Publish(null).RefCount();
|
CurrentLocation = _currentLocation.DistinctUntilChanged().Publish(null).RefCount();
|
||||||
CurrentItems =
|
CurrentItems =
|
||||||
Observable.Merge(
|
Observable.Merge(
|
||||||
CurrentLocation
|
CurrentLocation
|
||||||
@@ -69,7 +69,7 @@ namespace FileTime.Core.Services
|
|||||||
private IObservable<IAbsolutePath?> GetSelectedItemByLocation(IContainer? currentLocation)
|
private IObservable<IAbsolutePath?> GetSelectedItemByLocation(IContainer? currentLocation)
|
||||||
{
|
{
|
||||||
//TODO:
|
//TODO:
|
||||||
return currentLocation?.Items?.Select(i => i.FirstOrDefault()) ?? Observable.Return((IAbsolutePath?)null);
|
return currentLocation?.Items?.Select(i => i?.FirstOrDefault()) ?? Observable.Return((IAbsolutePath?)null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace FileTime.GuiApp
|
|||||||
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
|
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
|
||||||
.AddSingleton<DefaultModeKeyInputHandler>()
|
.AddSingleton<DefaultModeKeyInputHandler>()
|
||||||
.AddSingleton<RapidTravelModeKeyInputHandler>()
|
.AddSingleton<RapidTravelModeKeyInputHandler>()
|
||||||
|
.AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>()
|
||||||
//TODO: move??
|
//TODO: move??
|
||||||
.AddTransient<ITab, Tab>()
|
.AddTransient<ITab, Tab>()
|
||||||
.AddTransient<ITabViewModel, TabViewModel>()
|
.AddTransient<ITabViewModel, TabViewModel>()
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Reactive.Concurrency;
|
||||||
|
using FileTime.App.Core.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace FileTime.GuiApp.Services
|
||||||
|
{
|
||||||
|
public class AvaloniaRxSchedulerService : IRxSchedulerService
|
||||||
|
{
|
||||||
|
public IScheduler GetUIScheduler() => RxApp.MainThreadScheduler;
|
||||||
|
|
||||||
|
public IScheduler GetWorkerScheduler() => RxApp.TaskpoolScheduler;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,6 +103,23 @@
|
|||||||
<ColumnDefinition Width="45*" />
|
<ColumnDefinition Width="45*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<ListBox
|
||||||
|
x:CompileBindings="False"
|
||||||
|
AutoScrollToSelectedItem="True"
|
||||||
|
Classes="ContentListView"
|
||||||
|
IsTabStop="True"
|
||||||
|
Items="{Binding AppState.SelectedTab^.ParentsChildren^}"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Visible">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="corevm:IItemViewModel">
|
||||||
|
<local:ItemView
|
||||||
|
ShowAttributes="False"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
<Rectangle
|
<Rectangle
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@@ -112,7 +129,6 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Fill="{DynamicResource ContentSeparatorBrush}" />
|
Fill="{DynamicResource ContentSeparatorBrush}" />
|
||||||
|
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
RowDefinitions="Auto,*">
|
RowDefinitions="Auto,*">
|
||||||
|
|||||||
@@ -19,17 +19,5 @@ namespace FileTime.Providers.Local
|
|||||||
+ ((directoryInfo.Attributes & FileAttributes.System) == FileAttributes.System ? "s" : "-");
|
+ ((directoryInfo.Attributes & FileAttributes.System) == FileAttributes.System ? "s" : "-");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<FileInfo> GetFilesSafe(DirectoryInfo directoryInfo)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return directoryInfo.GetFiles();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return Enumerable.Empty<FileInfo>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
@@ -31,9 +32,14 @@ namespace FileTime.Providers.Local
|
|||||||
Items.OnNext(rootDirectories.Select(DirectoryToAbsolutePath).ToList());
|
Items.OnNext(rootDirectories.Select(DirectoryToAbsolutePath).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<IItem> GetItemByNativePathAsync(NativePath nativePath, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown)
|
public override Task<IItem> GetItemByNativePathAsync(
|
||||||
|
NativePath nativePath,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
{
|
{
|
||||||
var path = nativePath.Path;
|
var path = nativePath.Path;
|
||||||
|
Exception? innerException;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((path?.Length ?? 0) == 0)
|
if ((path?.Length ?? 0) == 0)
|
||||||
@@ -42,7 +48,7 @@ namespace FileTime.Providers.Local
|
|||||||
}
|
}
|
||||||
else if (Directory.Exists(path))
|
else if (Directory.Exists(path))
|
||||||
{
|
{
|
||||||
return Task.FromResult((IItem)DirectoryToContainer(new DirectoryInfo(path!.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar)));
|
return Task.FromResult((IItem)DirectoryToContainer(new DirectoryInfo(path!.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar), !itemInitializationSettings.SkipChildInitialization));
|
||||||
}
|
}
|
||||||
else if (File.Exists(path))
|
else if (File.Exists(path))
|
||||||
{
|
{
|
||||||
@@ -56,20 +62,24 @@ namespace FileTime.Providers.Local
|
|||||||
_ => "Directory or file"
|
_ => "Directory or file"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (forceResolvePathType == AbsolutePathType.Container) throw new DirectoryNotFoundException($"{type} not found: '{path}'");
|
innerException = forceResolvePathType switch
|
||||||
throw new FileNotFoundException(type + " not found", path);
|
{
|
||||||
|
AbsolutePathType.Container => new DirectoryNotFoundException($"{type} not found: '{path}'"),
|
||||||
|
_ => new FileNotFoundException(type + " not found", path)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (!forceResolve) throw new Exception($"Could not resolve path '{nativePath.Path}' and {nameof(forceResolve)} is false.", e);
|
if (!forceResolve) throw new Exception($"Could not resolve path '{nativePath.Path}' and {nameof(forceResolve)} is false.", e);
|
||||||
|
innerException = e;
|
||||||
return forceResolvePathType switch
|
|
||||||
{
|
|
||||||
AbsolutePathType.Container => Task.FromResult((IItem)CreateEmptyContainer(nativePath, Observable.Return(new List<Exception>() { e }))),
|
|
||||||
AbsolutePathType.Element => Task.FromResult(CreateEmptyElement(nativePath)),
|
|
||||||
_ => throw new Exception($"Could not resolve path '{nativePath.Path}' and could not force create, because {nameof(forceResolvePathType)} is {nameof(AbsolutePathType.Unknown)}.", e)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return forceResolvePathType switch
|
||||||
|
{
|
||||||
|
AbsolutePathType.Container => Task.FromResult((IItem)CreateEmptyContainer(nativePath, Observable.Return(new List<Exception>() { innerException }))),
|
||||||
|
AbsolutePathType.Element => Task.FromResult(CreateEmptyElement(nativePath)),
|
||||||
|
_ => throw new Exception($"Could not resolve path '{nativePath.Path}' and could not force create, because {nameof(forceResolvePathType)} is {nameof(AbsolutePathType.Unknown)}.", innerException)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Container CreateEmptyContainer(NativePath nativePath, IObservable<IEnumerable<Exception>>? exceptions = null)
|
private Container CreateEmptyContainer(NativePath nativePath, IObservable<IEnumerable<Exception>>? exceptions = null)
|
||||||
@@ -108,8 +118,8 @@ namespace FileTime.Providers.Local
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName) => Task.FromResult(GetItemsByContainer(fullName));
|
public override Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName) => Task.FromResult(GetItemsByContainer(fullName));
|
||||||
public List<IAbsolutePath> GetItemsByContainer(FullName fullName) => GetItemsByContainer(new DirectoryInfo(GetNativePath(fullName).Path));
|
private List<IAbsolutePath> GetItemsByContainer(FullName fullName) => GetItemsByContainer(new DirectoryInfo(GetNativePath(fullName).Path));
|
||||||
public List<IAbsolutePath> GetItemsByContainer(DirectoryInfo directoryInfo) => directoryInfo.GetDirectories().Select(DirectoryToAbsolutePath).Concat(GetFilesSafe(directoryInfo).Select(FileToAbsolutePath)).ToList();
|
private List<IAbsolutePath> GetItemsByContainer(DirectoryInfo directoryInfo) => directoryInfo.GetDirectories().Select(DirectoryToAbsolutePath).Concat(directoryInfo.GetFiles().Select(FileToAbsolutePath)).ToList();
|
||||||
|
|
||||||
private IAbsolutePath DirectoryToAbsolutePath(DirectoryInfo directoryInfo)
|
private IAbsolutePath DirectoryToAbsolutePath(DirectoryInfo directoryInfo)
|
||||||
{
|
{
|
||||||
@@ -123,7 +133,7 @@ namespace FileTime.Providers.Local
|
|||||||
return new AbsolutePath(this, fullName, AbsolutePathType.Element);
|
return new AbsolutePath(this, fullName, AbsolutePathType.Element);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Container DirectoryToContainer(DirectoryInfo directoryInfo)
|
private Container DirectoryToContainer(DirectoryInfo directoryInfo, bool initializeChildren = true)
|
||||||
{
|
{
|
||||||
var fullName = GetFullName(directoryInfo.FullName);
|
var fullName = GetFullName(directoryInfo.FullName);
|
||||||
var parentFullName = fullName.GetParent();
|
var parentFullName = fullName.GetParent();
|
||||||
@@ -131,6 +141,7 @@ namespace FileTime.Providers.Local
|
|||||||
this,
|
this,
|
||||||
parentFullName ?? new FullName(""),
|
parentFullName ?? new FullName(""),
|
||||||
AbsolutePathType.Container);
|
AbsolutePathType.Container);
|
||||||
|
var exceptions = new BehaviorSubject<IEnumerable<Exception>>(Enumerable.Empty<Exception>());
|
||||||
|
|
||||||
return new(
|
return new(
|
||||||
directoryInfo.Name,
|
directoryInfo.Name,
|
||||||
@@ -145,9 +156,24 @@ namespace FileTime.Providers.Local
|
|||||||
true,
|
true,
|
||||||
GetDirectoryAttributes(directoryInfo),
|
GetDirectoryAttributes(directoryInfo),
|
||||||
this,
|
this,
|
||||||
Observable.Return(Enumerable.Empty<Exception>()),
|
exceptions,
|
||||||
Observable.Return(GetItemsByContainer(directoryInfo))
|
Observable.FromAsync(async () => await Task.Run(InitChildren))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Task<List<IAbsolutePath>?> InitChildren()
|
||||||
|
{
|
||||||
|
List<IAbsolutePath>? result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = initializeChildren ? (List<IAbsolutePath>?)GetItemsByContainer(directoryInfo) : null;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
exceptions.OnNext(new List<Exception>() { e });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Element FileToElement(FileInfo fileInfo)
|
private Element FileToElement(FileInfo fileInfo)
|
||||||
|
|||||||
Reference in New Issue
Block a user