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 @@ +