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,8 +47,8 @@ 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))
|
||||
{
|
||||
@@ -59,10 +66,10 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
searchQuery = containerNameInput.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO proper error message
|
||||
if(string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||
|
||||
var searchMatcher = searchCommand.SearchType switch
|
||||
{
|
||||
SearchType.NameContains => new NameContainsMatcher(_itemNameConverterService, searchQuery),
|
||||
@@ -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 IReadOnlyList<ISearchTask> SearchTasks { get; }
|
||||
|
||||
public SearchManager(ISearchContentProvider searchContainerProvider)
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user