From 558a0a08bbea0368a6ed5cb276bae9f53ec79ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20Kov=C3=A1cs?= Date: Thu, 3 Aug 2023 10:48:39 +0200 Subject: [PATCH] Container traits to extensions --- .../IContainerScanSnapshotProvider.cs | 9 --- .../IContainerSizeScanProvider.cs | 10 ++++ .../ISizeScanContainer.cs | 5 +- ...er.cs => ContainerSizeSizeScanProvider.cs} | 21 ++++++- .../SizeScanContainer.cs | 40 ++++++++++--- .../SizeScanTask.cs | 57 +++++++------------ .../Startup.cs | 5 +- .../Exceptions/ItemNotFoundException.cs | 9 ++- .../Services/IModalService.cs | 1 + .../Persistence/TabPersistenceService.cs | 10 +++- .../NavigationUserCommandHandlerService.cs | 26 +++++++-- .../ToolUserCommandHandlerService.cs | 8 +-- .../ViewModels/AppStateBase.cs | 6 +- .../Services/FrequencyNavigationService.cs | 23 ++++++-- .../FileTime.App.Search/SearchTask.cs | 10 ++-- .../ContainerTraits/IEscHandlerContainer.cs | 6 -- .../IStatusProviderContainer.cs | 8 --- .../Models/ExtensionCollection.cs | 17 +----- .../EscHandlerContainerExtension.cs | 12 ++++ .../NonRestorableContainerExtension.cs | 6 ++ .../RealContainerProviderExtension.cs | 11 ++++ .../StatusProviderContainerExtension.cs | 13 +++++ .../Models/TabLocationChanged.cs | 4 +- .../Services/ITabEvents.cs | 2 +- .../FileTime.Core.Command/Copy/CopyCommand.cs | 2 +- src/Core/FileTime.Core.Services/Tab.cs | 4 +- src/Core/FileTime.Core.Services/TabEvents.cs | 8 +-- .../Converters/FormatSizeConverter.cs | 5 +- .../Services/DefaultModeKeyInputHandler.cs | 36 ++++++------ .../FileTime.GuiApp/Services/ModalService.cs | 12 +++- .../ViewModels/MainWindowViewModel.cs | 16 +++--- .../FileTime.GuiApp/Views/MainWindow.axaml.cs | 14 ++++- 32 files changed, 258 insertions(+), 158 deletions(-) delete mode 100644 src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerScanSnapshotProvider.cs create mode 100644 src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerSizeScanProvider.cs rename src/AppCommon/FileTime.App.ContainerSizeScanner/{ContainerScanProvider.cs => ContainerSizeSizeScanProvider.cs} (88%) delete mode 100644 src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IEscHandlerContainer.cs delete mode 100644 src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IStatusProviderContainer.cs create mode 100644 src/Core/FileTime.Core.Abstraction/Models/Extensions/EscHandlerContainerExtension.cs create mode 100644 src/Core/FileTime.Core.Abstraction/Models/Extensions/NonRestorableContainerExtension.cs create mode 100644 src/Core/FileTime.Core.Abstraction/Models/Extensions/RealContainerProviderExtension.cs create mode 100644 src/Core/FileTime.Core.Abstraction/Models/Extensions/StatusProviderContainerExtension.cs diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerScanSnapshotProvider.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerScanSnapshotProvider.cs deleted file mode 100644 index f5cb708..0000000 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerScanSnapshotProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FileTime.Core.ContentAccess; -using FileTime.Core.Models; - -namespace FileTime.App.ContainerSizeScanner; - -public interface IContainerScanSnapshotProvider : IContentProvider -{ - ISizeScanTask StartSizeScan(IContainer scanSizeOf); -} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerSizeScanProvider.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerSizeScanProvider.cs new file mode 100644 index 0000000..81ce6c2 --- /dev/null +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/IContainerSizeScanProvider.cs @@ -0,0 +1,10 @@ +using FileTime.App.Core.Services; +using FileTime.Core.ContentAccess; +using FileTime.Core.Models; + +namespace FileTime.App.ContainerSizeScanner; + +public interface IContainerSizeScanProvider : IContentProvider, IExitHandler +{ + ISizeScanTask StartSizeScan(IContainer scanSizeOf); +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/ISizeScanContainer.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/ISizeScanContainer.cs index 43ada17..3830fbf 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/ISizeScanContainer.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner.Abstractions/ISizeScanContainer.cs @@ -1,17 +1,16 @@ using System.Collections.ObjectModel; using DeclarativeProperty; using FileTime.Core.Models; -using FileTime.Core.Models.ContainerTraits; namespace FileTime.App.ContainerSizeScanner; -public interface ISizeScanContainer : ISizeItem, IContainer, IStatusProviderContainer +public interface ISizeScanContainer : ISizeItem, IContainer { public Task AddSizeSourceAsync(IDeclarativeProperty sizeElement); ObservableCollection ChildContainers { get; } - ObservableCollection ChildElements { get; } ObservableCollection SizeItems { get; } IContainer RealContainer { get; init; } Task StartLoadingAsync(); Task StopLoadingAsync(); + Task AddSizeChildAsync(ISizeItem newChild); } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/ContainerScanProvider.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/ContainerSizeSizeScanProvider.cs similarity index 88% rename from src/AppCommon/FileTime.App.ContainerSizeScanner/ContainerScanProvider.cs rename to src/AppCommon/FileTime.App.ContainerSizeScanner/ContainerSizeSizeScanProvider.cs index 0b690fe..70cdf4b 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/ContainerScanProvider.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/ContainerSizeSizeScanProvider.cs @@ -1,4 +1,5 @@ using FileTime.App.Core.Exceptions; +using FileTime.App.Core.Services; using FileTime.Core.ContentAccess; using FileTime.Core.Enums; using FileTime.Core.Models; @@ -7,14 +8,14 @@ using InitableService; namespace FileTime.App.ContainerSizeScanner; -public class ContainerScanProvider : ContentProviderBase, IContainerScanSnapshotProvider +public class ContainerSizeSizeScanProvider : ContentProviderBase, IContainerSizeScanProvider { private readonly ITimelessContentProvider _timelessContentProvider; private readonly IServiceProvider _serviceProvider; private readonly List _sizeScanTasks = new(); internal const string ContentProviderName = "container-size-scan"; - public ContainerScanProvider( + public ContainerSizeSizeScanProvider( ITimelessContentProvider timelessContentProvider, IServiceProvider serviceProvider) : base(ContentProviderName, timelessContentProvider) @@ -110,4 +111,20 @@ public class ContainerScanProvider : ContentProviderBase, IContainerScanSnapshot return searchTask; } + + public Task ExitAsync(CancellationToken token = default) + { + foreach (var sizeScanTask in _sizeScanTasks) + { + try + { + sizeScanTask.Stop(); + } + catch + { + } + } + + return Task.CompletedTask; + } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanContainer.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanContainer.cs index 7645a64..e6bc336 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanContainer.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanContainer.cs @@ -5,14 +5,15 @@ using DeclarativeProperty; using FileTime.Core.ContentAccess; using FileTime.Core.Enums; using FileTime.Core.Models; -using FileTime.Core.Models.ContainerTraits; +using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; namespace FileTime.App.ContainerSizeScanner; -//TODO: create readonly version -public record SizeScanContainer : ISizeScanContainer, IEscHandlerContainer +//TODO: create readonly version, or not... +public record SizeScanContainer : ISizeScanContainer { + private readonly ITimelessContentProvider _timelessContentProvider; private readonly ReadOnlyExtensionCollection _readOnlyExtensions; private readonly BehaviorSubject _isLoading = new(false); private readonly CombineProperty _size; @@ -38,25 +39,35 @@ public record SizeScanContainer : ISizeScanContainer, IEscHandlerContainer public ObservableCollection Items { get; } = new(); public IObservable IsLoading { get; } public bool? IsLoaded { get; private set; } - public Task WaitForLoaded(CancellationToken token = default) => throw new NotImplementedException(); + + public async Task WaitForLoaded(CancellationToken token = default) + { + while (IsLoaded != true) await Task.Delay(1, token); + } public bool AllowRecursiveDeletion => false; public IDeclarativeProperty Size { get; } public ObservableCollection ChildContainers { get; } = new(); - public ObservableCollection ChildElements { get; } = new(); public ObservableCollection SizeItems { get; } = new(); public required IContainer RealContainer { get; init; } - internal SizeScanContainer() + internal SizeScanContainer(ITimelessContentProvider timelessContentProvider) { + _timelessContentProvider = timelessContentProvider; _readOnlyExtensions = new ReadOnlyExtensionCollection(Extensions); + IsLoading = _isLoading.AsObservable(); + CreatedAt = DateTime.Now; _size = new(childContainerSizes => Task.FromResult(childContainerSizes.Sum())); Size = _size.Debounce(TimeSpan.FromSeconds(1)); - CreatedAt = DateTime.Now; + + Extensions.Add(new EscHandlerContainerExtension(HandleEsc)); + Extensions.Add(new NonRestorableContainerExtension()); + Extensions.Add(new RealContainerProviderExtension(() => new(_timelessContentProvider, RealContainer!))); + Extensions.Add(new StatusProviderContainerExtension(() => Status)); } public async Task AddSizeSourceAsync(IDeclarativeProperty sizeElement) @@ -90,4 +101,19 @@ public record SizeScanContainer : ISizeScanContainer, IEscHandlerContainer SizeScanTask.Stop(); return Task.FromResult(new ContainerEscapeResult(true)); } + + public async Task AddSizeChildAsync(ISizeItem newChild) + { + SizeItems.Add(newChild); + + if (newChild is ISizeScanContainer newContainer) + { + ChildContainers.Add(newContainer); + } + + await AddSizeSourceAsync(newChild.Size); + Items.Add(new AbsolutePath( + _timelessContentProvider, + newChild)); + } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs index 193daa2..6339ed7 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs @@ -1,5 +1,4 @@ using DeclarativeProperty; -using FileTime.Core.Enums; using FileTime.Core.Models; using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; @@ -13,7 +12,7 @@ public class SizeScanTask : ISizeScanTask private int _processedItems; private ulong _processedItemsTotal; private IContainer _scanSizeOf = null!; - private readonly IContainerScanSnapshotProvider _containerScanSnapshotProvider; + private readonly IContainerSizeScanProvider _containerSizeScanProvider; private readonly ITimelessContentProvider _timelessContentProvider; private readonly ILogger _logger; private Thread? _sizeScanThread; @@ -24,11 +23,11 @@ public class SizeScanTask : ISizeScanTask public bool IsRunning { get; private set; } public SizeScanTask( - IContainerScanSnapshotProvider containerScanSnapshotProvider, + IContainerSizeScanProvider containerSizeScanProvider, ITimelessContentProvider timelessContentProvider, ILogger logger) { - _containerScanSnapshotProvider = containerScanSnapshotProvider; + _containerSizeScanProvider = containerSizeScanProvider; _timelessContentProvider = timelessContentProvider; _logger = logger; _containerStatusDebounced = _containerStatus.Debounce(TimeSpan.FromMilliseconds(250)); @@ -38,16 +37,16 @@ public class SizeScanTask : ISizeScanTask { _scanSizeOf = scanSizeOf; var name = $"{_searchId++}_{scanSizeOf.Name}"; - var randomId = ContainerScanProvider.ContentProviderName + Constants.SeparatorChar + name; - SizeSizeScanContainer = new SizeScanContainer + var randomId = ContainerSizeSizeScanProvider.ContentProviderName + Constants.SeparatorChar + name; + SizeSizeScanContainer = new SizeScanContainer(_timelessContentProvider) { Name = name, DisplayName = scanSizeOf.DisplayName, FullName = new FullName(randomId), NativePath = new NativePath(randomId), - Parent = new AbsolutePath(_timelessContentProvider, _containerScanSnapshotProvider), + Parent = new AbsolutePath(_timelessContentProvider, _containerSizeScanProvider), RealContainer = scanSizeOf, - Provider = _containerScanSnapshotProvider, + Provider = _containerSizeScanProvider, Status = _containerStatusDebounced, SizeScanTask = this }; @@ -87,8 +86,8 @@ public class SizeScanTask : ISizeScanTask IContainer realContainer, ISizeScanContainer sizeScanContainer) { - if(_cancelled) return; - + if (_cancelled) return; + await realContainer.WaitForLoaded(); var resolvedItems = new List(realContainer.Items.Count); foreach (var item in realContainer.Items) @@ -99,43 +98,36 @@ public class SizeScanTask : ISizeScanTask foreach (var element in resolvedItems.OfType()) { - if(_cancelled) return; - + if (_cancelled) return; + var fileExtension = element.GetExtension(); - if (fileExtension?.Size is not { } size) continue; + var size = fileExtension?.Size ?? 0; var sizeProperty = new DeclarativeProperty(size); - var childName = sizeScanContainer.FullName!.GetChild(element.Name).Path; - await sizeScanContainer.AddSizeSourceAsync(sizeProperty); - sizeScanContainer.Items.Add(new AbsolutePath( - _timelessContentProvider, - PointInTime.Present, - new FullName(childName), - AbsolutePathType.Element)); - - var childSearchContainer = new SizeScanElement + var childElement = new SizeScanElement { Name = element.Name, DisplayName = element.DisplayName, FullName = new FullName(childName), NativePath = new NativePath(childName), Parent = new AbsolutePath(_timelessContentProvider, sizeScanContainer), - Provider = _containerScanSnapshotProvider, + Provider = _containerSizeScanProvider, Size = sizeProperty }; - sizeScanContainer.SizeItems.Add(childSearchContainer); + await sizeScanContainer.AddSizeChildAsync(childElement); + _processedItems++; _processedItemsTotal++; } foreach (var childContainer in resolvedItems.OfType()) { - if(_cancelled) return; - + if (_cancelled) return; + var childName = sizeScanContainer.FullName!.GetChild(childContainer.Name).Path; - var childSearchContainer = new SizeScanContainer + var childSearchContainer = new SizeScanContainer(_timelessContentProvider) { Name = childContainer.Name, DisplayName = childContainer.DisplayName, @@ -143,19 +135,12 @@ public class SizeScanTask : ISizeScanTask NativePath = new NativePath(childName), Parent = new AbsolutePath(_timelessContentProvider, sizeScanContainer), RealContainer = childContainer, - Provider = _containerScanSnapshotProvider, + Provider = _containerSizeScanProvider, Status = _containerStatusDebounced, SizeScanTask = this }; - sizeScanContainer.ChildContainers.Add(childSearchContainer); - sizeScanContainer.SizeItems.Add(childSearchContainer); - await sizeScanContainer.AddSizeSourceAsync(childSearchContainer.Size); - sizeScanContainer.Items.Add(new AbsolutePath( - _timelessContentProvider, - PointInTime.Present, - new FullName(childName), - AbsolutePathType.Container)); + await sizeScanContainer.AddSizeChildAsync(childSearchContainer); await TraverseTree(childContainer, childSearchContainer); } diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/Startup.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/Startup.cs index a18e927..ba3ea74 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/Startup.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/Startup.cs @@ -9,8 +9,9 @@ public static class Startup { public static IServiceCollection AddContainerSizeScanner(this IServiceCollection services) { - services.TryAddSingleton(); - services.AddSingleton(sp => sp.GetRequiredService()); + services.TryAddSingleton(); + services.AddSingleton(sp => sp.GetRequiredService()); + services.AddSingleton(sp => sp.GetRequiredService()); services.AddTransient(); services.AddTransient(); return services; diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Exceptions/ItemNotFoundException.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Exceptions/ItemNotFoundException.cs index ad650d9..fc057cd 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/Exceptions/ItemNotFoundException.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Exceptions/ItemNotFoundException.cs @@ -8,25 +8,24 @@ public enum ItemNotFoundExceptionType FullName, NativePath } + public class ItemNotFoundException : Exception { public string Path { get; } public ItemNotFoundExceptionType Type { get; } = ItemNotFoundExceptionType.Raw; - public ItemNotFoundException(string path) + public ItemNotFoundException(string path) : base("Item not found " + path) { Path = path; } - public ItemNotFoundException(FullName path) + public ItemNotFoundException(FullName path) : this(path.Path) { - Path = path.Path; Type = ItemNotFoundExceptionType.FullName; } - public ItemNotFoundException(NativePath path) + public ItemNotFoundException(NativePath path) : this(path.Path) { - Path = path.Path; Type = ItemNotFoundExceptionType.NativePath; } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Services/IModalService.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Services/IModalService.cs index 4682a4c..32859fd 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/Services/IModalService.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Services/IModalService.cs @@ -10,4 +10,5 @@ public interface IModalService void OpenModal(IModalViewModel modalToOpen); void CloseModal(IModalViewModel modalToClose); T OpenModal() where T : IModalViewModel; + event EventHandler? AllModalClosed; } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/Services/Persistence/TabPersistenceService.cs b/src/AppCommon/FileTime.App.Core/Services/Persistence/TabPersistenceService.cs index afaf409..f7a0dca 100644 --- a/src/AppCommon/FileTime.App.Core/Services/Persistence/TabPersistenceService.cs +++ b/src/AppCommon/FileTime.App.Core/Services/Persistence/TabPersistenceService.cs @@ -2,6 +2,7 @@ using System.Text.Json; using FileTime.App.Core.Models; using FileTime.App.Core.ViewModels; using FileTime.Core.Models; +using FileTime.Core.Models.Extensions; using FileTime.Core.Services; using FileTime.Core.Timeline; using FileTime.Providers.Local; @@ -202,7 +203,14 @@ public class TabPersistenceService : ITabPersistenceService { var currentLocation = tab.CurrentLocation.Value; if (currentLocation is null) continue; - tabStates.Add(new TabState(currentLocation.FullName!.Path, tab.TabNumber)); + var path = currentLocation.FullName!.Path; + + if (currentLocation.GetExtension()?.RealContainer() is { } realPath) + { + path = realPath.Path.Path; + } + + tabStates.Add(new TabState(path, tab.TabNumber)); } return new TabStates( diff --git a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs index 154409f..64f2873 100644 --- a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs +++ b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs @@ -13,6 +13,7 @@ using FileTime.Core.Services; using FileTime.Core.Timeline; using FileTime.Providers.Local; using InitableService; +using Microsoft.Extensions.Logging; namespace FileTime.App.Core.Services.UserCommandHandler; @@ -27,6 +28,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase private readonly IUserCommunicationService _userCommunicationService; private readonly IFrequencyNavigationService _frequencyNavigationService; private readonly ICommandPaletteService _commandPaletteService; + private readonly ILogger _logger; private ITabViewModel? _selectedTab; private IDeclarativeProperty? _currentLocation; private IDeclarativeProperty? _currentSelectedItem; @@ -41,7 +43,8 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase ITimelessContentProvider timelessContentProvider, IUserCommunicationService userCommunicationService, IFrequencyNavigationService frequencyNavigationService, - ICommandPaletteService commandPaletteService) : base(appState) + ICommandPaletteService commandPaletteService, + ILogger logger) : base(appState) { _appState = appState; _serviceProvider = serviceProvider; @@ -51,6 +54,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase _userCommunicationService = userCommunicationService; _frequencyNavigationService = frequencyNavigationService; _commandPaletteService = commandPaletteService; + _logger = logger; SaveSelectedTab(t => _selectedTab = t); SaveCurrentSelectedItem(i => _currentSelectedItem = i); @@ -332,11 +336,23 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase } else if (tabViewModel == null) { - var newLocation = _currentLocation?.Value?.FullName is { } fullName - ? (IContainer) await _timelessContentProvider.GetItemByFullNameAsync(fullName, PointInTime.Present) - : _localContentProvider; + IContainer? newLocation = null; - var tab = await _serviceProvider.GetAsyncInitableResolver(newLocation) + try + { + newLocation = _currentLocation?.Value?.FullName is { } fullName + ? (IContainer) await _timelessContentProvider.GetItemByFullNameAsync(fullName, PointInTime.Present) + : _localContentProvider; + } + catch(Exception ex) + { + var fullName = _currentLocation?.Value?.FullName?.Path ?? "unknown"; + _logger.LogError(ex, "Could not resolve container while switching to tab {TabNumber} to path {FullName}", number, fullName); + } + + newLocation ??= _localContentProvider; + + var tab = await _serviceProvider.GetAsyncInitableResolver(newLocation) .GetRequiredServiceAsync(); var newTabViewModel = _serviceProvider.GetInitableResolver(tab, number).GetRequiredService(); diff --git a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs index c5249be..5a2a7fb 100644 --- a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs +++ b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ToolUserCommandHandlerService.cs @@ -22,7 +22,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase private readonly ITimelessContentProvider _timelessContentProvider; private readonly IUserCommandHandlerService _userCommandHandlerService; private readonly IContentAccessorFactory _contentAccessorFactory; - private readonly IContainerScanSnapshotProvider _containerScanSnapshotProvider; + private readonly IContainerSizeScanProvider _containerSizeScanProvider; private IDeclarativeProperty? _currentLocation; private IDeclarativeProperty? _currentSelectedItem; private ITabViewModel? _currentSelectedTab; @@ -36,7 +36,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase ITimelessContentProvider timelessContentProvider, IUserCommandHandlerService userCommandHandlerService, IContentAccessorFactory contentAccessorFactory, - IContainerScanSnapshotProvider containerScanSnapshotProvider) : base(appState) + IContainerSizeScanProvider containerSizeScanProvider) : base(appState) { _systemClipboardService = systemClipboardService; _userCommunicationService = userCommunicationService; @@ -45,7 +45,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase _timelessContentProvider = timelessContentProvider; _userCommandHandlerService = userCommandHandlerService; _contentAccessorFactory = contentAccessorFactory; - _containerScanSnapshotProvider = containerScanSnapshotProvider; + _containerSizeScanProvider = containerSizeScanProvider; SaveCurrentLocation(l => _currentLocation = l); SaveCurrentSelectedItem(i => _currentSelectedItem = i); SaveSelectedTab(t => _currentSelectedTab = t); @@ -65,7 +65,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase { if (_currentLocation?.Value is null) return; - var searchTask = _containerScanSnapshotProvider.StartSizeScan(_currentLocation.Value); + var searchTask = _containerSizeScanProvider.StartSizeScan(_currentLocation.Value); var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SizeSizeScanContainer)); await _userCommandHandlerService.HandleCommandAsync(openContainerCommand); } diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/AppStateBase.cs b/src/AppCommon/FileTime.App.Core/ViewModels/AppStateBase.cs index e9dfbf6..45c0b96 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/AppStateBase.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/AppStateBase.cs @@ -2,11 +2,9 @@ using System.Collections.ObjectModel; using System.Reactive.Linq; using System.Reactive.Subjects; using DeclarativeProperty; -using DynamicData; using FileTime.App.Core.Models.Enums; using FileTime.App.Core.ViewModels.Timeline; -using FileTime.Core.Models; -using FileTime.Core.Models.ContainerTraits; +using FileTime.Core.Models.Extensions; using MvvmGen; using MoreLinq; @@ -48,7 +46,7 @@ public abstract partial class AppStateBase : IAppState ContainerStatus = SelectedTab .Map(t => t?.CurrentLocation) .Switch() - .Map(c => c is IStatusProviderContainer statusProvider ? statusProvider.Status : null) + .Map(c => c?.GetExtension()?.GetStatusProperty()) .Switch(); } diff --git a/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs b/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs index c93b9a0..2e386d8 100644 --- a/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs +++ b/src/AppCommon/FileTime.App.FrequencyNavigation/Services/FrequencyNavigationService.cs @@ -6,6 +6,7 @@ using FileTime.App.Core.Services; using FileTime.App.FrequencyNavigation.Models; using FileTime.App.FrequencyNavigation.ViewModels; using FileTime.Core.Models; +using FileTime.Core.Models.Extensions; using FileTime.Core.Services; using Microsoft.Extensions.Logging; using PropertyChanged.SourceGenerator; @@ -38,9 +39,16 @@ public partial class FrequencyNavigationService : IFrequencyNavigationService, I tabEvents.LocationChanged += OnTabLocationChanged; } - void OnTabLocationChanged(object? sender, TabLocationChanged e) + async void OnTabLocationChanged(object? sender, TabLocationChanged e) { - IncreaseContainerScore(e.Location); + try + { + await IncreaseContainerScore(e.Location); + } + catch (Exception ex) + { + _logger.LogError(ex, "Fatal error while increasing container score"); + } } public void OpenNavigationWindow() @@ -59,12 +67,16 @@ public partial class FrequencyNavigationService : IFrequencyNavigationService, I } } - private async void IncreaseContainerScore(FullName containerName) + private async Task IncreaseContainerScore(IContainer container) { await _saveLock.WaitAsync(); try { - var containerNameString = containerName.Path; + if (container.GetExtension() is not null) return; + + var containerNameString = container.FullName?.Path; + if (containerNameString is null) return; + if (_containerScores.ContainsKey(containerNameString)) { _containerScores[containerNameString].Score++; @@ -89,6 +101,7 @@ public partial class FrequencyNavigationService : IFrequencyNavigationService, I if (TryAgeContainerScores() || DateTime.Now - _lastSave > TimeSpan.FromMinutes(5)) { } + //TODO: move to if above await SaveStateAsync(); } @@ -113,7 +126,7 @@ public partial class FrequencyNavigationService : IFrequencyNavigationService, I var itemsToRemove = new List(); foreach (var container in _containerScores) { - var newScore = (int)Math.Floor(container.Value.Score * 0.9); + var newScore = (int) Math.Floor(container.Value.Score * 0.9); if (newScore > 0) { container.Value.Score = newScore; diff --git a/src/AppCommon/FileTime.App.Search/SearchTask.cs b/src/AppCommon/FileTime.App.Search/SearchTask.cs index 2bf2e0d..f46aa0e 100644 --- a/src/AppCommon/FileTime.App.Search/SearchTask.cs +++ b/src/AppCommon/FileTime.App.Search/SearchTask.cs @@ -1,6 +1,7 @@ using System.Collections.ObjectModel; using FileTime.Core.Enums; using FileTime.Core.Models; +using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; namespace FileTime.App.Search; @@ -38,7 +39,8 @@ public class SearchTask : ISearchTask var extensions = new ExtensionCollection { - new SearchExtension(this) + new SearchExtension(this), + new RealContainerProviderExtension(() => new AbsolutePath(_timelessContentProvider, baseContainer)) }; _container = new Container( baseContainer.Name, @@ -102,9 +104,9 @@ public class SearchTask : ISearchTask var childName = _container.FullName.GetChild(itemPath.Path.GetName()); _realFullNames.Add(childName, itemPath.Path); _items.Add(new AbsolutePath( - _timelessContentProvider, - PointInTime.Present, - childName, + _timelessContentProvider, + PointInTime.Present, + childName, AbsolutePathType.Container )); } diff --git a/src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IEscHandlerContainer.cs b/src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IEscHandlerContainer.cs deleted file mode 100644 index 7fea2cf..0000000 --- a/src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IEscHandlerContainer.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FileTime.Core.Models.ContainerTraits; - -public interface IEscHandlerContainer -{ - Task HandleEsc(); -} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IStatusProviderContainer.cs b/src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IStatusProviderContainer.cs deleted file mode 100644 index 4f1f1e5..0000000 --- a/src/Core/FileTime.Core.Abstraction/Models/ContainerTraits/IStatusProviderContainer.cs +++ /dev/null @@ -1,8 +0,0 @@ -using DeclarativeProperty; - -namespace FileTime.Core.Models.ContainerTraits; - -public interface IStatusProviderContainer -{ - IDeclarativeProperty Status { get; } -} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/ExtensionCollection.cs b/src/Core/FileTime.Core.Abstraction/Models/ExtensionCollection.cs index 5101a93..d0f0914 100644 --- a/src/Core/FileTime.Core.Abstraction/Models/ExtensionCollection.cs +++ b/src/Core/FileTime.Core.Abstraction/Models/ExtensionCollection.cs @@ -6,20 +6,12 @@ namespace FileTime.Core.Models; public class ExtensionCollection : IEnumerable { - private readonly List _extensions = new(); + private readonly HashSet _extensions = new(); public ExtensionCollection() { } - public ExtensionCollection(IEnumerable objects) - { - foreach (var obj in objects) - { - AddSafe(obj); - } - } - private void AddSafe(object obj) { var objType = obj.GetType(); @@ -35,12 +27,7 @@ public class ExtensionCollection : IEnumerable AddSafe(obj); } - public void Remove() - { - _extensions.RemoveAll(i => i is T); - } - - public ReadOnlyExtensionCollection AsReadOnly() => new ReadOnlyExtensionCollection(this); + public ReadOnlyExtensionCollection AsReadOnly() => new(this); public IEnumerator GetEnumerator() => _extensions.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _extensions.GetEnumerator(); diff --git a/src/Core/FileTime.Core.Abstraction/Models/Extensions/EscHandlerContainerExtension.cs b/src/Core/FileTime.Core.Abstraction/Models/Extensions/EscHandlerContainerExtension.cs new file mode 100644 index 0000000..dbf3e0c --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/Models/Extensions/EscHandlerContainerExtension.cs @@ -0,0 +1,12 @@ +namespace FileTime.Core.Models.Extensions; + +public class EscHandlerContainerExtension +{ + private readonly Func> _handleEsc; + + public EscHandlerContainerExtension(Func> handleEsc) + { + _handleEsc = handleEsc; + } + public async Task HandleEsc() => await _handleEsc(); +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/Extensions/NonRestorableContainerExtension.cs b/src/Core/FileTime.Core.Abstraction/Models/Extensions/NonRestorableContainerExtension.cs new file mode 100644 index 0000000..b980c1b --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/Models/Extensions/NonRestorableContainerExtension.cs @@ -0,0 +1,6 @@ +namespace FileTime.Core.Models.Extensions; + +public class NonRestorableContainerExtension +{ + +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/Extensions/RealContainerProviderExtension.cs b/src/Core/FileTime.Core.Abstraction/Models/Extensions/RealContainerProviderExtension.cs new file mode 100644 index 0000000..ac03cf2 --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/Models/Extensions/RealContainerProviderExtension.cs @@ -0,0 +1,11 @@ +namespace FileTime.Core.Models.Extensions; + +public class RealContainerProviderExtension +{ + public RealContainerProviderExtension(Func realContainer) + { + RealContainer = realContainer; + } + + public Func RealContainer { get; } +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/Extensions/StatusProviderContainerExtension.cs b/src/Core/FileTime.Core.Abstraction/Models/Extensions/StatusProviderContainerExtension.cs new file mode 100644 index 0000000..df4a517 --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/Models/Extensions/StatusProviderContainerExtension.cs @@ -0,0 +1,13 @@ +using DeclarativeProperty; + +namespace FileTime.Core.Models.Extensions; + +public class StatusProviderContainerExtension +{ + public StatusProviderContainerExtension(Func> getStatusProperty) + { + GetStatusProperty = getStatusProperty; + } + + public Func> GetStatusProperty { get; } +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/TabLocationChanged.cs b/src/Core/FileTime.Core.Abstraction/Models/TabLocationChanged.cs index c51892a..6f92248 100644 --- a/src/Core/FileTime.Core.Abstraction/Models/TabLocationChanged.cs +++ b/src/Core/FileTime.Core.Abstraction/Models/TabLocationChanged.cs @@ -4,10 +4,10 @@ namespace FileTime.Core.Models; public class TabLocationChanged : EventArgs { - public FullName Location { get; } + public IContainer Location { get; } public ITab Tab { get; } - public TabLocationChanged(FullName location, ITab tab) + public TabLocationChanged(IContainer location, ITab tab) { Location = location; Tab = tab; diff --git a/src/Core/FileTime.Core.Abstraction/Services/ITabEvents.cs b/src/Core/FileTime.Core.Abstraction/Services/ITabEvents.cs index f53bd8e..f12932c 100644 --- a/src/Core/FileTime.Core.Abstraction/Services/ITabEvents.cs +++ b/src/Core/FileTime.Core.Abstraction/Services/ITabEvents.cs @@ -5,5 +5,5 @@ namespace FileTime.Core.Services; public interface ITabEvents { event EventHandler LocationChanged; - void OnLocationChanged(ITab tab, FullName location); + void OnLocationChanged(ITab tab, IContainer location); } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs b/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs index fb5b1ed..13ee8d6 100644 --- a/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs +++ b/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs @@ -69,7 +69,7 @@ public class CopyCommand : CommandBase, ITransportationCommand { var elapsed = DateTime.Now - start; - var size = new ByteSize(total / elapsed.TotalSeconds); + var size = ByteSize.FromBytes(total / elapsed.TotalSeconds); return Task.FromResult(size + "/s"); }); diff --git a/src/Core/FileTime.Core.Services/Tab.cs b/src/Core/FileTime.Core.Services/Tab.cs index 41fda98..f6e4622 100644 --- a/src/Core/FileTime.Core.Services/Tab.cs +++ b/src/Core/FileTime.Core.Services/Tab.cs @@ -165,7 +165,7 @@ public class Tab : ITab if (newLocation.FullName != null) { - _tabEvents.OnLocationChanged(this, newLocation.FullName); + _tabEvents.OnLocationChanged(this, newLocation); } } @@ -177,7 +177,7 @@ public class Tab : ITab if (newLocation.FullName != null) { - _tabEvents.OnLocationChanged(this, newLocation.FullName); + _tabEvents.OnLocationChanged(this, newLocation); } } diff --git a/src/Core/FileTime.Core.Services/TabEvents.cs b/src/Core/FileTime.Core.Services/TabEvents.cs index 1b2c050..1f3aa51 100644 --- a/src/Core/FileTime.Core.Services/TabEvents.cs +++ b/src/Core/FileTime.Core.Services/TabEvents.cs @@ -4,10 +4,8 @@ namespace FileTime.Core.Services; public class TabEvents : ITabEvents { - public event EventHandler LocationChanged; + public event EventHandler? LocationChanged; - public void OnLocationChanged(ITab tab, FullName location) - { - LocationChanged?.Invoke(this, new TabLocationChanged(location, tab)); - } + public void OnLocationChanged(ITab tab, IContainer location) + => LocationChanged?.Invoke(this, new TabLocationChanged(location, tab)); } \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/FormatSizeConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/FormatSizeConverter.cs index 1d41969..2d05b53 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/FormatSizeConverter.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/FormatSizeConverter.cs @@ -22,8 +22,9 @@ public class FormatSizeConverter : IValueConverter public static string ToSizeString(long fileSize, int? precision = null) { - var size = new ByteSize(fileSize); - return precision == null? size.ToString() + var size = ByteSize.FromBytes(fileSize); + return precision == null + ? size.ToString() : size.ToString("0." + new string('#', precision.Value)); } } \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Services/DefaultModeKeyInputHandler.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Services/DefaultModeKeyInputHandler.cs index 9f94176..371fd45 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Services/DefaultModeKeyInputHandler.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Services/DefaultModeKeyInputHandler.cs @@ -1,16 +1,16 @@ -using System.Reactive.Linq; using Avalonia.Input; using FileTime.App.Core.Services; using FileTime.App.Core.UserCommand; using FileTime.App.Core.ViewModels; using FileTime.Core.Extensions; using FileTime.Core.Models; -using FileTime.Core.Models.ContainerTraits; +using FileTime.Core.Models.Extensions; using FileTime.GuiApp.Configuration; using FileTime.GuiApp.Extensions; using FileTime.GuiApp.Models; using FileTime.GuiApp.ViewModels; using Microsoft.Extensions.Logging; +using DeclarativeProperty; namespace FileTime.GuiApp.Services; @@ -20,8 +20,7 @@ public class DefaultModeKeyInputHandler : IDefaultModeKeyInputHandler private readonly IModalService _modalService; private readonly IKeyboardConfigurationService _keyboardConfigurationService; private readonly List _keysToSkip = new(); - private ITabViewModel? _selectedTab; - private IContainer? _currentLocation; + private readonly IDeclarativeProperty _currentLocation; private readonly ILogger _logger; private readonly IUserCommandHandlerService _userCommandHandlerService; private readonly IIdentifiableUserCommandService _identifiableUserCommandService; @@ -42,19 +41,20 @@ public class DefaultModeKeyInputHandler : IDefaultModeKeyInputHandler _modalService = modalService; _userCommandHandlerService = userCommandHandlerService; - _appState.SelectedTab.Subscribe(t => _selectedTab = t); - _appState.SelectedTab.Select(t => t == null ? Observable.Return(null) : t.CurrentLocation!).Switch().Subscribe(l => _currentLocation = l); + _currentLocation = _appState.SelectedTab + .Map(t => t?.CurrentLocation) + .Switch(); _openModals = modalService.OpenModals.ToBindedCollection(); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Up) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Down) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Tab) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.PageDown) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.PageUp) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.F4, alt: true) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.LWin) }); - _keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.RWin) }); + _keysToSkip.Add(new[] {new KeyConfig(Key.Up)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.Down)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.Tab)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.PageDown)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.PageUp)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.F4, alt: true)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.LWin)}); + _keysToSkip.Add(new[] {new KeyConfig(Key.RWin)}); } public async Task HandleInputKey(Key key, SpecialKeysStatus specialKeysStatus, Action setHandled) @@ -73,7 +73,7 @@ public class DefaultModeKeyInputHandler : IDefaultModeKeyInputHandler { _modalService.CloseModal(_openModals.Collection!.Last()); } - else if (_currentLocation is IEscHandlerContainer escHandler) + else if (_currentLocation.Value?.GetExtension() is { } escHandler) { var escapeResult = await escHandler.HandleEsc(); if (escapeResult.NavigateTo != null) @@ -118,7 +118,11 @@ public class DefaultModeKeyInputHandler : IDefaultModeKeyInputHandler setHandled(true); _appState.PreviousKeys.Clear(); _appState.PossibleCommands = new(); - await CallCommandAsync(_identifiableUserCommandService.GetCommand(selectedCommandBinding.Command)); + var command = _identifiableUserCommandService.GetCommand(selectedCommandBinding.Command); + if (command is not null) + { + await CallCommandAsync(command); + } } else if (_keysToSkip.Any(k => k.AreKeysEqual(_appState.PreviousKeys))) { diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Services/ModalService.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Services/ModalService.cs index 724ef32..b942e01 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Services/ModalService.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Services/ModalService.cs @@ -10,6 +10,7 @@ public class ModalService : IModalService private readonly IServiceProvider _serviceProvider; private readonly SourceList _openModals = new(); public IObservable> OpenModals { get; } + public event EventHandler? AllModalClosed; public ModalService(IServiceProvider serviceProvider) { @@ -19,8 +20,15 @@ public class ModalService : IModalService public void OpenModal(IModalViewModel modalToOpen) => _openModals.Add(modalToOpen); - public void CloseModal(IModalViewModel modalToClose) => _openModals.Remove(modalToClose); - + public void CloseModal(IModalViewModel modalToClose) + { + _openModals.Remove(modalToClose); + if (_openModals.Count == 0) + { + AllModalClosed?.Invoke(this, EventArgs.Empty); + } + } + public T OpenModal() where T : IModalViewModel { var modal = _serviceProvider.GetRequiredService(); diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs index 22285cf..913f948 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs @@ -32,12 +32,14 @@ namespace FileTime.GuiApp.ViewModels; [Inject(typeof(IRefreshSmoothnessCalculator), PropertyAccessModifier = AccessModifier.Public)] [Inject(typeof(IAdminElevationManager), PropertyAccessModifier = AccessModifier.Public)] [Inject(typeof(IClipboardService), PropertyAccessModifier = AccessModifier.Public)] +[Inject(typeof(IModalService), PropertyName = "_modalService")] public partial class MainWindowViewModel : IMainWindowViewModel { public bool Loading => false; public IObservable MainFont => _fontService.MainFont.Select(x => x ?? ""); public IGuiAppState AppState => _appState; public string Title { get; private set; } + public Action? FocusDefaultElement { get; set; } partial void OnInitialize() { @@ -59,13 +61,13 @@ public partial class MainWindowViewModel : IMainWindowViewModel Title += " (Debug)"; #endif + _modalService.AllModalClosed += (_, _) => FocusDefaultElement?.Invoke(); + Task.Run(async () => await _lifecycleService.InitStartupHandlersAsync()).Wait(); } - public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action setHandled) - { - _keyInputHandlerService.ProcessKeyDown(key, keyModifiers, setHandled); - } + public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action setHandled) + => _keyInputHandlerService.ProcessKeyDown(key, keyModifiers, setHandled); public async Task OpenContainerByFullName(FullName fullName) { @@ -75,8 +77,6 @@ public partial class MainWindowViewModel : IMainWindowViewModel new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, resolvedContainer))); } - public async Task OnExit() - { - await _lifecycleService.ExitAsync(); - } + public async Task OnExit() + => await _lifecycleService.ExitAsync(); } \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs index ba3f9f0..712087c 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs @@ -74,7 +74,10 @@ public partial class MainWindow : Window, IUiAccessor _logger?.LogInformation( $"{nameof(MainWindow)} opened, starting {nameof(MainWindowViewModel)} initialization..."); - ViewModel = DI.ServiceProvider.GetRequiredService(); + + var viewModel = DI.ServiceProvider.GetRequiredService(); + viewModel.FocusDefaultElement = () => Focus(); + ViewModel = viewModel; } } @@ -111,7 +114,7 @@ public partial class MainWindow : Window, IUiAccessor && sender is StyledElement control) { FullName? path = null; - if (control.DataContext is IHaveFullPath { Path: { } } hasFullPath) + if (control.DataContext is IHaveFullPath {Path: { }} hasFullPath) { path = hasFullPath.Path; } @@ -154,7 +157,12 @@ public partial class MainWindow : Window, IUiAccessor private void OnWindowClosed(object? sender, EventArgs e) { var vm = ViewModel; - Task.Run(() => vm?.OnExit()).Wait(); + Task.Run(async () => + { + if (vm is null) return; + await vm.OnExit(); + }) + .Wait(); } private void InputList_OnKeyUp(object? sender, KeyEventArgs e)