diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/PasteCommand.cs b/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/PasteCommand.cs
index ca40719..6630feb 100644
--- a/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/PasteCommand.cs
+++ b/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/PasteCommand.cs
@@ -8,9 +8,9 @@ public sealed class PasteCommand : IIdentifiableUserCommand
public const string PasteOverwriteCommandName = "paste_overwrite";
public const string PasteSkipCommandName = "paste_skip";
- public static PasteCommand Merge { get; } = new PasteCommand(PasteMode.Merge, PasteMergeCommandName);
- public static PasteCommand Overwrite { get; } = new PasteCommand(PasteMode.Overwrite, PasteOverwriteCommandName);
- public static PasteCommand Skip { get; } = new PasteCommand(PasteMode.Skip, PasteSkipCommandName);
+ public static readonly PasteCommand Merge = new(PasteMode.Merge, PasteMergeCommandName);
+ public static readonly PasteCommand Overwrite = new(PasteMode.Overwrite, PasteOverwriteCommandName);
+ public static readonly PasteCommand Skip = new(PasteMode.Skip, PasteSkipCommandName);
public PasteMode PasteMode { get; }
diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/SearchCommand.cs b/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/SearchCommand.cs
new file mode 100644
index 0000000..5ca8bfb
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Core.Abstraction/UserCommand/SearchCommand.cs
@@ -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; }
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj
index 1241f1b..0bf9a6d 100644
--- a/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj
+++ b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj
@@ -26,6 +26,7 @@
+
diff --git a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs
index a333ea5..6662bc2 100644
--- a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs
+++ b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs
@@ -1,6 +1,8 @@
using System.Diagnostics;
using FileTime.App.Core.UserCommand;
using FileTime.App.Core.ViewModels;
+using FileTime.App.Search;
+using FileTime.Core.Interactions;
using FileTime.Core.Models;
namespace FileTime.App.Core.Services.UserCommandHandler;
@@ -8,12 +10,23 @@ namespace FileTime.App.Core.Services.UserCommandHandler;
public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
{
private readonly ISystemClipboardService _systemClipboardService;
+ private readonly IUserCommunicationService _userCommunicationService;
+ private readonly ISearchManager _searchManager;
+ private readonly IItemNameConverterService _itemNameConverterService;
private IContainer? _currentLocation;
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;
+ _userCommunicationService = userCommunicationService;
+ _searchManager = searchManager;
+ _itemNameConverterService = itemNameConverterService;
SaveCurrentLocation(l => _currentLocation = l);
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
@@ -21,9 +34,45 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
{
new TypeUserCommandHandler(OpenInDefaultFileExplorer),
new TypeUserCommandHandler(CopyNativePath),
+ new TypeUserCommandHandler(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()
{
if (_currentSelectedItem?.BaseItem?.NativePath is null) return;
diff --git a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/TypeUserCommandHandler.cs b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/TypeUserCommandHandler.cs
index 7c1beee..3943070 100644
--- a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/TypeUserCommandHandler.cs
+++ b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/TypeUserCommandHandler.cs
@@ -2,7 +2,7 @@ using FileTime.App.Core.UserCommand;
namespace FileTime.App.Core.Services.UserCommandHandler;
-public class TypeUserCommandHandler : IUserCommandHandler
+public class TypeUserCommandHandler : IUserCommandHandler where T : IUserCommand
{
private readonly Func _handler;
diff --git a/src/AppCommon/FileTime.App.Core/StartupServices/DefaultIdentifiableCommandHandlerRegister.cs b/src/AppCommon/FileTime.App.Core/StartupServices/DefaultIdentifiableCommandHandlerRegister.cs
index bb35875..1c20fbd 100644
--- a/src/AppCommon/FileTime.App.Core/StartupServices/DefaultIdentifiableCommandHandlerRegister.cs
+++ b/src/AppCommon/FileTime.App.Core/StartupServices/DefaultIdentifiableCommandHandlerRegister.cs
@@ -41,6 +41,7 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
AddUserCommand(PauseCommandSchedulerCommand.Instance);
AddUserCommand(RefreshCommand.Instance);
AddUserCommand(StartCommandSchedulerCommand.Instance);
+ AddUserCommand(IdentifiableSearchCommand.SearchByNameContains);
AddUserCommand(SwitchToTabCommand.SwitchToLastTab);
AddUserCommand(SwitchToTabCommand.SwitchToTab1);
AddUserCommand(SwitchToTabCommand.SwitchToTab2);
diff --git a/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs b/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs
index 2038c35..5538bba 100644
--- a/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs
+++ b/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs
@@ -19,7 +19,7 @@ public partial class FrequencyNavigationService : IFrequencyNavigationService, I
private DateTime _lastSave = DateTime.Now;
private readonly ILogger _logger;
private readonly IModalService _modalService;
- private readonly SemaphoreSlim _saveLock = new(1);
+ private readonly SemaphoreSlim _saveLock = new(1, 1);
private Dictionary _containerScores = new();
private readonly BehaviorSubject _showWindow = new(false);
private readonly string _dbPath;
diff --git a/src/AppCommon/FileTime.App.Search.Abstractions/FileTime.App.Search.Abstractions.csproj b/src/AppCommon/FileTime.App.Search.Abstractions/FileTime.App.Search.Abstractions.csproj
new file mode 100644
index 0000000..a3e8643
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search.Abstractions/FileTime.App.Search.Abstractions.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net7.0
+ enable
+ enable
+ FileTime.App.Search
+
+
+
+
+
+
+
+
diff --git a/src/AppCommon/FileTime.App.Search.Abstractions/ISearchContainerProvider.cs b/src/AppCommon/FileTime.App.Search.Abstractions/ISearchContainerProvider.cs
new file mode 100644
index 0000000..c093972
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search.Abstractions/ISearchContainerProvider.cs
@@ -0,0 +1,8 @@
+using FileTime.Core.ContentAccess;
+
+namespace FileTime.App.Search;
+
+public interface ISearchContentProvider : IContentProvider
+{
+
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search.Abstractions/ISearchManager.cs b/src/AppCommon/FileTime.App.Search.Abstractions/ISearchManager.cs
new file mode 100644
index 0000000..5bd898b
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search.Abstractions/ISearchManager.cs
@@ -0,0 +1,8 @@
+using FileTime.Core.Models;
+
+namespace FileTime.App.Search;
+
+public interface ISearchManager
+{
+ Task StartSearchAsync(ISearchMatcher matcher, IContainer searchIn);
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search.Abstractions/ISearchMatcher.cs b/src/AppCommon/FileTime.App.Search.Abstractions/ISearchMatcher.cs
new file mode 100644
index 0000000..32d52c3
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search.Abstractions/ISearchMatcher.cs
@@ -0,0 +1,10 @@
+using FileTime.App.Core.Models;
+using FileTime.Core.Models;
+
+namespace FileTime.App.Search;
+
+public interface ISearchMatcher
+{
+ Task IsItemMatchAsync(IItem item);
+ List GetDisplayName(IItem item);
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search/FileTime.App.Search.csproj b/src/AppCommon/FileTime.App.Search/FileTime.App.Search.csproj
new file mode 100644
index 0000000..93ccce2
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search/FileTime.App.Search.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AppCommon/FileTime.App.Search/NameContainsMatcher.cs b/src/AppCommon/FileTime.App.Search/NameContainsMatcher.cs
new file mode 100644
index 0000000..fd0d487
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search/NameContainsMatcher.cs
@@ -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 IsItemMatchAsync(IItem item) => Task.FromResult(item.Name.Contains(_searchText, StringComparison.OrdinalIgnoreCase));
+
+ public List GetDisplayName(IItem item) => _itemNameConverterService.GetDisplayName(item.DisplayName, _searchText);
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search/SearchContentProvider.cs b/src/AppCommon/FileTime.App.Search/SearchContentProvider.cs
new file mode 100644
index 0000000..0b885a9
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search/SearchContentProvider.cs
@@ -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> Exceptions { get; }
+ public ReadOnlyExtensionCollection Extensions { get; }
+ public IObservable>?> Items { get; }
+ public IObservable IsLoading { get; }
+ public bool AllowRecursiveDeletion { get; }
+ public Task OnEnter() => throw new NotImplementedException();
+
+ public bool SupportsContentStreams { get; }
+ public Task GetItemByFullNameAsync(FullName fullName, PointInTime pointInTime, bool forceResolve = false, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, ItemInitializationSettings itemInitializationSettings = default) => throw new NotImplementedException();
+
+ public Task 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 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();
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search/SearchManager.cs b/src/AppCommon/FileTime.App.Search/SearchManager.cs
new file mode 100644
index 0000000..1e76d6d
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search/SearchManager.cs
@@ -0,0 +1,27 @@
+using FileTime.Core.Models;
+
+namespace FileTime.App.Search;
+
+public class SearchManager : ISearchManager
+{
+ private readonly ISearchContentProvider _searchContainerProvider;
+ private readonly List _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();
+ }
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search/SearchTask.cs b/src/AppCommon/FileTime.App.Search/SearchTask.cs
new file mode 100644
index 0000000..f6ec555
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search/SearchTask.cs
@@ -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 _exceptions = new();
+ private readonly SourceCache _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();
+
+ 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AppCommon/FileTime.App.Search/Startup.cs b/src/AppCommon/FileTime.App.Search/Startup.cs
new file mode 100644
index 0000000..23f438a
--- /dev/null
+++ b/src/AppCommon/FileTime.App.Search/Startup.cs
@@ -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();
+ services.AddSingleton();
+
+ return services;
+ }
+}
\ No newline at end of file
diff --git a/src/Core/FileTime.Core.Models/Container.cs b/src/Core/FileTime.Core.Models/Container.cs
index ace5ff0..32d47f2 100644
--- a/src/Core/FileTime.Core.Models/Container.cs
+++ b/src/Core/FileTime.Core.Models/Container.cs
@@ -32,8 +32,5 @@ public record Container(
IObservable IContainer.IsLoading => IsLoading.AsObservable();
public AbsolutePathType Type => AbsolutePathType.Container;
- public void CancelLoading()
- {
- _loadingCancellationTokenSource.Cancel();
- }
+ public void CancelLoading() => _loadingCancellationTokenSource.Cancel();
}
\ No newline at end of file
diff --git a/src/FileTime.sln b/src/FileTime.sln
index 31054f1..4c07a38 100644
--- a/src/FileTime.sln
+++ b/src/FileTime.sln
@@ -67,6 +67,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.FrequencyNavig
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}"
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -199,6 +211,8 @@ Global
{2D07F149-106B-4644-9586-D6218F78D868} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
{253348AD-C9C0-4162-A2ED-C6FF8730B275} = {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
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.Abstractions/Configuration/MainConfiguration.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.Abstractions/Configuration/MainConfiguration.cs
index c2f099a..1ac0107 100644
--- a/src/GuiApp/Avalonia/FileTime.GuiApp.Abstractions/Configuration/MainConfiguration.cs
+++ b/src/GuiApp/Avalonia/FileTime.GuiApp.Abstractions/Configuration/MainConfiguration.cs
@@ -39,42 +39,41 @@ public static class MainConfiguration
}
}
- private static List InitDefaultKeyBindings()
- {
- return new List()
+ private static List InitDefaultKeyBindings() =>
+ new List()
{
//new CommandBindingConfiguration(ConfigCommand.AutoRefresh, new KeyConfig(Key.R, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.ChangeTimelineMode, new[] { Key.T, Key.M }),
new(CloseTabCommand.CommandName, Key.Q),
//new CommandBindingConfiguration(ConfigCommand.Compress, new[] { Key.Y, Key.C }),
- new(CopyCommand.CommandName, new[] { Key.Y, Key.Y }),
+ new(CopyCommand.CommandName, new[] {Key.Y, Key.Y}),
//new CommandBindingConfiguration(ConfigCommand.CopyHash, new[] { Key.C, Key.H }),
- new(CopyNativePathCommand.CommandName, new[] { Key.C, Key.P }),
+ new(CopyNativePathCommand.CommandName, new[] {Key.C, Key.P}),
new(CreateContainer.CommandName, Key.F7),
- new(CreateContainer.CommandName, new[] { Key.C, Key.C }),
- new(CreateElement.CommandName, new[] { Key.C, Key.E }),
+ new(CreateContainer.CommandName, new[] {Key.C, Key.C}),
+ new(CreateElement.CommandName, new[] {Key.C, Key.E}),
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Key.D, Key.D }),
//new CommandBindingConfiguration(ConfigCommand.Edit, new KeyConfig(Key.F4)),
- new(EnterRapidTravelCommand.CommandName,new KeyConfig(Key.OemComma, shift: true)),
- new(EnterRapidTravelCommand.CommandName,new KeyConfig(Key.OemQuestion, shift: true)),
+ new(EnterRapidTravelCommand.CommandName, new KeyConfig(Key.OemComma, shift: true)),
+ new(EnterRapidTravelCommand.CommandName, new KeyConfig(Key.OemQuestion, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.FindByName, new[] { Key.F, Key.N }),
//new CommandBindingConfiguration(ConfigCommand.FindByNameRegex, new[] { Key.F, Key.R }),
new(GoByFrequencyCommand.CommandName, Key.Z),
- new(GoToHomeCommand.CommandName, new[] { Key.G, Key.H }),
+ new(GoToHomeCommand.CommandName, new[] {Key.G, Key.H}),
new(GoToPathCommand.CommandName, new KeyConfig(Key.L, ctrl: true)),
- new(GoToPathCommand.CommandName, new[] { Key.G, Key.P }),
- new(GoToProviderCommand.CommandName, new[] { Key.G, Key.T }),
- new(GoToRootCommand.CommandName, new[] { Key.G, Key.R }),
- new(DeleteCommand.HardDeleteCommandName, new[] { new KeyConfig(Key.D,shift: true), new KeyConfig(Key.D, shift: true) }),
+ new(GoToPathCommand.CommandName, new[] {Key.G, Key.P}),
+ new(GoToProviderCommand.CommandName, new[] {Key.G, Key.T}),
+ new(GoToRootCommand.CommandName, new[] {Key.G, Key.R}),
+ new(DeleteCommand.HardDeleteCommandName, new[] {new KeyConfig(Key.D, shift: true), new KeyConfig(Key.D, shift: true)}),
new(MarkCommand.CommandName, Key.Space),
new(MoveCursorToLastCommand.CommandName, new KeyConfig(Key.G, shift: true)),
- new(MoveCursorToFirstCommand.CommandName, new[] { Key.G, Key.G }),
+ new(MoveCursorToFirstCommand.CommandName, new[] {Key.G, Key.G}),
//new CommandBindingConfiguration(ConfigCommand.NextTimelineBlock, Key.L ),
//new CommandBindingConfiguration(ConfigCommand.NextTimelineCommand, Key.J ),
- new(OpenInDefaultFileExplorerCommand.CommandName, new[] { Key.O, Key.E }),
- new(PasteCommand.PasteMergeCommandName, new[] { Key.P, Key.P }),
- new(PasteCommand.PasteOverwriteCommandName, new[] { Key.P, Key.O }),
- new(PasteCommand.PasteSkipCommandName, new[] { Key.P, Key.S }),
+ new(OpenInDefaultFileExplorerCommand.CommandName, new[] {Key.O, Key.E}),
+ new(PasteCommand.PasteMergeCommandName, new[] {Key.P, Key.P}),
+ new(PasteCommand.PasteOverwriteCommandName, new[] {Key.P, Key.O}),
+ new(PasteCommand.PasteSkipCommandName, new[] {Key.P, Key.S}),
//new CommandBindingConfiguration(ConfigCommand.PinFavorite, new[] { Key.F, Key.P }),
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineBlock, Key.H ),
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineCommand, Key.K ),
@@ -84,7 +83,8 @@ public static class MainConfiguration
//new CommandBindingConfiguration(ConfigCommand.RunCommand, new KeyConfig(Key.D4, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.ScanContainerSize, new[] { Key.C, Key.S }),
//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.SwitchToTab1CommandName, Key.D1),
new(SwitchToTabCommand.SwitchToTab2CommandName, Key.D2),
@@ -94,9 +94,9 @@ public static class MainConfiguration
new(SwitchToTabCommand.SwitchToTab6CommandName, Key.D6),
new(SwitchToTabCommand.SwitchToTab7CommandName, Key.D7),
new(SwitchToTabCommand.SwitchToTab8CommandName, Key.D8),
- new (PauseCommandSchedulerCommand.CommandName, new[] { Key.T, Key.P }),
+ new(PauseCommandSchedulerCommand.CommandName, new[] {Key.T, Key.P}),
//new CommandBindingConfiguration(ConfigCommand.TimelineRefresh, new[] { Key.T, Key.R }),
- new (StartCommandSchedulerCommand.CommandName, new[] { Key.T, Key.S }),
+ new(StartCommandSchedulerCommand.CommandName, new[] {Key.T, Key.S}),
//new CommandBindingConfiguration(ConfigCommand.ToggleAdvancedIcons, new[] { Key.Z, Key.I }),
new(GoUpCommand.CommandName, Key.Left),
new(OpenSelectedCommand.CommandName, Key.Right),
@@ -106,7 +106,6 @@ public static class MainConfiguration
new(MoveCursorUpPageCommand.CommandName, Key.PageUp),
new(MoveCursorDownPageCommand.CommandName, Key.PageDown),
};
- }
private static void PopulateDefaultEditorPrograms(Dictionary configuration)
{
diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs
index a4854fb..4c2bc21 100644
--- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs
+++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs
@@ -3,6 +3,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using FileTime.App.DependencyInjection;
using FileTime.App.FrequencyNavigation;
+using FileTime.App.Search;
using FileTime.GuiApp.Font;
using FileTime.GuiApp.ViewModels;
using FileTime.GuiApp.Views;
@@ -19,6 +20,7 @@ public partial class App : Application
DI.ServiceProvider = DependencyInjection
.RegisterDefaultServices()
.AddFrequencyNavigation()
+ .AddSearch()
.AddConfiguration(configuration)
.ConfigureFont(configuration)
.RegisterLogging()
diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj b/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj
index d107efb..abbb4a8 100644
--- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj
+++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj
@@ -42,6 +42,7 @@
+