Search WIP
This commit is contained in:
@@ -8,9 +8,9 @@ public sealed class PasteCommand : IIdentifiableUserCommand
|
|||||||
public const string PasteOverwriteCommandName = "paste_overwrite";
|
public const string PasteOverwriteCommandName = "paste_overwrite";
|
||||||
public const string PasteSkipCommandName = "paste_skip";
|
public const string PasteSkipCommandName = "paste_skip";
|
||||||
|
|
||||||
public static PasteCommand Merge { get; } = new PasteCommand(PasteMode.Merge, PasteMergeCommandName);
|
public static readonly PasteCommand Merge = new(PasteMode.Merge, PasteMergeCommandName);
|
||||||
public static PasteCommand Overwrite { get; } = new PasteCommand(PasteMode.Overwrite, PasteOverwriteCommandName);
|
public static readonly PasteCommand Overwrite = new(PasteMode.Overwrite, PasteOverwriteCommandName);
|
||||||
public static PasteCommand Skip { get; } = new PasteCommand(PasteMode.Skip, PasteSkipCommandName);
|
public static readonly PasteCommand Skip = new(PasteMode.Skip, PasteSkipCommandName);
|
||||||
|
|
||||||
public PasteMode PasteMode { get; }
|
public PasteMode PasteMode { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
namespace FileTime.App.Core.UserCommand;
|
||||||
|
|
||||||
|
public enum SearchType
|
||||||
|
{
|
||||||
|
NameContains,
|
||||||
|
NameRegex
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SearchCommand : IUserCommand
|
||||||
|
{
|
||||||
|
public string? SearchText { get; }
|
||||||
|
public SearchType SearchType { get; }
|
||||||
|
|
||||||
|
public SearchCommand(string? searchText, SearchType searchType)
|
||||||
|
{
|
||||||
|
SearchText = searchText;
|
||||||
|
SearchType = searchType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdentifiableSearchCommand : SearchCommand, IIdentifiableUserCommand
|
||||||
|
{
|
||||||
|
public const string SearchByNameContainsCommandName = "search_name_contains";
|
||||||
|
|
||||||
|
public static readonly IdentifiableSearchCommand SearchByNameContains =
|
||||||
|
new(null, SearchType.NameContains, SearchByNameContainsCommandName);
|
||||||
|
|
||||||
|
public IdentifiableSearchCommand(
|
||||||
|
string? searchText,
|
||||||
|
SearchType searchType,
|
||||||
|
string commandId)
|
||||||
|
: base(searchText, searchType)
|
||||||
|
{
|
||||||
|
UserCommandID = commandId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserCommandID { get; }
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||||
<ProjectReference Include="..\..\Core\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
<ProjectReference Include="..\..\Core\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj" />
|
<ProjectReference Include="..\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.App.Search\FileTime.App.Search.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using FileTime.App.Core.UserCommand;
|
using FileTime.App.Core.UserCommand;
|
||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
|
using FileTime.App.Search;
|
||||||
|
using FileTime.Core.Interactions;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||||
@@ -8,12 +10,23 @@ namespace FileTime.App.Core.Services.UserCommandHandler;
|
|||||||
public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||||
{
|
{
|
||||||
private readonly ISystemClipboardService _systemClipboardService;
|
private readonly ISystemClipboardService _systemClipboardService;
|
||||||
|
private readonly IUserCommunicationService _userCommunicationService;
|
||||||
|
private readonly ISearchManager _searchManager;
|
||||||
|
private readonly IItemNameConverterService _itemNameConverterService;
|
||||||
private IContainer? _currentLocation;
|
private IContainer? _currentLocation;
|
||||||
private IItemViewModel? _currentSelectedItem;
|
private IItemViewModel? _currentSelectedItem;
|
||||||
|
|
||||||
public ToolUserCommandHandlerService(IAppState appState, ISystemClipboardService systemClipboardService) : base(appState)
|
public ToolUserCommandHandlerService(
|
||||||
|
IAppState appState,
|
||||||
|
ISystemClipboardService systemClipboardService,
|
||||||
|
IUserCommunicationService userCommunicationService,
|
||||||
|
ISearchManager searchManager,
|
||||||
|
IItemNameConverterService itemNameConverterService) : base(appState)
|
||||||
{
|
{
|
||||||
_systemClipboardService = systemClipboardService;
|
_systemClipboardService = systemClipboardService;
|
||||||
|
_userCommunicationService = userCommunicationService;
|
||||||
|
_searchManager = searchManager;
|
||||||
|
_itemNameConverterService = itemNameConverterService;
|
||||||
SaveCurrentLocation(l => _currentLocation = l);
|
SaveCurrentLocation(l => _currentLocation = l);
|
||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
|
|
||||||
@@ -21,9 +34,45 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
{
|
{
|
||||||
new TypeUserCommandHandler<OpenInDefaultFileExplorerCommand>(OpenInDefaultFileExplorer),
|
new TypeUserCommandHandler<OpenInDefaultFileExplorerCommand>(OpenInDefaultFileExplorer),
|
||||||
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
||||||
|
new TypeUserCommandHandler<SearchCommand>(Search),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Search(SearchCommand searchCommand)
|
||||||
|
{
|
||||||
|
if(_currentLocation is null) return;
|
||||||
|
|
||||||
|
var searchQuery = searchCommand.SearchText;
|
||||||
|
if (string.IsNullOrEmpty(searchQuery))
|
||||||
|
{
|
||||||
|
var title = searchCommand.SearchType switch
|
||||||
|
{
|
||||||
|
SearchType.NameContains => "Search by Name",
|
||||||
|
SearchType.NameRegex => "Search by Name (Regex)",
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
var containerNameInput = new TextInputElement(title);
|
||||||
|
await _userCommunicationService.ReadInputs(containerNameInput);
|
||||||
|
|
||||||
|
if (containerNameInput.Value is not null)
|
||||||
|
{
|
||||||
|
searchQuery = containerNameInput.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO proper error message
|
||||||
|
if(string.IsNullOrWhiteSpace(searchQuery)) return;
|
||||||
|
|
||||||
|
var searchMatcher = searchCommand.SearchType switch
|
||||||
|
{
|
||||||
|
SearchType.NameContains => new NameContainsMatcher(_itemNameConverterService, searchQuery),
|
||||||
|
//SearchType.NameRegex => new NameRegexMatcher(searchQuery),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
|
||||||
|
await _searchManager.StartSearchAsync(searchMatcher, _currentLocation);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CopyNativePath()
|
private async Task CopyNativePath()
|
||||||
{
|
{
|
||||||
if (_currentSelectedItem?.BaseItem?.NativePath is null) return;
|
if (_currentSelectedItem?.BaseItem?.NativePath is null) return;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using FileTime.App.Core.UserCommand;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||||
|
|
||||||
public class TypeUserCommandHandler<T> : IUserCommandHandler
|
public class TypeUserCommandHandler<T> : IUserCommandHandler where T : IUserCommand
|
||||||
{
|
{
|
||||||
private readonly Func<T, Task> _handler;
|
private readonly Func<T, Task> _handler;
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
|||||||
AddUserCommand(PauseCommandSchedulerCommand.Instance);
|
AddUserCommand(PauseCommandSchedulerCommand.Instance);
|
||||||
AddUserCommand(RefreshCommand.Instance);
|
AddUserCommand(RefreshCommand.Instance);
|
||||||
AddUserCommand(StartCommandSchedulerCommand.Instance);
|
AddUserCommand(StartCommandSchedulerCommand.Instance);
|
||||||
|
AddUserCommand(IdentifiableSearchCommand.SearchByNameContains);
|
||||||
AddUserCommand(SwitchToTabCommand.SwitchToLastTab);
|
AddUserCommand(SwitchToTabCommand.SwitchToLastTab);
|
||||||
AddUserCommand(SwitchToTabCommand.SwitchToTab1);
|
AddUserCommand(SwitchToTabCommand.SwitchToTab1);
|
||||||
AddUserCommand(SwitchToTabCommand.SwitchToTab2);
|
AddUserCommand(SwitchToTabCommand.SwitchToTab2);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public partial class FrequencyNavigationService : IFrequencyNavigationService, I
|
|||||||
private DateTime _lastSave = DateTime.Now;
|
private DateTime _lastSave = DateTime.Now;
|
||||||
private readonly ILogger<FrequencyNavigationService> _logger;
|
private readonly ILogger<FrequencyNavigationService> _logger;
|
||||||
private readonly IModalService _modalService;
|
private readonly IModalService _modalService;
|
||||||
private readonly SemaphoreSlim _saveLock = new(1);
|
private readonly SemaphoreSlim _saveLock = new(1, 1);
|
||||||
private Dictionary<string, ContainerFrequencyData> _containerScores = new();
|
private Dictionary<string, ContainerFrequencyData> _containerScores = new();
|
||||||
private readonly BehaviorSubject<bool> _showWindow = new(false);
|
private readonly BehaviorSubject<bool> _showWindow = new(false);
|
||||||
private readonly string _dbPath;
|
private readonly string _dbPath;
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>FileTime.App.Search</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public interface ISearchContentProvider : IContentProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public interface ISearchManager
|
||||||
|
{
|
||||||
|
Task StartSearchAsync(ISearchMatcher matcher, IContainer searchIn);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using FileTime.App.Core.Models;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public interface ISearchMatcher
|
||||||
|
{
|
||||||
|
Task<bool> IsItemMatchAsync(IItem item);
|
||||||
|
List<ItemNamePart> GetDisplayName(IItem item);
|
||||||
|
}
|
||||||
20
src/AppCommon/FileTime.App.Search/FileTime.App.Search.csproj
Normal file
20
src/AppCommon/FileTime.App.Search/FileTime.App.Search.csproj
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.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" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
21
src/AppCommon/FileTime.App.Search/NameContainsMatcher.cs
Normal file
21
src/AppCommon/FileTime.App.Search/NameContainsMatcher.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using FileTime.App.Core.Models;
|
||||||
|
using FileTime.App.Core.Services;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public class NameContainsMatcher : ISearchMatcher
|
||||||
|
{
|
||||||
|
private readonly IItemNameConverterService _itemNameConverterService;
|
||||||
|
private readonly string _searchText;
|
||||||
|
|
||||||
|
public NameContainsMatcher(IItemNameConverterService itemNameConverterService, string searchText)
|
||||||
|
{
|
||||||
|
_itemNameConverterService = itemNameConverterService;
|
||||||
|
_searchText = searchText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> IsItemMatchAsync(IItem item) => Task.FromResult(item.Name.Contains(_searchText, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
public List<ItemNamePart> GetDisplayName(IItem item) => _itemNameConverterService.GetDisplayName(item.DisplayName, _searchText);
|
||||||
|
}
|
||||||
44
src/AppCommon/FileTime.App.Search/SearchContentProvider.cs
Normal file
44
src/AppCommon/FileTime.App.Search/SearchContentProvider.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using DynamicData;
|
||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public class SearchContentProvider : 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();
|
||||||
|
|
||||||
|
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 Task<IItem> GetItemByNativePathAsync(NativePath nativePath, PointInTime pointInTime, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, ItemInitializationSettings itemInitializationSettings = default) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public NativePath GetNativePath(FullName fullName) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public bool CanHandlePath(NativePath path) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public bool CanHandlePath(FullName path) => throw new NotImplementedException();
|
||||||
|
}
|
||||||
27
src/AppCommon/FileTime.App.Search/SearchManager.cs
Normal file
27
src/AppCommon/FileTime.App.Search/SearchManager.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public class SearchManager : ISearchManager
|
||||||
|
{
|
||||||
|
private readonly ISearchContentProvider _searchContainerProvider;
|
||||||
|
private readonly List<SearchTask> _searchTasks = new();
|
||||||
|
|
||||||
|
public SearchManager(ISearchContentProvider searchContainerProvider)
|
||||||
|
{
|
||||||
|
_searchContainerProvider = searchContainerProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
||||||
|
{
|
||||||
|
var searchTask = new SearchTask(
|
||||||
|
searchIn,
|
||||||
|
_searchContainerProvider,
|
||||||
|
matcher
|
||||||
|
);
|
||||||
|
|
||||||
|
_searchTasks.Add(searchTask);
|
||||||
|
|
||||||
|
await searchTask.StartAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/AppCommon/FileTime.App.Search/SearchTask.cs
Normal file
101
src/AppCommon/FileTime.App.Search/SearchTask.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System.Reactive.Linq;
|
||||||
|
using DynamicData;
|
||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Extensions;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public class SearchTask
|
||||||
|
{
|
||||||
|
private readonly IContainer _baseContainer;
|
||||||
|
private readonly ISearchMatcher _matcher;
|
||||||
|
private readonly Container _container;
|
||||||
|
private readonly SourceList<Exception> _exceptions = new();
|
||||||
|
private readonly SourceCache<AbsolutePath, string> _items = new(p => p.Path.Path);
|
||||||
|
private readonly SemaphoreSlim _searchingLock = new(1, 1);
|
||||||
|
private bool _isSearching;
|
||||||
|
|
||||||
|
public SearchTask(
|
||||||
|
IContainer baseContainer,
|
||||||
|
IContentProvider contentProvider,
|
||||||
|
ISearchMatcher matcher
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_baseContainer = baseContainer;
|
||||||
|
_matcher = matcher;
|
||||||
|
_container = new Container(
|
||||||
|
baseContainer.Name,
|
||||||
|
baseContainer.DisplayName,
|
||||||
|
new FullName(""),
|
||||||
|
new NativePath(""),
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
SupportsDelete.False,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
contentProvider,
|
||||||
|
false,
|
||||||
|
PointInTime.Present,
|
||||||
|
_exceptions.Connect(),
|
||||||
|
new ReadOnlyExtensionCollection(new ExtensionCollection()),
|
||||||
|
Observable.Return(_items.Connect())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StartAsync()
|
||||||
|
{
|
||||||
|
await _searchingLock.WaitAsync();
|
||||||
|
if (_isSearching) return;
|
||||||
|
_isSearching = true;
|
||||||
|
_searchingLock.Release();
|
||||||
|
|
||||||
|
Task.Run(BootstrapSearch);
|
||||||
|
|
||||||
|
async Task BootstrapSearch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_container.IsLoading.OnNext(true);
|
||||||
|
await TraverseTree(_baseContainer);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_container.IsLoading.OnNext(false);
|
||||||
|
|
||||||
|
await _searchingLock.WaitAsync();
|
||||||
|
_isSearching = false;
|
||||||
|
_searchingLock.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TraverseTree(IContainer container)
|
||||||
|
{
|
||||||
|
var items = (await container.Items.GetItemsAsync())?.ToList();
|
||||||
|
if (items is null) return;
|
||||||
|
|
||||||
|
var childContainers = new List<IContainer>();
|
||||||
|
|
||||||
|
foreach (var itemPath in items)
|
||||||
|
{
|
||||||
|
var item = await itemPath.ResolveAsync();
|
||||||
|
if (await _matcher.IsItemMatchAsync(item))
|
||||||
|
{
|
||||||
|
_items.AddOrUpdate(itemPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item is IContainer childContainer)
|
||||||
|
childContainers.Add(childContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var childContainer in childContainers)
|
||||||
|
{
|
||||||
|
await TraverseTree(childContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/AppCommon/FileTime.App.Search/Startup.cs
Normal file
14
src/AppCommon/FileTime.App.Search/Startup.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public static class Startup
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddSearch(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<ISearchContentProvider, SearchContentProvider>();
|
||||||
|
services.AddSingleton<ISearchManager, SearchManager>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,8 +32,5 @@ public record Container(
|
|||||||
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
||||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||||
|
|
||||||
public void CancelLoading()
|
public void CancelLoading() => _loadingCancellationTokenSource.Cancel();
|
||||||
{
|
|
||||||
_loadingCancellationTokenSource.Cancel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -67,6 +67,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.FrequencyNavig
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.FrequencyNavigation.Abstractions", "AppCommon\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj", "{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.FrequencyNavigation.Abstractions", "AppCommon\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj", "{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.Search", "AppCommon\FileTime.App.Search\FileTime.App.Search.csproj", "{0D3C3584-242F-4DD6-A04A-2225A8AB6746}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.Search.Abstractions", "AppCommon\FileTime.App.Search.Abstractions\FileTime.App.Search.Abstractions.csproj", "{D8D4A5C3-14B5-49E7-B029-D6E5D9574388}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -169,6 +173,14 @@ Global
|
|||||||
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0D3C3584-242F-4DD6-A04A-2225A8AB6746}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0D3C3584-242F-4DD6-A04A-2225A8AB6746}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0D3C3584-242F-4DD6-A04A-2225A8AB6746}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0D3C3584-242F-4DD6-A04A-2225A8AB6746}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D8D4A5C3-14B5-49E7-B029-D6E5D9574388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D8D4A5C3-14B5-49E7-B029-D6E5D9574388}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D8D4A5C3-14B5-49E7-B029-D6E5D9574388}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D8D4A5C3-14B5-49E7-B029-D6E5D9574388}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -199,6 +211,8 @@ Global
|
|||||||
{2D07F149-106B-4644-9586-D6218F78D868} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
|
{2D07F149-106B-4644-9586-D6218F78D868} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
|
||||||
{253348AD-C9C0-4162-A2ED-C6FF8730B275} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
{253348AD-C9C0-4162-A2ED-C6FF8730B275} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
||||||
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
{C1CA8B7E-F8E6-40AB-A45B-5EBEF6996290} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
||||||
|
{0D3C3584-242F-4DD6-A04A-2225A8AB6746} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
||||||
|
{D8D4A5C3-14B5-49E7-B029-D6E5D9574388} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
||||||
|
|||||||
@@ -39,9 +39,8 @@ public static class MainConfiguration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<CommandBindingConfiguration> InitDefaultKeyBindings()
|
private static List<CommandBindingConfiguration> InitDefaultKeyBindings() =>
|
||||||
{
|
new List<CommandBindingConfiguration>()
|
||||||
return new List<CommandBindingConfiguration>()
|
|
||||||
{
|
{
|
||||||
//new CommandBindingConfiguration(ConfigCommand.AutoRefresh, new KeyConfig(Key.R, shift: true)),
|
//new CommandBindingConfiguration(ConfigCommand.AutoRefresh, new KeyConfig(Key.R, shift: true)),
|
||||||
//new CommandBindingConfiguration(ConfigCommand.ChangeTimelineMode, new[] { Key.T, Key.M }),
|
//new CommandBindingConfiguration(ConfigCommand.ChangeTimelineMode, new[] { Key.T, Key.M }),
|
||||||
@@ -85,6 +84,7 @@ public static class MainConfiguration
|
|||||||
//new CommandBindingConfiguration(ConfigCommand.ScanContainerSize, new[] { Key.C, Key.S }),
|
//new CommandBindingConfiguration(ConfigCommand.ScanContainerSize, new[] { Key.C, Key.S }),
|
||||||
//new CommandBindingConfiguration(ConfigCommand.ShowAllShortcut, Key.F1),
|
//new CommandBindingConfiguration(ConfigCommand.ShowAllShortcut, Key.F1),
|
||||||
new(DeleteCommand.SoftDeleteCommandName, new[] {new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true)}),
|
new(DeleteCommand.SoftDeleteCommandName, new[] {new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true)}),
|
||||||
|
new(IdentifiableSearchCommand.SearchByNameContainsCommandName, new[] {Key.S, Key.N}),
|
||||||
new(SwitchToTabCommand.SwitchToLastTabCommandName, Key.D9),
|
new(SwitchToTabCommand.SwitchToLastTabCommandName, Key.D9),
|
||||||
new(SwitchToTabCommand.SwitchToTab1CommandName, Key.D1),
|
new(SwitchToTabCommand.SwitchToTab1CommandName, Key.D1),
|
||||||
new(SwitchToTabCommand.SwitchToTab2CommandName, Key.D2),
|
new(SwitchToTabCommand.SwitchToTab2CommandName, Key.D2),
|
||||||
@@ -106,7 +106,6 @@ public static class MainConfiguration
|
|||||||
new(MoveCursorUpPageCommand.CommandName, Key.PageUp),
|
new(MoveCursorUpPageCommand.CommandName, Key.PageUp),
|
||||||
new(MoveCursorDownPageCommand.CommandName, Key.PageDown),
|
new(MoveCursorDownPageCommand.CommandName, Key.PageDown),
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private static void PopulateDefaultEditorPrograms(Dictionary<string, string> configuration)
|
private static void PopulateDefaultEditorPrograms(Dictionary<string, string> configuration)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Avalonia.Controls.ApplicationLifetimes;
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using FileTime.App.DependencyInjection;
|
using FileTime.App.DependencyInjection;
|
||||||
using FileTime.App.FrequencyNavigation;
|
using FileTime.App.FrequencyNavigation;
|
||||||
|
using FileTime.App.Search;
|
||||||
using FileTime.GuiApp.Font;
|
using FileTime.GuiApp.Font;
|
||||||
using FileTime.GuiApp.ViewModels;
|
using FileTime.GuiApp.ViewModels;
|
||||||
using FileTime.GuiApp.Views;
|
using FileTime.GuiApp.Views;
|
||||||
@@ -19,6 +20,7 @@ public partial class App : Application
|
|||||||
DI.ServiceProvider = DependencyInjection
|
DI.ServiceProvider = DependencyInjection
|
||||||
.RegisterDefaultServices()
|
.RegisterDefaultServices()
|
||||||
.AddFrequencyNavigation()
|
.AddFrequencyNavigation()
|
||||||
|
.AddSearch()
|
||||||
.AddConfiguration(configuration)
|
.AddConfiguration(configuration)
|
||||||
.ConfigureFont(configuration)
|
.ConfigureFont(configuration)
|
||||||
.RegisterLogging()
|
.RegisterLogging()
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Search\FileTime.App.Search.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.Font\FileTime.GuiApp.Font.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.Font\FileTime.GuiApp.Font.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp\FileTime.GuiApp.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp\FileTime.GuiApp.csproj" />
|
||||||
|
|||||||
Reference in New Issue
Block a user