Search WIP
This commit is contained in:
@@ -4,6 +4,7 @@ using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.Search;
|
||||
using FileTime.Core.Interactions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||
|
||||
@@ -13,6 +14,8 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
private readonly IUserCommunicationService _userCommunicationService;
|
||||
private readonly ISearchManager _searchManager;
|
||||
private readonly IItemNameConverterService _itemNameConverterService;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
||||
private IContainer? _currentLocation;
|
||||
private IItemViewModel? _currentSelectedItem;
|
||||
|
||||
@@ -21,12 +24,16 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
ISystemClipboardService systemClipboardService,
|
||||
IUserCommunicationService userCommunicationService,
|
||||
ISearchManager searchManager,
|
||||
IItemNameConverterService itemNameConverterService) : base(appState)
|
||||
IItemNameConverterService itemNameConverterService,
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IUserCommandHandlerService userCommandHandlerService) : base(appState)
|
||||
{
|
||||
_systemClipboardService = systemClipboardService;
|
||||
_userCommunicationService = userCommunicationService;
|
||||
_searchManager = searchManager;
|
||||
_itemNameConverterService = itemNameConverterService;
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_userCommandHandlerService = userCommandHandlerService;
|
||||
SaveCurrentLocation(l => _currentLocation = l);
|
||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||
|
||||
@@ -40,7 +47,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
|
||||
private async Task Search(SearchCommand searchCommand)
|
||||
{
|
||||
if(_currentLocation is null) return;
|
||||
if (_currentLocation is null) return;
|
||||
|
||||
var searchQuery = searchCommand.SearchText;
|
||||
if (string.IsNullOrEmpty(searchQuery))
|
||||
@@ -61,7 +68,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
}
|
||||
|
||||
//TODO proper error message
|
||||
if(string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||
if (string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||
|
||||
var searchMatcher = searchCommand.SearchType switch
|
||||
{
|
||||
@@ -70,7 +77,9 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
await _searchManager.StartSearchAsync(searchMatcher, _currentLocation);
|
||||
var searchTask = await _searchManager.StartSearchAsync(searchMatcher, _currentLocation);
|
||||
var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SearchContainer));
|
||||
await _userCommandHandlerService.HandleCommandAsync(openContainerCommand);
|
||||
}
|
||||
|
||||
private async Task CopyNativePath()
|
||||
|
||||
@@ -134,7 +134,6 @@ public partial class TabViewModel : ITabViewModel
|
||||
.OfType<IContainerViewModel>()
|
||||
.Where(c => c?.Container is not null)
|
||||
.Select(c => c.Container!.Items)
|
||||
.Switch()
|
||||
.Select(i =>
|
||||
i
|
||||
?.TransformAsync(MapItem)
|
||||
@@ -165,7 +164,6 @@ public partial class TabViewModel : ITabViewModel
|
||||
.Select(p => Observable.FromAsync(async () => (IContainer)await p!.ResolveAsync()))
|
||||
.Switch()
|
||||
.Select(p => p.Items)
|
||||
.Switch()
|
||||
.Select(items =>
|
||||
items
|
||||
?.TransformAsync(MapItem)
|
||||
|
||||
@@ -4,5 +4,6 @@ namespace FileTime.App.Search;
|
||||
|
||||
public interface ISearchManager
|
||||
{
|
||||
Task StartSearchAsync(ISearchMatcher matcher, IContainer searchIn);
|
||||
Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn);
|
||||
IReadOnlyList<ISearchTask> SearchTasks { get; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.Search;
|
||||
|
||||
public interface ISearchTask
|
||||
{
|
||||
IContainer SearchContainer { get; }
|
||||
Task StartAsync();
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.ContentAccess\FileTime.Core.ContentAccess.csproj" />
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Search.Abstractions\FileTime.App.Search.Abstractions.csproj" />
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
@@ -6,39 +5,34 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Search;
|
||||
|
||||
public class SearchContentProvider : ISearchContentProvider
|
||||
public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
||||
{
|
||||
public string Name { get; }
|
||||
public string DisplayName { get; }
|
||||
public FullName? FullName { get; }
|
||||
public NativePath? NativePath { get; }
|
||||
public AbsolutePath? Parent { get; }
|
||||
public bool IsHidden { get; }
|
||||
public bool IsExists { get; }
|
||||
public DateTime? CreatedAt { get; }
|
||||
public SupportsDelete CanDelete { get; }
|
||||
public bool CanRename { get; }
|
||||
public IContentProvider Provider { get; }
|
||||
public string? Attributes { get; }
|
||||
public AbsolutePathType Type { get; }
|
||||
public PointInTime PointInTime { get; }
|
||||
public IObservable<IChangeSet<Exception>> Exceptions { get; }
|
||||
public ReadOnlyExtensionCollection Extensions { get; }
|
||||
public IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> Items { get; }
|
||||
public IObservable<bool> IsLoading { get; }
|
||||
public bool AllowRecursiveDeletion { get; }
|
||||
public Task OnEnter() => throw new NotImplementedException();
|
||||
private readonly ISearchManager _searchManager;
|
||||
public const string ContentProviderName = "search";
|
||||
|
||||
public bool SupportsContentStreams { get; }
|
||||
public Task<IItem> GetItemByFullNameAsync(FullName fullName, PointInTime pointInTime, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, ItemInitializationSettings itemInitializationSettings = default) => throw new NotImplementedException();
|
||||
public SearchContentProvider(ISearchManager searchManager) : base(ContentProviderName)
|
||||
{
|
||||
_searchManager = searchManager;
|
||||
}
|
||||
|
||||
public Task<IItem> GetItemByNativePathAsync(NativePath nativePath, PointInTime pointInTime, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, ItemInitializationSettings itemInitializationSettings = default) => throw new NotImplementedException();
|
||||
public override Task<IItem> GetItemByNativePathAsync(
|
||||
NativePath nativePath,
|
||||
PointInTime pointInTime,
|
||||
bool forceResolve = false,
|
||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||
ItemInitializationSettings itemInitializationSettings = default
|
||||
) =>
|
||||
Task.FromResult((IItem)_searchManager.SearchTasks
|
||||
.First(searchTask => searchTask.SearchContainer.NativePath == nativePath).SearchContainer);
|
||||
|
||||
public NativePath GetNativePath(FullName fullName) => throw new NotImplementedException();
|
||||
public override NativePath GetNativePath(FullName fullName) => new(fullName.Path);
|
||||
|
||||
public Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||
public override Task<byte[]?> GetContentAsync(
|
||||
IElement element,
|
||||
int? maxLength = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
=> Task.FromResult(null as byte[]);
|
||||
|
||||
public bool CanHandlePath(NativePath path) => throw new NotImplementedException();
|
||||
|
||||
public bool CanHandlePath(FullName path) => throw new NotImplementedException();
|
||||
public override bool CanHandlePath(NativePath path) => path.Path.StartsWith(ContentProviderName);
|
||||
}
|
||||
@@ -1,19 +1,25 @@
|
||||
using FileTime.Core.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FileTime.App.Search;
|
||||
|
||||
public class SearchManager : ISearchManager
|
||||
{
|
||||
private readonly ISearchContentProvider _searchContainerProvider;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private ISearchContentProvider? _searchContainerProvider;
|
||||
private readonly List<SearchTask> _searchTasks = new();
|
||||
|
||||
public SearchManager(ISearchContentProvider searchContainerProvider)
|
||||
public IReadOnlyList<ISearchTask> SearchTasks { get; }
|
||||
|
||||
public SearchManager(IServiceProvider serviceProvider)
|
||||
{
|
||||
_searchContainerProvider = searchContainerProvider;
|
||||
_serviceProvider = serviceProvider;
|
||||
SearchTasks = _searchTasks.AsReadOnly();
|
||||
}
|
||||
|
||||
public async Task StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
||||
public async Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
||||
{
|
||||
_searchContainerProvider ??= _serviceProvider.GetRequiredService<ISearchContentProvider>();
|
||||
var searchTask = new SearchTask(
|
||||
searchIn,
|
||||
_searchContainerProvider,
|
||||
@@ -23,5 +29,7 @@ public class SearchManager : ISearchManager
|
||||
_searchTasks.Add(searchTask);
|
||||
|
||||
await searchTask.StartAsync();
|
||||
|
||||
return searchTask;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Search;
|
||||
|
||||
public class SearchTask
|
||||
public class SearchTask : ISearchTask
|
||||
{
|
||||
private readonly IContainer _baseContainer;
|
||||
private readonly ISearchMatcher _matcher;
|
||||
@@ -17,6 +17,9 @@ public class SearchTask
|
||||
private readonly SourceCache<AbsolutePath, string> _items = new(p => p.Path.Path);
|
||||
private readonly SemaphoreSlim _searchingLock = new(1, 1);
|
||||
private bool _isSearching;
|
||||
private static int _searchId = 1;
|
||||
|
||||
public IContainer SearchContainer => _container;
|
||||
|
||||
public SearchTask(
|
||||
IContainer baseContainer,
|
||||
@@ -24,13 +27,14 @@ public class SearchTask
|
||||
ISearchMatcher matcher
|
||||
)
|
||||
{
|
||||
var randomId = $"{SearchContentProvider.ContentProviderName}/{_searchId++}_{baseContainer.Name}";
|
||||
_baseContainer = baseContainer;
|
||||
_matcher = matcher;
|
||||
_container = new Container(
|
||||
baseContainer.Name,
|
||||
baseContainer.DisplayName,
|
||||
new FullName(""),
|
||||
new NativePath(""),
|
||||
new FullName(randomId),
|
||||
new NativePath(randomId),
|
||||
null,
|
||||
false,
|
||||
true,
|
||||
@@ -43,7 +47,7 @@ public class SearchTask
|
||||
PointInTime.Present,
|
||||
_exceptions.Connect(),
|
||||
new ReadOnlyExtensionCollection(new ExtensionCollection()),
|
||||
Observable.Return(_items.Connect())
|
||||
_items.Connect().StartWithEmpty()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace FileTime.App.Search;
|
||||
|
||||
@@ -6,8 +8,9 @@ public static class Startup
|
||||
{
|
||||
public static IServiceCollection AddSearch(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ISearchContentProvider, SearchContentProvider>();
|
||||
services.AddSingleton<ISearchManager, SearchManager>();
|
||||
services.TryAddSingleton<ISearchContentProvider, SearchContentProvider>();
|
||||
services.AddSingleton<IContentProvider>(sp => sp.GetRequiredService<ISearchContentProvider>());
|
||||
services.TryAddSingleton<ISearchManager, SearchManager>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ public static class DynamicDataExtensions
|
||||
{
|
||||
private class DisposableContext<TParam, TTaskResult>
|
||||
{
|
||||
private readonly SemaphoreSlim _semaphore = new(1, 1);
|
||||
private readonly Func<TParam, TTaskResult> _transformResult;
|
||||
private readonly TaskCompletionSource<TTaskResult?> _taskCompletionSource;
|
||||
private bool _isFinished;
|
||||
public IDisposable? Disposable { get; set; }
|
||||
|
||||
public DisposableContext(Func<TParam, TTaskResult> transformResult,
|
||||
@@ -22,6 +24,7 @@ public static class DynamicDataExtensions
|
||||
|
||||
public void OnNext(TParam param)
|
||||
{
|
||||
if (IsFinished()) return;
|
||||
Disposable?.Dispose();
|
||||
var result = _transformResult(param);
|
||||
_taskCompletionSource.SetResult(result);
|
||||
@@ -29,15 +32,27 @@ public static class DynamicDataExtensions
|
||||
|
||||
public void OnError(Exception ex)
|
||||
{
|
||||
if (IsFinished()) return;
|
||||
Disposable?.Dispose();
|
||||
_taskCompletionSource.SetException(ex);
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
if (IsFinished()) return;
|
||||
Disposable?.Dispose();
|
||||
_taskCompletionSource.SetResult(default);
|
||||
}
|
||||
|
||||
private bool IsFinished()
|
||||
{
|
||||
_semaphore.Wait();
|
||||
var finished = _isFinished;
|
||||
_isFinished = true;
|
||||
_semaphore.Release();
|
||||
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
@@ -46,12 +61,12 @@ public static class DynamicDataExtensions
|
||||
.Select(s =>
|
||||
s is null
|
||||
? new SourceList<AbsolutePath>().Connect().StartWithEmpty().ToCollection()
|
||||
: s.ToCollection())
|
||||
: s.StartWithEmpty().ToCollection())
|
||||
.Switch());
|
||||
|
||||
public static async Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
this IObservable<IChangeSet<AbsolutePath, string>> stream)
|
||||
=> await GetItemsAsync(stream.ToCollection());
|
||||
=> await GetItemsAsync(stream.StartWithEmpty().ToCollection());
|
||||
|
||||
public static Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
this IObservable<IReadOnlyCollection<AbsolutePath>> stream)
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace FileTime.Core.Models;
|
||||
|
||||
public interface IContainer : IItem
|
||||
{
|
||||
IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> Items { get; }
|
||||
IObservable<IChangeSet<AbsolutePath, string>> Items { get; }
|
||||
IObservable<bool> IsLoading { get; }
|
||||
bool AllowRecursiveDeletion { get; }
|
||||
}
|
||||
@@ -10,11 +10,12 @@ namespace FileTime.Core.ContentAccess;
|
||||
public abstract class ContentProviderBase : IContentProvider
|
||||
{
|
||||
private readonly ReadOnlyExtensionCollection _extensions;
|
||||
private readonly IObservable<IChangeSet<AbsolutePath, string>> _items;
|
||||
|
||||
protected BehaviorSubject<IObservable<IChangeSet<AbsolutePath, string>>?> Items { get; } = new(null);
|
||||
protected SourceCache<AbsolutePath, string> Items { get; } = new(p => p.Path.Path);
|
||||
protected ExtensionCollection Extensions { get; }
|
||||
|
||||
IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> IContainer.Items => Items;
|
||||
IObservable<IChangeSet<AbsolutePath, string>> IContainer.Items => _items;
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
@@ -59,6 +60,7 @@ public abstract class ContentProviderBase : IContentProvider
|
||||
FullName = FullName.CreateSafe(name);
|
||||
Extensions = new ExtensionCollection();
|
||||
_extensions = Extensions.AsReadOnly();
|
||||
_items = Items.Connect().StartWithEmpty();
|
||||
}
|
||||
|
||||
public virtual Task OnEnter() => Task.CompletedTask;
|
||||
|
||||
@@ -24,7 +24,7 @@ public record Container(
|
||||
PointInTime PointInTime,
|
||||
IObservable<IChangeSet<Exception>> Exceptions,
|
||||
ReadOnlyExtensionCollection Extensions,
|
||||
IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> Items) : IContainer
|
||||
IObservable<IChangeSet<AbsolutePath, string>> Items) : IContainer
|
||||
{
|
||||
private readonly CancellationTokenSource _loadingCancellationTokenSource = new();
|
||||
public CancellationToken LoadingCancellationToken => _loadingCancellationTokenSource.Token;
|
||||
|
||||
@@ -52,8 +52,7 @@ public class Tab : ITab
|
||||
CurrentLocation
|
||||
.Where(c => c is not null)
|
||||
.Select(c => c!.Items)
|
||||
.Switch()
|
||||
.Select(items => items?.TransformAsync(MapItem)),
|
||||
.Select(items => items.TransformAsync(MapItem)),
|
||||
_itemFilters.Connect().StartWithEmpty().ToCollection(),
|
||||
(items, filters) =>
|
||||
items
|
||||
|
||||
@@ -14,45 +14,35 @@ namespace FileTime.GuiApp.Services;
|
||||
|
||||
public class RootDriveInfoService : IStartupHandler
|
||||
{
|
||||
private readonly SourceList<DriveInfo> _rootDrives = new();
|
||||
private readonly List<DriveInfo> _rootDrives = new();
|
||||
|
||||
public RootDriveInfoService(
|
||||
IGuiAppState guiAppState,
|
||||
ILocalContentProvider localContentProvider,
|
||||
ITimelessContentProvider timelessContentProvider)
|
||||
ILocalContentProvider localContentProvider)
|
||||
{
|
||||
InitRootDrives();
|
||||
|
||||
var localContentProviderAsList = new SourceCache<AbsolutePath, string>(i => i.Path.Path);
|
||||
localContentProviderAsList.AddOrUpdate(new AbsolutePath(timelessContentProvider, localContentProvider));
|
||||
var localContentProviderStream = localContentProviderAsList.Connect();
|
||||
|
||||
var rootDriveInfos = Observable.CombineLatest(
|
||||
localContentProvider.Items,
|
||||
_rootDrives.Connect().StartWithEmpty().ToCollection(),
|
||||
(items, drives) =>
|
||||
var rootDriveInfos = localContentProvider.Items.Transform(
|
||||
i =>
|
||||
{
|
||||
var rootDrive = _rootDrives.FirstOrDefault(d =>
|
||||
{
|
||||
return items is null
|
||||
? Observable.Empty<IChangeSet<(AbsolutePath Path, DriveInfo? Drive), string>>()
|
||||
: items!
|
||||
.Or(new[] { localContentProviderStream })
|
||||
.Transform(i => (Path: i, Drive: drives.FirstOrDefault(d =>
|
||||
{
|
||||
var containerPath = localContentProvider.GetNativePath(i.Path).Path;
|
||||
var drivePath = d.Name.TrimEnd(Path.DirectorySeparatorChar);
|
||||
return containerPath == drivePath
|
||||
|| (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && containerPath == "/" &&
|
||||
d.Name == "/");
|
||||
})))
|
||||
.Filter(t => t.Drive is not null);
|
||||
}
|
||||
)
|
||||
.Switch()
|
||||
.TransformAsync(async t => (Item: await t.Path.ResolveAsyncSafe(), Drive: t.Drive!))
|
||||
.Filter(t => t.Item is IContainer)
|
||||
.Transform(t => (Container: (IContainer)t.Item!, t.Drive))
|
||||
.Transform(t => new RootDriveInfo(t.Drive, t.Container))
|
||||
.Sort(SortExpressionComparer<RootDriveInfo>.Ascending(d => d.Name));
|
||||
var containerPath = localContentProvider.GetNativePath(i.Path).Path;
|
||||
var drivePath = d.Name.TrimEnd(Path.DirectorySeparatorChar);
|
||||
return containerPath == drivePath
|
||||
|| (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && containerPath == "/" &&
|
||||
d.Name == "/");
|
||||
});
|
||||
|
||||
return (Path: i, Drive: rootDrive);
|
||||
}
|
||||
)
|
||||
.Filter(t => t.Drive is not null)
|
||||
.TransformAsync(async t => (Item: await t.Path.ResolveAsyncSafe(), Drive: t.Drive!))
|
||||
.Filter(t => t.Item is IContainer)
|
||||
.Transform(t => (Container: (IContainer) t.Item!, t.Drive))
|
||||
.Transform(t => new RootDriveInfo(t.Drive, t.Container))
|
||||
.Sort(SortExpressionComparer<RootDriveInfo>.Ascending(d => d.Name));
|
||||
|
||||
guiAppState.RootDriveInfos = rootDriveInfos.ToBindedCollection();
|
||||
|
||||
@@ -68,6 +58,7 @@ public class RootDriveInfoService : IStartupHandler
|
||||
&& d.DriveFormat != "tracefs"
|
||||
&& !d.RootDirectory.FullName.StartsWith("/snap/"));
|
||||
|
||||
_rootDrives.Clear();
|
||||
_rootDrives.AddRange(drives);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Runtime.InteropServices;
|
||||
using DynamicData;
|
||||
using FileTime.Core.ContentAccess;
|
||||
@@ -13,7 +12,6 @@ namespace FileTime.Providers.Local;
|
||||
public sealed partial class LocalContentProvider : ContentProviderBase, ILocalContentProvider
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly SourceCache<AbsolutePath, string> _rootDirectories = new(i => i.Path.Path);
|
||||
private readonly bool _isCaseInsensitive;
|
||||
|
||||
public LocalContentProvider(ITimelessContentProvider timelessContentProvider) : base("local")
|
||||
@@ -24,8 +22,6 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
||||
SupportsContentStreams = true;
|
||||
|
||||
RefreshRootDirectories();
|
||||
|
||||
Items.OnNext(_rootDirectories.Connect());
|
||||
}
|
||||
|
||||
public override Task OnEnter()
|
||||
@@ -41,7 +37,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
||||
? new DirectoryInfo("/").GetDirectories()
|
||||
: Environment.GetLogicalDrives().Select(d => new DirectoryInfo(d));
|
||||
|
||||
_rootDirectories.Edit(actions =>
|
||||
Items.Edit(actions =>
|
||||
{
|
||||
actions.Clear();
|
||||
actions.AddOrUpdate(rootDirectories.Select(d => DirectoryToAbsolutePath(d, PointInTime.Present)));
|
||||
@@ -50,7 +46,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
||||
|
||||
public override bool CanHandlePath(NativePath path)
|
||||
{
|
||||
var rootDrive = _rootDirectories
|
||||
var rootDrive = Items
|
||||
.Items
|
||||
.FirstOrDefault(r =>
|
||||
path.Path.StartsWith(
|
||||
@@ -173,7 +169,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
||||
pointInTime,
|
||||
exceptions.Connect(),
|
||||
new ExtensionCollection().AsReadOnly(),
|
||||
Observable.Return<IObservable<IChangeSet<AbsolutePath, string>>?>(null)
|
||||
new SourceCache<AbsolutePath, string>(a => a.Path.Path).Connect()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,9 +224,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
||||
pointInTime,
|
||||
exceptions.Connect(),
|
||||
new ExtensionCollection().AsReadOnly(),
|
||||
//Observable.FromAsync(async () => await Task.Run(InitChildrenHelper)
|
||||
//Observable.Return(InitChildren())
|
||||
Observable.Return(children.Connect())
|
||||
children.Connect().StartWithEmpty()
|
||||
);
|
||||
|
||||
Task.Run(() => LoadChildren(container, directoryInfo, children, pointInTime, exceptions));
|
||||
|
||||
Reference in New Issue
Block a user