diff --git a/.vscode/launch.json b/.vscode/launch.json index 3c6340a..dd6f1b1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,9 +9,9 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build cli", - "program": "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI/bin/Debug/net6.0/FileTime.ConsoleUI.dll", + "program": "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App/bin/Debug/net6.0/FileTime.ConsoleUI.App.dll", "args": [], - "cwd": "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI", + "cwd": "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App", "console": "internalConsole", "stopAtEntry": false }, @@ -20,9 +20,9 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build gui", - "program": "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp/bin/Debug/net6.0/FileTime.GuiApp.dll", + "program": "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp.App/bin/Debug/net6.0/FileTime.GuiApp.App.dll", "args": [], - "cwd": "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp/bin/Debug/net6.0", + "cwd": "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp.App/bin/Debug/net6.0", "console": "internalConsole", "stopAtEntry": false }, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 746cb96..f95a2f1 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj", + "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp/FileTime.GuiApp.csproj", + "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -31,7 +31,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj", + "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -43,7 +43,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj", + "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj", "-p:PublishSingleFile=true", "-c", "Release", @@ -60,7 +60,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj", + "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj", "-p:PublishSingleFile=true", "-c", "Release", @@ -77,7 +77,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp/FileTime.GuiApp.csproj", + "${workspaceFolder}/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj", "-c", "Release", ], @@ -90,7 +90,7 @@ "args": [ "watch", "run", - "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj", + "${workspaceFolder}/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Command/Commands.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Command/Commands.cs new file mode 100644 index 0000000..22a7765 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Command/Commands.cs @@ -0,0 +1,66 @@ +namespace FileTime.App.Core.Command +{ + public enum Commands + { + None, + + AutoRefresh, + ChangeTimelineMode, + CloseTab, + Compress, + Copy, + CopyHash, + CopyPath, + CreateContainer, + CreateElement, + Cut, + Edit, + EnterRapidTravel, + FindByName, + FindByNameRegex, + GoToHome, + GoToPath, + GoToProvider, + GoToRoot, + GoUp, + HardDelete, + Mark, + MoveCursorDown, + MoveCursorDownPage, + MoveCursorUp, + MoveCursorUpPage, + MoveToFirst, + MoveToLast, + NextTimelineBlock, + NextTimelineCommand, + Open, + OpenInFileBrowser, + OpenOrRun, + PasteMerge, + PasteOverwrite, + PasteSkip, + PinFavorite, + PreviousTimelineBlock, + PreviousTimelineCommand, + Refresh, + Rename, + RunCommand, + ScanContainerSize, + ShowAllShotcut, + SoftDelete, + SwitchToLastTab, + SwitchToTab1, + SwitchToTab2, + SwitchToTab3, + SwitchToTab4, + SwitchToTab5, + SwitchToTab6, + SwitchToTab7, + SwitchToTab8, + TimelinePause, + TimelineRefresh, + TimelineStart, + ToggleAdvancedIcons, + ToggleHidden, + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj b/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj new file mode 100644 index 0000000..d2d0d89 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/IAppState.cs b/src/AppCommon/FileTime.App.Core.Abstraction/IAppState.cs new file mode 100644 index 0000000..60333d9 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/IAppState.cs @@ -0,0 +1,16 @@ +using System.Collections.ObjectModel; +using FileTime.App.Core.ViewModels; + +namespace FileTime.App.Core +{ + public interface IAppState + { + ObservableCollection Tabs { get; } + ITabViewModel? SelectedTab { get; } + IObservable SearchText { get; } + + void AddTab(ITabViewModel tabViewModel); + void RemoveTab(ITabViewModel tabViewModel); + void SetSearchText(string? searchText); + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemAttributeType.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemAttributeType.cs new file mode 100644 index 0000000..030402b --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemAttributeType.cs @@ -0,0 +1,10 @@ +namespace FileTime.App.Core.Models.Enums +{ + public enum ItemAttributeType + { + File, + Element, + Container, + SizeContainer + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemViewMode.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemViewMode.cs new file mode 100644 index 0000000..2f8eb6e --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemViewMode.cs @@ -0,0 +1,12 @@ +namespace FileTime.App.Core.Models.Enums +{ + public enum ItemViewMode + { + Default, + Alternative, + Selected, + Marked, + MarkedSelected, + MarkedAlternative + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Models/ItemNamePart.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Models/ItemNamePart.cs new file mode 100644 index 0000000..81e01fe --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Models/ItemNamePart.cs @@ -0,0 +1,14 @@ +namespace FileTime.App.Core.Models +{ + public class ItemNamePart + { + public string Text { get; set; } + public bool IsSpecial { get; set; } + + public ItemNamePart(string text, bool isSpecial = false) + { + Text = text; + IsSpecial = isSpecial; + } + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Services/IItemNameConverterService.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Services/IItemNameConverterService.cs new file mode 100644 index 0000000..72825c1 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Services/IItemNameConverterService.cs @@ -0,0 +1,11 @@ +using FileTime.App.Core.Models; + +namespace FileTime.App.Core.Services +{ + public interface IItemNameConverterService + { + List GetDisplayName(string name, string? searchText); + string GetFileExtension(string fullName); + string GetFileName(string fullName); + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs new file mode 100644 index 0000000..b405f2d --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public interface IContainerSizeContainerViewModel : IItemViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs new file mode 100644 index 0000000..26bb120 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public interface IContainerViewModel : IItemViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs new file mode 100644 index 0000000..b3ea19a --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public interface IElementViewModel : IItemViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs new file mode 100644 index 0000000..d6bd017 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public interface IFileViewModel : IElementViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs new file mode 100644 index 0000000..f299ca5 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs @@ -0,0 +1,15 @@ +using FileTime.App.Core.Models; +using FileTime.App.Core.Models.Enums; +using FileTime.Core.Models; + +namespace FileTime.App.Core.ViewModels +{ + public interface IItemViewModel + { + IItem? Item { get; set; } + IObservable>? DisplayName { get; set; } + IObservable? IsSelected { get; set; } + IObservable? IsMarked { get; set; } + ItemViewMode ViewMode { get; set; } + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs new file mode 100644 index 0000000..ed528e0 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs @@ -0,0 +1,16 @@ + +using FileTime.Core.Models; +using FileTime.Core.Services; +using InitableService; + +namespace FileTime.App.Core.ViewModels +{ + public interface ITabViewModel : IInitable + { + IObservable? CurrentLocation { get; } + IObservable? CurrentSelectedItem { get; } + IObservable>? CurrentItems { get; } + IObservable> MarkedItems { get; } + ITab? Tab { get; } + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/AppStateBase.cs b/src/AppCommon/FileTime.App.Core/AppStateBase.cs new file mode 100644 index 0000000..6ec81aa --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/AppStateBase.cs @@ -0,0 +1,49 @@ +using System.Collections.ObjectModel; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using FileTime.App.Core.ViewModels; +using MvvmGen; + +namespace FileTime.App.Core +{ + [ViewModel] + public abstract partial class AppStateBase : IAppState + { + private readonly BehaviorSubject _searchText = new(null); + public ObservableCollection Tabs { get; } = new(); + public IObservable SearchText { get; private set; } + + [Property] + private ITabViewModel? _selectedTab; + + partial void OnInitialize() + { + SearchText = _searchText.AsObservable(); + } + + public void AddTab(ITabViewModel tabViewModel) + { + Tabs.Add(tabViewModel); + if (_selectedTab == null) + { + SelectedTab = Tabs.First(); + } + } + + public void RemoveTab(ITabViewModel tabViewModel) + { + if (!Tabs.Contains(tabViewModel)) return; + + Tabs.Remove(tabViewModel); + if (_selectedTab == tabViewModel) + { + SelectedTab = Tabs.FirstOrDefault(); + } + } + + public void SetSearchText(string? searchText) + { + _searchText.OnNext(searchText); + } + } +} \ 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 new file mode 100644 index 0000000..bd8eec7 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/src/AppCommon/FileTime.App.Core/Services/ItemNameConverterService.cs b/src/AppCommon/FileTime.App.Core/Services/ItemNameConverterService.cs new file mode 100644 index 0000000..24f85ae --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/Services/ItemNameConverterService.cs @@ -0,0 +1,56 @@ +using FileTime.App.Core.Models; + +namespace FileTime.App.Core.Services +{ + public class ItemNameConverterService : IItemNameConverterService + { + public List GetDisplayName(string name, string? searchText) + { + var nameParts = new List(); + searchText = searchText?.ToLower(); + + if (!string.IsNullOrEmpty(searchText)) + { + var nameLeft = name; + + while (nameLeft.ToLower().IndexOf(searchText, StringComparison.Ordinal) is int rapidTextStart && rapidTextStart != -1) + { + var before = rapidTextStart > 0 ? nameLeft.Substring(0, rapidTextStart) : null; + var rapidTravel = nameLeft.Substring(rapidTextStart, searchText.Length); + + nameLeft = nameLeft.Substring(rapidTextStart + searchText.Length); + + if (before != null) + { + nameParts.Add(new ItemNamePart(before)); + } + + nameParts.Add(new ItemNamePart(rapidTravel, true)); + } + + if (nameLeft.Length > 0) + { + nameParts.Add(new ItemNamePart(nameLeft)); + } + } + else + { + nameParts.Add(new ItemNamePart(name)); + } + return nameParts; + } + + public string GetFileName(string fullName) + { + var parts = fullName.Split('.'); + var fileName = string.Join('.', parts[..^1]); + return string.IsNullOrEmpty(fileName) ? fullName : fileName; + } + + public string GetFileExtension(string fullName) + { + var parts = fullName.Split('.'); + return parts.Length == 1 || (parts.Length == 2 && string.IsNullOrEmpty(parts[0])) ? "" : parts[^1]; + } + } +} diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs new file mode 100644 index 0000000..24b22fa --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public class ContainerSizeContainerViewModel : ItemViewModel, IContainerSizeContainerViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs new file mode 100644 index 0000000..9b3de7e --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs @@ -0,0 +1,6 @@ +namespace FileTime.App.Core.ViewModels +{ + public class ContainerViewModel : ItemViewModel, IContainerViewModel + { + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs new file mode 100644 index 0000000..5aa99f2 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public class ElementViewModel : ItemViewModel, IElementViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs new file mode 100644 index 0000000..9cd8407 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.App.Core.ViewModels +{ + public class FileViewModel : ElementViewModel, IFileViewModel + { + + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs new file mode 100644 index 0000000..4b8f0c0 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs @@ -0,0 +1,26 @@ +using FileTime.App.Core.Models; +using FileTime.App.Core.Models.Enums; +using FileTime.Core.Models; +using MvvmGen; + +namespace FileTime.App.Core.ViewModels +{ + [ViewModel] + public abstract partial class ItemViewModel : IItemViewModel + { + [Property] + private IItem? _item; + + [Property] + private IObservable>? _displayName; + + [Property] + private IObservable? _isSelected; + + [Property] + private IObservable? _isMarked; + + [Property] + private ItemViewMode _viewMode; + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs new file mode 100644 index 0000000..cfe3911 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs @@ -0,0 +1,105 @@ +using System.Reactive.Linq; +using System.Reactive.Subjects; +using FileTime.App.Core.Services; +using FileTime.Core.Models; +using FileTime.Core.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace FileTime.App.Core.ViewModels +{ + public class TabViewModel : ITabViewModel, IDisposable + { + private readonly IServiceProvider _serviceProvider; + private readonly IItemNameConverterService _itemNameConverterService; + private readonly IAppState _appState; + private readonly BehaviorSubject> _markedItems = new(Enumerable.Empty()); + private readonly List _disposables = new(); + private bool disposed; + + public IObservable? CurrentLocation { get; private set; } + public IObservable? CurrentSelectedItem { get; private set; } + public IObservable>? CurrentItems { get; private set; } + public IObservable> MarkedItems { get; } + + public ITab? Tab { get; private set; } + + public TabViewModel( + IServiceProvider serviceProvider, + IItemNameConverterService itemNameConverterService, + IAppState appState) + { + _serviceProvider = serviceProvider; + _itemNameConverterService = itemNameConverterService; + _appState = appState; + + MarkedItems = _markedItems.Select(e => e.ToList()).AsObservable(); + } + + public void Init(ITab tab) + { + CurrentLocation = tab.CurrentLocation.AsObservable(); + CurrentItems = tab.CurrentItems.Select(items => items.Select(MapItemToViewModel).ToList()); + CurrentSelectedItem = CurrentItems.CombineLatest( + tab.CurrentSelectedItem, + (currentItems, currentSelectedItemPath) => currentItems.FirstOrDefault(i => i.Item?.FullName == currentSelectedItemPath?.Path)); + tab.CurrentLocation.Subscribe((_) => _markedItems.OnNext(Enumerable.Empty())); + + Tab = tab; + } + + private IItemViewModel MapItemToViewModel(IItem item) + { + if (item is IContainer container) + { + var containerViewModel = _serviceProvider.GetRequiredService(); + InitIItemViewModel(containerViewModel, item); + + return containerViewModel; + } + else if (item is IElement element) + { + var elementViewModel = _serviceProvider.GetRequiredService(); + InitIItemViewModel(elementViewModel, item); + + return elementViewModel; + } + + throw new ArgumentException($"{nameof(item)} is not {nameof(IContainer)} neighter {nameof(IElement)}"); + + void InitIItemViewModel(IItemViewModel itemViewModel, IItem item) + { + itemViewModel.Item = item; + itemViewModel.DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s)); + itemViewModel.IsMarked = MarkedItems.Select(m => m.Contains(item.FullName)); + itemViewModel.IsSelected = MarkedItems.Select(m => m.Contains(item.FullName)); + } + } + + ~TabViewModel() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposed && disposing) + { + foreach (var disposable in _disposables) + { + try + { + disposable.Dispose(); + } + catch { } + } + } + disposed = true; + } + } +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/FileTime.Core.Abstraction.csproj b/src/Core/FileTime.Core.Abstraction/FileTime.Core.Abstraction.csproj index f2d4187..3dc96ef 100644 --- a/src/Core/FileTime.Core.Abstraction/FileTime.Core.Abstraction.csproj +++ b/src/Core/FileTime.Core.Abstraction/FileTime.Core.Abstraction.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/src/Core/FileTime.Core.Abstraction/Models/Constants.cs b/src/Core/FileTime.Core.Abstraction/Models/Constants.cs index 7244ea6..c414f03 100644 --- a/src/Core/FileTime.Core.Abstraction/Models/Constants.cs +++ b/src/Core/FileTime.Core.Abstraction/Models/Constants.cs @@ -3,5 +3,6 @@ namespace FileTime.Core.Models public static class Constants { public const char SeparatorChar = '/'; + public const int MaximumObservableMergeOperations = 4; } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Services/ITab.cs b/src/Core/FileTime.Core.Abstraction/Services/ITab.cs index 7420885..9c2949e 100644 --- a/src/Core/FileTime.Core.Abstraction/Services/ITab.cs +++ b/src/Core/FileTime.Core.Abstraction/Services/ITab.cs @@ -1,7 +1,14 @@ +using FileTime.Core.Models; +using InitableService; + namespace FileTime.Core.Services { - public interface ITab + public interface ITab : IInitable { - + IObservable CurrentLocation { get; } + IObservable CurrentSelectedItem { get; } + IObservable> CurrentItems { get; } + + void ChangeLocation(IContainer newLocation); } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Services/FileTime.Core.Services.csproj b/src/Core/FileTime.Core.Services/FileTime.Core.Services.csproj index 13eed31..ac049af 100644 --- a/src/Core/FileTime.Core.Services/FileTime.Core.Services.csproj +++ b/src/Core/FileTime.Core.Services/FileTime.Core.Services.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Core/FileTime.Core.Services/Tab.cs b/src/Core/FileTime.Core.Services/Tab.cs index 78913ad..7877f72 100644 --- a/src/Core/FileTime.Core.Services/Tab.cs +++ b/src/Core/FileTime.Core.Services/Tab.cs @@ -1,7 +1,65 @@ +using System.Reactive.Linq; +using System.Reactive.Subjects; +using FileTime.Core.Models; + namespace FileTime.Core.Services { public class Tab : ITab { - + private readonly BehaviorSubject _currentLocation = new(null); + private readonly BehaviorSubject _currentSelectedItem = new(null); + public IObservable CurrentLocation { get; } + public IObservable> CurrentItems { get; } + public IObservable CurrentSelectedItem { get; } + + public Tab() + { + CurrentLocation = _currentLocation.AsObservable(); + CurrentItems = _currentLocation + .Select(c => + Observable.FromAsync(async () => + c == null + ? Enumerable.Empty() + : await c.Items + .ToAsyncEnumerable() + .SelectAwait( + async i => + { + try + { + //TODO: force create by AbsolutePath name + return await i.ContentProvider.GetItemByFullNameAsync(i.Path); + } + catch { return null!; } + } + + ) + .Where(i => i != null) + .ToListAsync() + ) + ) + .Merge(Constants.MaximumObservableMergeOperations); + CurrentSelectedItem = CurrentLocation.Select(GetSelectedItemByLocation).Merge(_currentSelectedItem).Throttle(TimeSpan.FromMilliseconds(500)); + + CurrentItems.Subscribe(c => + { + ; + }); + } + + public void Init(IContainer currentLocation) + { + _currentLocation.OnNext(currentLocation); + } + + private IAbsolutePath? GetSelectedItemByLocation(IContainer? currentLocation) + { + return currentLocation?.Items[0]; + } + + public void ChangeLocation(IContainer newLocation) + { + _currentLocation.OnNext(newLocation); + } } } \ No newline at end of file diff --git a/src/FileTime.sln b/src/FileTime.sln index 939bc35..a86ec00 100644 --- a/src/FileTime.sln +++ b/src/FileTime.sln @@ -19,7 +19,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppCommon", "AppCommon", "{ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Avalonia", "Avalonia", "{01F231DE-4A65-435F-B4BB-77EE5221890C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.GuiApp", "GuiApp\Avalonia\FileTime.GuiApp\FileTime.GuiApp.csproj", "{C389087E-EB78-4DCD-96AF-F1E2A4DEE0B0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.GuiApp.App", "GuiApp\Avalonia\FileTime.GuiApp.App\FileTime.GuiApp.App.csproj", "{C389087E-EB78-4DCD-96AF-F1E2A4DEE0B0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{2FC40FE1-4446-44AB-BF77-00F94D995FA3}" EndProject @@ -31,6 +31,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.ConsoleUI", "Conso EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.ConsoleUI.App", "ConsoleApp\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj", "{77ABB06A-43AF-49D6-A802-A389CCB53724}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library", "Library", "{07CA18AA-B85D-4DEE-BB86-F569F6029853}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InitableService", "Library\InitableService\InitableService.csproj", "{C67E3453-9730-40B5-8D2D-5D4EEBE008E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.App.Core", "AppCommon\FileTime.App.Core\FileTime.App.Core.csproj", "{FC4AE72E-E302-45A0-BB9D-E87BB3250F0D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.App.Core.Abstraction", "AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj", "{3E9CCD7F-86AA-4BD8-A100-0CD71BDB1AA0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.GuiApp", "GuiApp\Avalonia\FileTime.GuiApp\FileTime.GuiApp.csproj", "{26331AB9-6E4D-40DB-8FF0-CB7133F67CA0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.GuiApp.CustomImpl", "GuiApp\Avalonia\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj", "{4B742649-225F-4C73-B118-1B29FE2A5774}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.Providers.Local.Abstractions", "Providers\FileTime.Providers.Local.Abstractions\FileTime.Providers.Local.Abstractions.csproj", "{1500A537-2116-4111-B216-7632040619B0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +83,30 @@ Global {77ABB06A-43AF-49D6-A802-A389CCB53724}.Debug|Any CPU.Build.0 = Debug|Any CPU {77ABB06A-43AF-49D6-A802-A389CCB53724}.Release|Any CPU.ActiveCfg = Release|Any CPU {77ABB06A-43AF-49D6-A802-A389CCB53724}.Release|Any CPU.Build.0 = Release|Any CPU + {C67E3453-9730-40B5-8D2D-5D4EEBE008E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C67E3453-9730-40B5-8D2D-5D4EEBE008E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C67E3453-9730-40B5-8D2D-5D4EEBE008E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C67E3453-9730-40B5-8D2D-5D4EEBE008E2}.Release|Any CPU.Build.0 = Release|Any CPU + {FC4AE72E-E302-45A0-BB9D-E87BB3250F0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC4AE72E-E302-45A0-BB9D-E87BB3250F0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC4AE72E-E302-45A0-BB9D-E87BB3250F0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC4AE72E-E302-45A0-BB9D-E87BB3250F0D}.Release|Any CPU.Build.0 = Release|Any CPU + {3E9CCD7F-86AA-4BD8-A100-0CD71BDB1AA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E9CCD7F-86AA-4BD8-A100-0CD71BDB1AA0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E9CCD7F-86AA-4BD8-A100-0CD71BDB1AA0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E9CCD7F-86AA-4BD8-A100-0CD71BDB1AA0}.Release|Any CPU.Build.0 = Release|Any CPU + {26331AB9-6E4D-40DB-8FF0-CB7133F67CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26331AB9-6E4D-40DB-8FF0-CB7133F67CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26331AB9-6E4D-40DB-8FF0-CB7133F67CA0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26331AB9-6E4D-40DB-8FF0-CB7133F67CA0}.Release|Any CPU.Build.0 = Release|Any CPU + {4B742649-225F-4C73-B118-1B29FE2A5774}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B742649-225F-4C73-B118-1B29FE2A5774}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B742649-225F-4C73-B118-1B29FE2A5774}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B742649-225F-4C73-B118-1B29FE2A5774}.Release|Any CPU.Build.0 = Release|Any CPU + {1500A537-2116-4111-B216-7632040619B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1500A537-2116-4111-B216-7632040619B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1500A537-2116-4111-B216-7632040619B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1500A537-2116-4111-B216-7632040619B0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -83,6 +121,12 @@ Global {A55F4A86-03ED-4D25-807A-04619A1D9507} = {A5291117-3001-498B-AC8B-E14F71F72570} {67D4102C-8B92-451C-B4A9-5A82B68A7A5D} = {CAEEAD3C-41EB-405C-ACA9-BA1E4C352549} {77ABB06A-43AF-49D6-A802-A389CCB53724} = {CAEEAD3C-41EB-405C-ACA9-BA1E4C352549} + {C67E3453-9730-40B5-8D2D-5D4EEBE008E2} = {07CA18AA-B85D-4DEE-BB86-F569F6029853} + {FC4AE72E-E302-45A0-BB9D-E87BB3250F0D} = {A5291117-3001-498B-AC8B-E14F71F72570} + {3E9CCD7F-86AA-4BD8-A100-0CD71BDB1AA0} = {A5291117-3001-498B-AC8B-E14F71F72570} + {26331AB9-6E4D-40DB-8FF0-CB7133F67CA0} = {01F231DE-4A65-435F-B4BB-77EE5221890C} + {4B742649-225F-4C73-B118-1B29FE2A5774} = {01F231DE-4A65-435F-B4BB-77EE5221890C} + {1500A537-2116-4111-B216-7632040619B0} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml new file mode 100644 index 0000000..6d07da0 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml @@ -0,0 +1,215 @@ + + + + #E7073642 + #083e4c + #D0083e4c + #80083e4c + + #00000000 + #10000000 + #93a1a1 + #00000000 + #10000000 + #b58900 + + #93a1a1 + #268bd2 + #fdf6e3 + #7793a1a1 + #93a1a1 + #073642 + #b58900 + #b58900 + #002b36 + + #dc322f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs similarity index 51% rename from src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs rename to src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs index 7a7883f..3782f81 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml.cs @@ -1,13 +1,29 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; +using FileTime.App.DependencyInjection; using FileTime.GuiApp.ViewModels; using FileTime.GuiApp.Views; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace FileTime.GuiApp { public partial class App : Application { + static App() + { + DI.ServiceProvider ??= DependencyInjection + .RegisterDefaultServices() + .AddConfiguration() + .RegisterLogging() + .AddViewModels() + .BuildServiceProvider() + .InitSerilog(); + + var logger = DI.ServiceProvider.GetRequiredService>(); + logger.LogInformation("App initialization completed."); + } public override void Initialize() { AvaloniaXamlLoader.Load(this); @@ -19,7 +35,7 @@ namespace FileTime.GuiApp { desktop.MainWindow = new MainWindow { - DataContext = new MainWindowViewModel(), + DataContext = new MainWindowLoadingViewModel(), }; } diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj b/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj new file mode 100644 index 0000000..5c260d9 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/FileTime.GuiApp.App.csproj @@ -0,0 +1,44 @@ + + + WinExe + net6.0 + enable + + copyused + true + filetime.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Program.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Program.cs new file mode 100644 index 0000000..d170055 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Program.cs @@ -0,0 +1,62 @@ +using System; +using System.IO; +using Avalonia; +using FileTime.GuiApp; + +namespace FileTime.GuiApp +{ + public static class Program + { + public static string AppDataRoot { get; } + public static string EnvironmentName { get; } + + static Program() + { + +#if DEBUG + EnvironmentName = "Development"; + + AppDataRoot = Path.Combine(Environment.CurrentDirectory, "appdata"); +#else + EnvironmentName = "Release"; + + var possibleDataRootsPaths = new List() + { + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FileTime"), + Path.Combine(Assembly.GetEntryAssembly()?.Location ?? ".", "fallbackDataRoot") + }; + + string? appDataRoot = null; + foreach (var possibleAppDataRoot in possibleDataRootsPaths) + { + try + { + var appDataRootDirectory = new DirectoryInfo(possibleAppDataRoot); + if (!appDataRootDirectory.Exists) appDataRootDirectory.Create(); + + //TODO write test + appDataRoot = possibleAppDataRoot; + break; + } + catch { } + } + + if (appDataRoot == null) throw new UnauthorizedAccessException(); + AppDataRoot = appDataRoot; +#endif + } + + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .LogToTrace(); + } +} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs new file mode 100644 index 0000000..6ae33b2 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using FileTime.App.Core; +using FileTime.App.Core.Services; +using FileTime.App.Core.ViewModels; +using FileTime.Core.Services; +using FileTime.GuiApp.Configuration; +using FileTime.GuiApp.Logging; +using FileTime.GuiApp.ViewModels; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using Serilog.Configuration; + +namespace FileTime.GuiApp +{ + public static class Startup + { + internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection) + { + return serviceCollection + .AddSingleton() + .AddSingleton() + .AddSingleton(s => s.GetRequiredService()) + //TODO: move?? + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient(); + } + + internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection) + { + return serviceCollection.AddLogging(loggingBuilder => + loggingBuilder.AddSerilog(dispose: true) + ); + } + + internal static IServiceCollection AddConfiguration(this IServiceCollection serviceCollection) + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(MainConfiguration.Configuration) + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) + .AddJsonFile($"appsettings.{Program.EnvironmentName}.json", true, true) + .Build(); + + return serviceCollection + .Configure(configuration.GetSection(SectionNames.ProgramsSectionName)) + .Configure(configuration.GetSection(SectionNames.KeybindingSectionName)) + .AddSingleton(configuration); + } + + internal static IServiceProvider InitSerilog(this IServiceProvider serviceProvider) + { + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(serviceProvider.GetService()) + .Enrich.FromLogContext() + .WriteTo.File( + Path.Combine(Program.AppDataRoot, "logs", "appLog.log"), + fileSizeLimitBytes: 10 * 1024 * 1024, + rollOnFileSizeLimit: true, + rollingInterval: RollingInterval.Day) + .WriteTo.MessageBoxSink(serviceProvider) + .CreateLogger(); + + return serviceProvider; + } + + internal static LoggerConfiguration MessageBoxSink( + this LoggerSinkConfiguration loggerConfiguration, + IServiceProvider serviceProvider) + { + return loggerConfiguration.Sink(serviceProvider.GetService()); + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/appsettings.Development.json b/src/GuiApp/Avalonia/FileTime.GuiApp.App/appsettings.Development.json new file mode 100644 index 0000000..bfd4587 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Information", + "System": "Warning" + } + } + } +} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/filetime.ico b/src/GuiApp/Avalonia/FileTime.GuiApp.App/filetime.ico new file mode 100644 index 0000000..217f28f Binary files /dev/null and b/src/GuiApp/Avalonia/FileTime.GuiApp.App/filetime.ico differ diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.CustomImpl/FileTime.GuiApp.CustomImpl.csproj b/src/GuiApp/Avalonia/FileTime.GuiApp.CustomImpl/FileTime.GuiApp.CustomImpl.csproj new file mode 100644 index 0000000..4f17a4f --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.CustomImpl/FileTime.GuiApp.CustomImpl.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.CustomImpl/ViewModels/AppState.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.CustomImpl/ViewModels/AppState.cs new file mode 100644 index 0000000..8295111 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.CustomImpl/ViewModels/AppState.cs @@ -0,0 +1,6 @@ +using FileTime.App.Core; + +namespace FileTime.GuiApp.ViewModels +{ + public class AppState : AppStateBase { } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml deleted file mode 100644 index a325e5c..0000000 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/CommandBindingConfiguration.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/CommandBindingConfiguration.cs new file mode 100644 index 0000000..d1b1472 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/CommandBindingConfiguration.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Input; +using FileTime.App.Core.Command; + +namespace FileTime.GuiApp.Configuration +{ + public class CommandBindingConfiguration + { + public List Keys { get; set; } = new List(); + + public Commands Command { get; set; } = Commands.None; + + public string KeysDisplayText => GetKeysDisplayText(); + + public CommandBindingConfiguration() { } + + public CommandBindingConfiguration(Commands command, IEnumerable keys) + { + Keys = new List(keys); + Command = command; + } + + public CommandBindingConfiguration(Commands command, KeyConfig key) + { + Keys = new List() { key }; + Command = command; + } + + public CommandBindingConfiguration(Commands command, IEnumerable keys) + { + Keys = keys.Select(k => new KeyConfig(k)).ToList(); + Command = command; + } + + public CommandBindingConfiguration(Commands command, Key key) + { + Keys = new List() { new KeyConfig(key) }; + Command = command; + } + + public string GetKeysDisplayText() + { + var s = ""; + + foreach (var k in Keys) + { + var keyString = k.Key.ToString(); + + if (keyString.Length == 1) + { + s += AddKeyWithCtrlOrAlt(k, s, (_, _, _) => k.Shift ? keyString.ToUpper() : keyString.ToLower()); + } + else + { + s += AddKeyWithCtrlOrAlt(k, s, AddSpecialKey); + } + } + + return s; + } + + private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func keyProcessor) + { + var s = ""; + + bool ctrlOrAlt = key.Ctrl || key.Alt; + + if (ctrlOrAlt && currentText.Length > 0 && currentText.Last() != ' ') s += " "; + + if (key.Ctrl) s += "CTRL+"; + if (key.Alt) s += "ALT+"; + s += keyProcessor(key, currentText, ctrlOrAlt); + + if (ctrlOrAlt) s += " "; + + return s; + } + + private static string AddSpecialKey(KeyConfig key, string currentText, bool wasCtrlOrAlt) + { + var s = ""; + + if (currentText.Length > 0 && currentText.Last() != ' ' && !wasCtrlOrAlt) s += " "; + s += key.Key.ToString(); + if (!wasCtrlOrAlt) s += " "; + + return s; + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/KeyBindingConfiguration.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/KeyBindingConfiguration.cs new file mode 100644 index 0000000..4b2eed6 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/KeyBindingConfiguration.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace FileTime.GuiApp.Configuration +{ + public class KeyBindingConfiguration + { + public bool UseDefaultBindings { get; set; } = true; + public List DefaultKeyBindings { get; set; } = new(); + public List KeyBindings { get; set; } = new(); + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/KeyConfig.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/KeyConfig.cs new file mode 100644 index 0000000..8701239 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/KeyConfig.cs @@ -0,0 +1,22 @@ +using Avalonia.Input; + +namespace FileTime.GuiApp.Configuration +{ + public class KeyConfig + { + public Key Key { get; set; } + public bool Shift { get; set; } + public bool Alt { get; set; } + public bool Ctrl { get; set; } + + public KeyConfig() { } + + public KeyConfig(Key key, bool shift = false, bool alt = false, bool ctrl = false) + { + Key = key; + Shift = shift; + Alt = alt; + Ctrl = ctrl; + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/MainConfiguration.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/MainConfiguration.cs new file mode 100644 index 0000000..64a2e51 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/MainConfiguration.cs @@ -0,0 +1,128 @@ +using Avalonia.Input; +using FileTime.App.Core.Command; +using System; +using System.Collections.Generic; + +namespace FileTime.GuiApp.Configuration +{ + public static class MainConfiguration + { + private static readonly Lazy> _defaultKeybindings = new(InitDefaultKeyBindings); + + public static Dictionary Configuration { get; } + + static MainConfiguration() + { + Configuration = new(); + PopulateDefaultEditorPrograms(Configuration); + PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings)); + } + + private static void PopulateDefaultKeyBindings(Dictionary configuration, List commandBindingConfigs, string basePath) + { + for (var i = 0; i < commandBindingConfigs.Count; i++) + { + var baseKey = basePath + $":[{i}]:"; + var commandBindingConfig = commandBindingConfigs[i]; + configuration.Add(baseKey + nameof(CommandBindingConfiguration.Command), commandBindingConfig.Command.ToString()); + + for (var j = 0; j < commandBindingConfig.Keys.Count; j++) + { + var key = commandBindingConfig.Keys[j]; + var keyBaseKey = baseKey + $"keys:[{j}]:"; + configuration.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString()); + configuration.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString()); + configuration.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString()); + configuration.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString()); + } + } + } + + private static List InitDefaultKeyBindings() + { + return new List() + { + new CommandBindingConfiguration(Commands.AutoRefresh, new KeyConfig(Key.R, shift: true)), + new CommandBindingConfiguration(Commands.ChangeTimelineMode, new[] { Key.T, Key.M }), + new CommandBindingConfiguration(Commands.CloseTab, Key.Q), + new CommandBindingConfiguration(Commands.Compress, new[] { Key.Y, Key.C }), + new CommandBindingConfiguration(Commands.Copy, new[] { Key.Y, Key.Y }), + new CommandBindingConfiguration(Commands.CopyHash, new[] { Key.C, Key.H }), + new CommandBindingConfiguration(Commands.CopyPath, new[] { Key.C, Key.P }), + new CommandBindingConfiguration(Commands.CreateContainer, Key.F7), + new CommandBindingConfiguration(Commands.CreateContainer, new[] { Key.C, Key.C }), + new CommandBindingConfiguration(Commands.CreateElement, new[] { Key.C, Key.E }), + new CommandBindingConfiguration(Commands.Cut, new[] { Key.D, Key.D }), + new CommandBindingConfiguration(Commands.Edit, new KeyConfig(Key.F4)), + new CommandBindingConfiguration(Commands.EnterRapidTravel, new KeyConfig(Key.OemComma, shift: true)), + new CommandBindingConfiguration(Commands.FindByName, new[] { Key.F, Key.N }), + new CommandBindingConfiguration(Commands.FindByNameRegex, new[] { Key.F, Key.R }), + new CommandBindingConfiguration(Commands.GoToHome, new[] { Key.G, Key.H }), + new CommandBindingConfiguration(Commands.GoToPath, new KeyConfig(Key.L, ctrl: true)), + new CommandBindingConfiguration(Commands.GoToPath, new[] { Key.G, Key.P }), + new CommandBindingConfiguration(Commands.GoToProvider, new[] { Key.G, Key.T }), + new CommandBindingConfiguration(Commands.GoToRoot, new[] { Key.G, Key.R }), + new CommandBindingConfiguration(Commands.HardDelete, new[] { new KeyConfig(Key.D,shift: true), new KeyConfig(Key.D, shift: true) }), + new CommandBindingConfiguration(Commands.Mark, Key.Space), + new CommandBindingConfiguration(Commands.MoveToLast, new KeyConfig(Key.G, shift: true)), + new CommandBindingConfiguration(Commands.MoveToFirst, new[] { Key.G, Key.G }), + new CommandBindingConfiguration(Commands.NextTimelineBlock, Key.L ), + new CommandBindingConfiguration(Commands.NextTimelineCommand, Key.J ), + new CommandBindingConfiguration(Commands.OpenInFileBrowser, new[] { Key.O, Key.E }), + new CommandBindingConfiguration(Commands.PasteMerge, new[] { Key.P, Key.P }), + new CommandBindingConfiguration(Commands.PasteOverwrite, new[] { Key.P, Key.O }), + new CommandBindingConfiguration(Commands.PasteSkip, new[] { Key.P, Key.S }), + new CommandBindingConfiguration(Commands.PinFavorite, new[] { Key.F, Key.P }), + new CommandBindingConfiguration(Commands.PreviousTimelineBlock, Key.H ), + new CommandBindingConfiguration(Commands.PreviousTimelineCommand, Key.K ), + new CommandBindingConfiguration(Commands.Refresh, Key.R), + new CommandBindingConfiguration(Commands.Rename, Key.F2), + new CommandBindingConfiguration(Commands.Rename, new[] { Key.C, Key.W }), + new CommandBindingConfiguration(Commands.RunCommand, new KeyConfig(Key.D4, shift: true)), + new CommandBindingConfiguration(Commands.ScanContainerSize, new[] { Key.C, Key.S }), + new CommandBindingConfiguration(Commands.ShowAllShotcut, Key.F1), + new CommandBindingConfiguration(Commands.SoftDelete, new[] { new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true) }), + new CommandBindingConfiguration(Commands.SwitchToLastTab, Key.D9), + new CommandBindingConfiguration(Commands.SwitchToTab1, Key.D1), + new CommandBindingConfiguration(Commands.SwitchToTab2, Key.D2), + new CommandBindingConfiguration(Commands.SwitchToTab3, Key.D3), + new CommandBindingConfiguration(Commands.SwitchToTab4, Key.D4), + new CommandBindingConfiguration(Commands.SwitchToTab5, Key.D5), + new CommandBindingConfiguration(Commands.SwitchToTab6, Key.D6), + new CommandBindingConfiguration(Commands.SwitchToTab7, Key.D7), + new CommandBindingConfiguration(Commands.SwitchToTab8, Key.D8), + new CommandBindingConfiguration(Commands.TimelinePause, new[] { Key.T, Key.P }), + new CommandBindingConfiguration(Commands.TimelineRefresh, new[] { Key.T, Key.R }), + new CommandBindingConfiguration(Commands.TimelineStart, new[] { Key.T, Key.S }), + new CommandBindingConfiguration(Commands.ToggleAdvancedIcons, new[] { Key.Z, Key.I }), + new CommandBindingConfiguration(Commands.GoUp, Key.Left), + new CommandBindingConfiguration(Commands.Open, Key.Right), + new CommandBindingConfiguration(Commands.OpenOrRun, Key.Enter), + new CommandBindingConfiguration(Commands.MoveCursorUp, Key.Up), + new CommandBindingConfiguration(Commands.MoveCursorDown, Key.Down), + new CommandBindingConfiguration(Commands.MoveCursorUpPage, Key.PageUp), + new CommandBindingConfiguration(Commands.MoveCursorDownPage, Key.PageDown), + }; + } + + private static void PopulateDefaultEditorPrograms(Dictionary configuration) + { + var editorPrograms = new List() + { + new ProgramConfiguration(@"c:\Program Files\Notepad++\notepad++.exe"), + new ProgramConfiguration("notepad.exe"), + }; + + for (var i = 0; i < editorPrograms.Count; i++) + { + if (editorPrograms[i].Path is not string path) continue; + configuration.Add($"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}", path); + + if (editorPrograms[i].Arguments is string arguments) + { + configuration.Add($"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}", arguments); + } + } + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/ProgramConfiguration.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/ProgramConfiguration.cs new file mode 100644 index 0000000..83df6da --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/ProgramConfiguration.cs @@ -0,0 +1,16 @@ +namespace FileTime.GuiApp.Configuration +{ + public class ProgramConfiguration + { + public string? Path { get; set; } + public string? Arguments { get; set; } + + public ProgramConfiguration() { } + + public ProgramConfiguration(string? path, string? arguments = null) + { + Path = path; + Arguments = arguments; + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/ProgramsConfiguration.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/ProgramsConfiguration.cs new file mode 100644 index 0000000..446abdf --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/ProgramsConfiguration.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace FileTime.GuiApp.Configuration +{ + public class ProgramsConfiguration + { + public List DefaultEditorPrograms { get; set; } = new(); + public List EditorPrograms { get; set; } = new(); + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/SectionNames.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/SectionNames.cs new file mode 100644 index 0000000..be44f8f --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Configuration/SectionNames.cs @@ -0,0 +1,8 @@ +namespace FileTime.GuiApp.Configuration +{ + public static class SectionNames + { + public const string KeybindingSectionName = "KeyBindings"; + public const string ProgramsSectionName = "Programs"; + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/DateTimeConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/DateTimeConverter.cs new file mode 100644 index 0000000..3d8b00f --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/DateTimeConverter.cs @@ -0,0 +1,18 @@ +using System.Globalization; +using Avalonia.Data.Converters; + +namespace FileTime.GuiApp.Converters +{ + public class DateTimeConverter : IValueConverter + { + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => + value is DateTime dateTime && parameter is string parameterS + ? dateTime.ToString(parameterS) + : value; + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ 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 new file mode 100644 index 0000000..30d57bc --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/FormatSizeConverter.cs @@ -0,0 +1,47 @@ +using System.Globalization; +using Avalonia.Data.Converters; + +namespace FileTime.GuiApp.Converters +{ + public class FormatSizeConverter : IValueConverter + { + private const long OneKiloByte = 1024; + private const long OneMegaByte = OneKiloByte * 1024; + private const long OneGigaByte = OneMegaByte * 1024; + private const long OneTerraByte = OneGigaByte * 1024; + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return (value, int.TryParse(parameter?.ToString(), out var prec)) switch + { + (long size, true) => ToSizeString(size, prec), + (long size, false) => ToSizeString(size), + (null, _) => "...", + _ => value + }; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public static string ToSizeString(long fileSize, int precision = 1) + { + var fileSizeD = (decimal)fileSize; + var (size, suffix) = fileSize switch + { + > OneTerraByte => (fileSizeD / OneTerraByte, "T"), + > OneGigaByte => (fileSizeD / OneGigaByte, "G"), + > OneMegaByte => (fileSizeD / OneMegaByte, "M"), + > OneKiloByte => (fileSizeD / OneKiloByte, "K"), + _ => (fileSizeD, "B") + }; + + var result = string.Format("{0:N" + precision + "}", size).Replace(',', '.'); + + if (result.Contains('.')) result = result.TrimEnd('0').TrimEnd('.'); + return result + " " + suffix; + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/GetFileExtensionConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/GetFileExtensionConverter.cs new file mode 100644 index 0000000..6d55585 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/GetFileExtensionConverter.cs @@ -0,0 +1,24 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using FileTime.App.Core.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace FileTime.GuiApp.Converters +{ + public class GetFileExtensionConverter : IValueConverter + { + private IItemNameConverterService? _itemNameConverterService; + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not string fullName) return value; + _itemNameConverterService ??= DI.ServiceProvider.GetRequiredService(); + + return _itemNameConverterService.GetFileExtension(fullName); + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/ItemViewModeToBrushConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/ItemViewModeToBrushConverter.cs new file mode 100644 index 0000000..29a8800 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/ItemViewModeToBrushConverter.cs @@ -0,0 +1,41 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Media; +using FileTime.App.Core.Models.Enums; + +namespace FileTime.GuiApp.Converters +{ + public class ItemViewModeToBrushConverter : IValueConverter + { + public Brush? DefaultBrush { get; set; } + public Brush? AlternativeBrush { get; set; } + public Brush? SelectedBrush { get; set; } + public Brush? MarkedBrush { get; set; } + public Brush? MarkedSelectedBrush { get; set; } + public Brush? MarkedAlternativeBrush { get; set; } + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is ItemViewMode viewMode) + { + return viewMode switch + { + ItemViewMode.Default => DefaultBrush, + ItemViewMode.Alternative => AlternativeBrush, + ItemViewMode.Selected => SelectedBrush, + ItemViewMode.Marked => MarkedBrush, + ItemViewMode.MarkedSelected => MarkedSelectedBrush, + ItemViewMode.MarkedAlternative => MarkedAlternativeBrush, + _ => throw new NotImplementedException() + }; + } + + return value; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/ItemViewModelIsAttributeTypeConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/ItemViewModelIsAttributeTypeConverter.cs new file mode 100644 index 0000000..edadd74 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/ItemViewModelIsAttributeTypeConverter.cs @@ -0,0 +1,37 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using FileTime.App.Core.Models.Enums; +using FileTime.App.Core.ViewModels; + +namespace FileTime.GuiApp.Converters +{ + public class ItemViewModelIsAttributeTypeConverter : IValueConverter + { + public bool Invert { get; set; } + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + var attributeType = GetAttributeType(value); + if (parameter == null) return attributeType; + var result = parameter is ItemAttributeType targetAttribute && attributeType == targetAttribute; + if (Invert && parameter is ItemAttributeType) result = !result; + return result; + } + + private static ItemAttributeType? GetAttributeType(object? value) + { + return value switch + { + IFileViewModel => ItemAttributeType.File, + IContainerSizeContainerViewModel => ItemAttributeType.SizeContainer, + IElementViewModel => ItemAttributeType.Element, + IContainerViewModel => ItemAttributeType.Container, + _ => null + }; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/NamePartShrinkerConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/NamePartShrinkerConverter.cs new file mode 100644 index 0000000..fb8d62c --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/NamePartShrinkerConverter.cs @@ -0,0 +1,115 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Media; +using FileTime.App.Core.Models; +using FileTime.GuiApp.ViewModels; + +namespace FileTime.GuiApp.Converters +{ + public class NamePartShrinkerConverter : IMultiValueConverter + { + private const int PixelPerChar = 8; + public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) + { + if (values.Count > 0 && values[0] is IList nameParts) + { + var attributeWidth = values[2] is bool b && b ? 340 : 0; + var newNameParts = nameParts; + if (values.Count > 1 && values[1] is double width && width > 0) + { + newNameParts = GetNamePartsForWidth(nameParts, width - attributeWidth); + } + + return newNameParts.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList(); + } + return null; + } + + private static List GetNamePartsForWidth(IList nameParts, double maxWidth) + { + //Best case, we are in the range + var textLength = nameParts.Select(p => p.Text.Length).Sum(); + if (textLength * PixelPerChar <= maxWidth) + { + return nameParts.ToList(); + } + + //Trying at least with the special parts + var newNameParts = new ItemNamePart?[nameParts.Count]; + for (var i = 0; i < nameParts.Count; i++) + { + if (nameParts[i].IsSpecial) + { + newNameParts[i] = nameParts[i]; + } + } + + return GetNamePartsForWidthOptimistic(nameParts, newNameParts, maxWidth); + } + + private static List GetNamePartsForWidthOptimistic(IList nameParts, ItemNamePart?[] newNameParts, double maxWidth) + { + var trimmedIndexes = new List(); + for (var i = 0; i < newNameParts.Length; i++) + { + if (newNameParts[i] == null) + { + trimmedIndexes.Add(i); + newNameParts[i] = new ItemNamePart("..."); + } + } + + var textLength = newNameParts.Select(p => p?.Text.Length ?? 0).Sum(); + if (textLength * PixelPerChar > maxWidth) + { + return GetNamePartsForWidthPessimistic(nameParts, maxWidth); + } + + foreach (var trimmedIndex in trimmedIndexes) + { + var baseTextLength = newNameParts.Select((p, i) => i == trimmedIndex ? 0 : (p?.Text.Length ?? 0)).Sum(); + var proposedText = nameParts[trimmedIndex].Text; + var trimmed = false; + while ((baseTextLength + proposedText.Length + (trimmed ? 3 : 0)) * PixelPerChar > maxWidth) + { + proposedText = proposedText[0..^1]; + trimmed = true; + } + newNameParts[trimmedIndex] = new ItemNamePart(proposedText + (trimmed ? "..." : "")); + if (trimmed) break; + } + + return newNameParts.OfType().ToList(); + } + + private static List GetNamePartsForWidthPessimistic(IList nameParts, double maxWidth) + { + var newNameParts = new List(nameParts); + foreach (var namePart in nameParts) + { + var baseTextLength = newNameParts.Select(p => p.Text.Length).Sum(); + var proposedText = namePart.Text; + var trimmed = false; + + while ((baseTextLength + 3) * PixelPerChar > maxWidth && proposedText != "") + { + proposedText = proposedText[0..^1]; + trimmed = true; + } + + if (!string.IsNullOrWhiteSpace(proposedText)) newNameParts.Add(new ItemNamePart(proposedText, namePart.IsSpecial)); + if (trimmed) break; + } + if (newNameParts.Last().IsSpecial) + { + newNameParts.Add(new ItemNamePart("...")); + } + else + { + var last = newNameParts.Last(); + last.Text += "..."; + } + return newNameParts; + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/DependencyInjection.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/DependencyInjection.cs new file mode 100644 index 0000000..8d18446 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/DependencyInjection.cs @@ -0,0 +1,7 @@ +namespace FileTime.GuiApp +{ + public static class DI + { + public static IServiceProvider ServiceProvider { get; set; } = null!; + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/FileTime.GuiApp.csproj b/src/GuiApp/Avalonia/FileTime.GuiApp/FileTime.GuiApp.csproj index a4ccf87..0325777 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/FileTime.GuiApp.csproj +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/FileTime.GuiApp.csproj @@ -1,36 +1,47 @@ - + + - WinExe net6.0 + enable enable - - copyused - true - Assets\filetime.ico + + + + + - - + + MSBuild:Compile + - - - + + MainWindow.axaml + + - + + + + + + + + - + + + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Logging/ToastMessageSink.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Logging/ToastMessageSink.cs new file mode 100644 index 0000000..e880018 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Logging/ToastMessageSink.cs @@ -0,0 +1,24 @@ +using Serilog.Core; +using Serilog.Events; + +namespace FileTime.GuiApp.Logging +{ + public class ToastMessageSink : ILogEventSink + { + //private readonly IDialogService dialogService; + + public ToastMessageSink(/*IDialogService dialogService*/) + { + //this.dialogService = dialogService; + } + + public void Emit(LogEvent logEvent) + { + /*if (logEvent.Level >= LogEventLevel.Error) + { + var message = logEvent.RenderMessage(); + dialogService.ShowToastMessage(message); + }*/ + } + } +} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Models/InputElementWrapper.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Models/InputElementWrapper.cs new file mode 100644 index 0000000..197f4ac --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Models/InputElementWrapper.cs @@ -0,0 +1,20 @@ +namespace FileTime.GuiApp.Models +{ + public class InputElementWrapper + { + /*public InputElement InputElement { get; } + + public string Value { get; set; } + + public object? Option { get; set; } + + public char? PasswordChar { get; set; } + + public InputElementWrapper(InputElement inputElement, string? defaultValue = null) + { + InputElement = inputElement; + Value = defaultValue ?? ""; + PasswordChar = inputElement.InputType == InputType.Password ? '*' : null; + }*/ + } +} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Program.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Program.cs deleted file mode 100644 index 1c8c973..0000000 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Program.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.ReactiveUI; - -namespace FileTime.GuiApp -{ - class Program - { - // Initialization code. Don't use any Avalonia, third-party APIs or any - // SynchronizationContext-reliant code before AppMain is called: things aren't initialized - // yet and stuff might break. - [STAThread] - public static void Main(string[] args) => BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); - - // Avalonia configuration, don't remove; also used by visual designer. - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .UsePlatformDetect() - .LogToTrace(); - } -} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/IMainWindowViewModelBase.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/IMainWindowViewModelBase.cs new file mode 100644 index 0000000..386e533 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/IMainWindowViewModelBase.cs @@ -0,0 +1,7 @@ +namespace FileTime.GuiApp.ViewModels +{ + public interface IMainWindowViewModelBase + { + bool Loading { get; } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/ItemNamePartViewModel.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/ItemNamePartViewModel.cs new file mode 100644 index 0000000..f3ce2c0 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/ItemNamePartViewModel.cs @@ -0,0 +1,16 @@ +using Avalonia.Media; + +namespace FileTime.GuiApp.ViewModels +{ + public class ItemNamePartViewModel + { + public string Text { get; set; } + public TextDecorationCollection? TextDecorations { get; set; } + + public ItemNamePartViewModel(string text, TextDecorationCollection? textDecorations) + { + Text = text; + TextDecorations = textDecorations; + } + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowLoadingViewModel.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowLoadingViewModel.cs new file mode 100644 index 0000000..576d851 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowLoadingViewModel.cs @@ -0,0 +1,7 @@ +namespace FileTime.GuiApp.ViewModels +{ + public class MainWindowLoadingViewModel : IMainWindowViewModelBase + { + public bool Loading => true; + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs index 76038d6..4d8491a 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs @@ -1,10 +1,37 @@ using System; -using System.Collections.Generic; -using System.Text; +using Avalonia.Input; +using FileTime.App.Core; +using FileTime.App.Core.ViewModels; +using FileTime.Core.Models; +using FileTime.Core.Services; +using FileTime.Providers.Local; +using Microsoft.Extensions.DependencyInjection; +using MvvmGen; namespace FileTime.GuiApp.ViewModels { - public class MainWindowViewModel + [ViewModel] + [Inject(typeof(IAppState), "_appState")] + [Inject(typeof(ILocalContentProvider), "_localContentProvider")] + [Inject(typeof(IServiceProvider), PropertyName = "_serviceProvider")] + public partial class MainWindowViewModel : IMainWindowViewModelBase { + public bool Loading => false; + public IAppState AppState => _appState; + + partial void OnInitialize() + { + if (AppState.Tabs.Count == 0) + { + var tab = _serviceProvider.GetInitableResolver(_localContentProvider).GetRequiredService(); + var tabViewModel = _serviceProvider.GetInitableResolver(tab).GetRequiredService(); + + _appState.AddTab(tabViewModel); + } + } + + public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action setHandled) + { + } } } diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/ItemView.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/ItemView.axaml new file mode 100644 index 0000000..5e97a7f --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/ItemView.axaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/ItemView.axaml.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/ItemView.axaml.cs new file mode 100644 index 0000000..728f75e --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/ItemView.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia; +using Avalonia.Controls; + +namespace FileTime.GuiApp.Views +{ + public partial class ItemView : UserControl + { + public static readonly StyledProperty ShowAttributesProperty = AvaloniaProperty.Register(nameof(ShowAttributes), true); + + public bool ShowAttributes + { + get => GetValue(ShowAttributesProperty); + set => SetValue(ShowAttributesProperty, value); + } + + public ItemView() + { + InitializeComponent(); + } + } +} diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml index 71e0c5b..22e81ca 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml @@ -1,17 +1,54 @@ + Title="FileTime" + TransparencyLevelHint="Blur" + Background="Transparent" + ExtendClientAreaToDecorationsHint="True" + x:DataType="vm:MainWindowViewModel" + x:CompileBindings="True"> - - - + + + + + + + + + + + + + + + - + + + + + + + + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs index 181d0c0..dd572b0 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml.cs @@ -1,12 +1,53 @@ +using System; using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Markup.Xaml; +using FileTime.GuiApp.Models; +using FileTime.GuiApp.ViewModels; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace FileTime.GuiApp.Views { public partial class MainWindow : Window { + private readonly ILogger? _logger; + private InputElementWrapper? _inputElementWrapper; + + public MainWindowViewModel? ViewModel + { + get => DataContext as MainWindowViewModel; + set + { + if (value != DataContext) + { + DataContext = value; + } + } + } + public MainWindow() { + _logger = DI.ServiceProvider.GetService>(); + _logger?.LogInformation($"Starting {nameof(MainWindow)} initialization..."); InitializeComponent(); } + + private void OnWindowOpened(object sender, EventArgs e) + { + if (DataContext is not MainWindowViewModel) + { + _logger?.LogInformation($"{nameof(MainWindow)} opened, starting {nameof(MainWindowViewModel)} initialization..."); + ViewModel = DI.ServiceProvider.GetRequiredService(); + } + } + + private void OnKeyDown(object sender, KeyEventArgs e) + { + if (_inputElementWrapper == null) + { + ViewModel?.ProcessKeyDown(e.Key, e.KeyModifiers, h => e.Handled = h); + } + } } } \ No newline at end of file diff --git a/src/Library/InitableService/Initable.cs b/src/Library/InitableService/Initable.cs new file mode 100644 index 0000000..81147d7 --- /dev/null +++ b/src/Library/InitableService/Initable.cs @@ -0,0 +1,148 @@ +// Autogenerated +namespace InitableService; + +public interface IInitable +{ + void Init(); +} +public interface IInitable +{ + void Init(T1 obj1); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14); +} +public interface IInitable +{ + void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15); +} +public interface IAsyncInitable +{ + Task InitAsync(); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14); +} + +public interface IAsyncInitable +{ + Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15); +} + + diff --git a/src/Library/InitableService/InitableExtensions.cs b/src/Library/InitableService/InitableExtensions.cs new file mode 100644 index 0000000..a35ea10 --- /dev/null +++ b/src/Library/InitableService/InitableExtensions.cs @@ -0,0 +1,1193 @@ +// Autogenerated +using InitableService; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class InitableExtensions +{ + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider) + { + return new Resolver(serviceProvider); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1) + { + return new Resolver(serviceProvider, obj1); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2) + { + return new Resolver(serviceProvider, obj1, obj2); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3) + { + return new Resolver(serviceProvider, obj1, obj2, obj3); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14); + } + + public static Resolver GetInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15) + { + return new Resolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14, obj15); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider) + { + return new AsyncResolver(serviceProvider); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1) + { + return new AsyncResolver(serviceProvider, obj1); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2) + { + return new AsyncResolver(serviceProvider, obj1, obj2); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14); + } + + public static AsyncResolver GetAsyncInitableResolver(this IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15) + { + return new AsyncResolver(serviceProvider, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14, obj15); + } + +} +public class Resolver +{ + IServiceProvider _serviceProvider; + public Resolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + public Resolver(IServiceProvider serviceProvider, T1 obj1) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + private T13 _obj13; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + _obj13 = obj13; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12, _obj13); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + private T13 _obj13; + private T14 _obj14; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + _obj13 = obj13; + _obj14 = obj14; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12, _obj13, _obj14); + return initableService; + } +} + +public class Resolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + private T13 _obj13; + private T14 _obj14; + private T15 _obj15; + public Resolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + _obj13 = obj13; + _obj14 = obj14; + _obj15 = obj15; + } + + public TResult GetRequiredService() + where TResult : class, IInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + initableService.Init(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12, _obj13, _obj14, _obj15); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + public AsyncResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + private T13 _obj13; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + _obj13 = obj13; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12, _obj13); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + private T13 _obj13; + private T14 _obj14; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + _obj13 = obj13; + _obj14 = obj14; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12, _obj13, _obj14); + return initableService; + } +} + +public class AsyncResolver +{ + IServiceProvider _serviceProvider; + private T1 _obj1; + private T2 _obj2; + private T3 _obj3; + private T4 _obj4; + private T5 _obj5; + private T6 _obj6; + private T7 _obj7; + private T8 _obj8; + private T9 _obj9; + private T10 _obj10; + private T11 _obj11; + private T12 _obj12; + private T13 _obj13; + private T14 _obj14; + private T15 _obj15; + public AsyncResolver(IServiceProvider serviceProvider, T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15) + { + _serviceProvider = serviceProvider; + _obj1 = obj1; + _obj2 = obj2; + _obj3 = obj3; + _obj4 = obj4; + _obj5 = obj5; + _obj6 = obj6; + _obj7 = obj7; + _obj8 = obj8; + _obj9 = obj9; + _obj10 = obj10; + _obj11 = obj11; + _obj12 = obj12; + _obj13 = obj13; + _obj14 = obj14; + _obj15 = obj15; + } + + public async Task GetRequiredServiceAsync() + where TResult : class, IAsyncInitable + { + var initableService = _serviceProvider.GetRequiredService()!; + await initableService.InitAsync(_obj1, _obj2, _obj3, _obj4, _obj5, _obj6, _obj7, _obj8, _obj9, _obj10, _obj11, _obj12, _obj13, _obj14, _obj15); + return initableService; + } +} + diff --git a/src/Library/InitableService/InitableService.csproj b/src/Library/InitableService/InitableService.csproj new file mode 100644 index 0000000..dbde20d --- /dev/null +++ b/src/Library/InitableService/InitableService.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/Library/InitableService/generateExtensions.csx b/src/Library/InitableService/generateExtensions.csx new file mode 100644 index 0000000..db67766 --- /dev/null +++ b/src/Library/InitableService/generateExtensions.csx @@ -0,0 +1,180 @@ +#!/usr/bin/env dotnet-script + +{ + const string header = +@"// Autogenerated +using InitableService; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class InitableExtensions +{ +"; + + const string footer = "}"; + using var initableWriter = File.CreateText("InitableExtensions.cs"); + initableWriter.WriteLine(header); + const int generateForParams = 15; + + for (var i = 0; i <= generateForParams; i++) + { + WriteInitableExtension(initableWriter, false, i); + initableWriter.WriteLine(); + } + + for (var i = 0; i <= generateForParams; i++) + { + WriteInitableExtension(initableWriter, true, i); + initableWriter.WriteLine(); + } + + initableWriter.WriteLine(footer); + + for (var i = 0; i <= generateForParams; i++) + { + WriteInitableResolver(initableWriter, false, i); + initableWriter.WriteLine(); + } + + for (var i = 0; i <= generateForParams; i++) + { + WriteInitableResolver(initableWriter, true, i); + initableWriter.WriteLine(); + } + + initableWriter.Flush(); +} + +void WriteInitableExtension(StreamWriter initableWriter, bool isAsync, int i) +{ + initableWriter.Write($"\tpublic static {(isAsync ? "Async" : "")}Resolver"); + if (i > 0) + { + initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">"); + } + initableWriter.Write($" Get{(isAsync ? "Async" : "")}InitableResolver"); + if (i > 0) + { + initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">"); + } + + initableWriter.Write("("); + var thisParameter = "this IServiceProvider serviceProvider"; + + if (i > 0) + { + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"T{c} obj{c}").Prepend(thisParameter))); + } + else + { + initableWriter.Write(thisParameter); + } + + initableWriter.WriteLine(")"); + initableWriter.WriteLine("\t{"); + initableWriter.Write($"\t\treturn new {(isAsync ? "Async" : "")}Resolver"); + + if (i > 0) + { + initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">"); + } + + initableWriter.Write("("); + if (i > 0) + { + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"obj{c}").Prepend("serviceProvider"))); + } + else + { + initableWriter.Write("serviceProvider"); + } + initableWriter.WriteLine(");"); + + initableWriter.WriteLine("\t}"); +} + +void WriteInitableResolver(StreamWriter initableWriter, bool isAsync, int i) +{ + initableWriter.Write($"public class {(isAsync ? "Async" : "")}Resolver"); + if (i > 0) + { + initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">"); + } + initableWriter.WriteLine(); + initableWriter.WriteLine("{"); + initableWriter.WriteLine("\tIServiceProvider _serviceProvider;"); + if (i > 0) + { + for (var j = 1; j <= i; j++) + { + initableWriter.WriteLine($"\tprivate T{j} _obj{j};"); + } + } + + initableWriter.Write($"\tpublic {(isAsync ? "Async" : "")}Resolver("); + if (i > 0) + { + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"T{c} obj{c}").Prepend("IServiceProvider serviceProvider"))); + } + else + { + initableWriter.Write("IServiceProvider serviceProvider"); + } + + initableWriter.WriteLine(")"); + initableWriter.WriteLine("\t{"); + initableWriter.WriteLine("\t\t_serviceProvider = serviceProvider;"); + if (i > 0) + { + for (var j = 1; j <= i; j++) + { + initableWriter.WriteLine($"\t\t_obj{j} = obj{j};"); + } + } + initableWriter.WriteLine("\t}"); + initableWriter.WriteLine(""); + + var returnType = isAsync ? "async Task" : "TResult"; + initableWriter.WriteLine($"\tpublic {returnType} GetRequiredService{(isAsync ? "Async" : "")}()"); + + + + initableWriter.Write($"\t\twhere TResult : class, I{(isAsync ? "Async" : "")}Initable"); + if (i > 0) + { + initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">"); + } + initableWriter.WriteLine(""); + initableWriter.WriteLine("\t{"); + initableWriter.WriteLine("\t\tvar initableService = _serviceProvider.GetRequiredService()!;"); + if (isAsync) + { + initableWriter.Write("\t\tawait initableService.InitAsync"); + } + else + { + initableWriter.Write("\t\tinitableService.Init"); + } + + initableWriter.Write("("); + + if (i > 0) + { + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"_obj{c}"))); + } + initableWriter.WriteLine(");"); + initableWriter.WriteLine("\t\treturn initableService;"); + + initableWriter.WriteLine("\t}"); + initableWriter.WriteLine("}"); +} \ No newline at end of file diff --git a/src/Library/InitableService/generateInterfaces.csx b/src/Library/InitableService/generateInterfaces.csx new file mode 100644 index 0000000..395990d --- /dev/null +++ b/src/Library/InitableService/generateInterfaces.csx @@ -0,0 +1,66 @@ +#!/usr/bin/env dotnet-script + +{ + const string header = +@"// Autogenerated +namespace InitableService; +"; + + const string footer = ""; + using var initableWriter = File.CreateText("Initable.cs"); + initableWriter.WriteLine(header); + const int generateForParams = 15; + + for (var i = 0; i <= generateForParams; i++) + { + WriteInitable(initableWriter, false, i); + } + + for (var i = 0; i <= generateForParams; i++) + { + WriteInitable(initableWriter, true, i); + initableWriter.WriteLine(); + } + + initableWriter.WriteLine(footer); + initableWriter.Flush(); +} + +void WriteInitable(StreamWriter initableWriter, bool isAsync, int i) +{ + initableWriter.Write($"public interface I{(isAsync ? "Async" : "")}Initable"); + if (i > 0) + { + initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">"); + } + + initableWriter.WriteLine(); + initableWriter.WriteLine("{"); + + if (isAsync) + { + initableWriter.Write("\tTask InitAsync"); + } + else + { + initableWriter.Write("\tvoid Init"); + } + + if (i > 0) + { + /*initableWriter.Write("<"); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c))); + initableWriter.Write(">");*/ + initableWriter.Write("("); + initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"T{c} obj{c}"))); + initableWriter.Write(")"); + } + else + { + initableWriter.Write("()"); + } + initableWriter.WriteLine(";"); + initableWriter.WriteLine("}"); +} \ No newline at end of file diff --git a/src/Providers/FileTime.Providers.Local.Abstractions/FileTime.Providers.Local.Abstractions.csproj b/src/Providers/FileTime.Providers.Local.Abstractions/FileTime.Providers.Local.Abstractions.csproj new file mode 100644 index 0000000..b077d38 --- /dev/null +++ b/src/Providers/FileTime.Providers.Local.Abstractions/FileTime.Providers.Local.Abstractions.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/Providers/FileTime.Providers.Local.Abstractions/ILocalContentProvider.cs b/src/Providers/FileTime.Providers.Local.Abstractions/ILocalContentProvider.cs new file mode 100644 index 0000000..0144a2f --- /dev/null +++ b/src/Providers/FileTime.Providers.Local.Abstractions/ILocalContentProvider.cs @@ -0,0 +1,9 @@ +using FileTime.Core.Services; + +namespace FileTime.Providers.Local +{ + public interface ILocalContentProvider : IContentProvider + { + + } +} \ No newline at end of file diff --git a/src/Providers/FileTime.Providers.Local/FileTime.Providers.Local.csproj b/src/Providers/FileTime.Providers.Local/FileTime.Providers.Local.csproj index 4c5b018..176e522 100644 --- a/src/Providers/FileTime.Providers.Local/FileTime.Providers.Local.csproj +++ b/src/Providers/FileTime.Providers.Local/FileTime.Providers.Local.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs b/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs index d9b20fc..02b7214 100644 --- a/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs +++ b/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs @@ -5,7 +5,7 @@ using FileTime.Core.Services; namespace FileTime.Providers.Local { - public class LocalContentProvider : ContentProviderBase + public class LocalContentProvider : ContentProviderBase, ILocalContentProvider { protected bool IsCaseInsensitive { get; init; } public LocalContentProvider() : base("local") @@ -43,7 +43,7 @@ namespace FileTime.Providers.Local return Task.FromResult((IItem)FileToElement(new FileInfo(path))); } - throw new FileNotFoundException(); + throw new FileNotFoundException("Directory or file not found", path); } public override Task> GetItemsByContainerAsync(FullName fullName) => Task.FromResult(GetItemsByContainer(fullName)); diff --git a/src/Providers/FileTime.Providers.Local/Startup.cs b/src/Providers/FileTime.Providers.Local/Startup.cs index f01f4da..121f452 100644 --- a/src/Providers/FileTime.Providers.Local/Startup.cs +++ b/src/Providers/FileTime.Providers.Local/Startup.cs @@ -8,8 +8,8 @@ namespace FileTime.Providers.Local public static IServiceCollection AddLocalServices(this IServiceCollection serviceCollection) { return serviceCollection - .AddSingleton() - .AddSingleton(sp => sp.GetService() ?? throw new Exception($"No {nameof(LocalContentProvider)} instance found")); + .AddSingleton() + .AddSingleton(sp => sp.GetRequiredService()); } } } \ No newline at end of file