Use primary constructors

This commit is contained in:
2023-10-31 14:18:21 +01:00
parent 2a7aa6bf3a
commit 17466de219
25 changed files with 132 additions and 339 deletions

View File

@@ -3,9 +3,9 @@ using PropertyChanged.SourceGenerator;
namespace FileTime.Core.Interactions; namespace FileTime.Core.Interactions;
public partial class OptionsInputElement<T> : InputElementBase, IOptionsInputElement, INotifyPropertyChanged public partial class OptionsInputElement<T>(string label, IEnumerable<OptionElement<T>> options) : InputElementBase(label, InputType.Options), IOptionsInputElement, INotifyPropertyChanged
{ {
public IReadOnlyCollection<OptionElement<T>> Options { get; } public IReadOnlyCollection<OptionElement<T>> Options { get; } = Enumerable.ToList<OptionElement<T>>(options);
[Notify] private T? _value; [Notify] private T? _value;
@@ -26,9 +26,4 @@ public partial class OptionsInputElement<T> : InputElementBase, IOptionsInputEle
} }
} }
} }
public OptionsInputElement(string label, IEnumerable<OptionElement<T>> options) : base(label, InputType.Options)
{
Options = options.ToList();
}
} }

View File

@@ -1,8 +1,7 @@
namespace GeneralInputKey; namespace GeneralInputKey;
public class GeneralKeyEventArgs public class GeneralKeyEventArgs(Action<bool>? handledChanged = null)
{ {
private readonly Action<bool>? _handledChanged;
private bool _handled; private bool _handled;
public required Keys? Key { get; init; } public required Keys? Key { get; init; }
public required char KeyChar { get; init; } public required char KeyChar { get; init; }
@@ -16,13 +15,8 @@ public class GeneralKeyEventArgs
if (_handled != value) if (_handled != value)
{ {
_handled = value; _handled = value;
_handledChanged?.Invoke(value); handledChanged?.Invoke(value);
} }
} }
} }
public GeneralKeyEventArgs(Action<bool>? handledChanged = null)
{
_handledChanged = handledChanged;
}
} }

View File

@@ -5,9 +5,8 @@ using TerminalUI.TextFormat;
namespace TerminalUI.Examples.Controls; namespace TerminalUI.Examples.Controls;
public class ProgressBarExamples public class ProgressBarExamples(IApplicationContext applicationContext)
{ {
private readonly IApplicationContext _applicationContext;
private static readonly IConsoleDriver _driver; private static readonly IConsoleDriver _driver;
static ProgressBarExamples() static ProgressBarExamples()
@@ -16,11 +15,6 @@ public class ProgressBarExamples
_driver.Init(); _driver.Init();
} }
public ProgressBarExamples(IApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public void LoadingExample() public void LoadingExample()
{ {
var progressBar = CreateProgressBar<object>(0); var progressBar = CreateProgressBar<object>(0);
@@ -46,7 +40,7 @@ public class ProgressBarExamples
{ {
Value = percent, Value = percent,
Attached = true, Attached = true,
ApplicationContext = _applicationContext ApplicationContext = applicationContext
}; };
private void RenderProgressBar<T>(ProgressBar<T> progressBar, Position position) private void RenderProgressBar<T>(ProgressBar<T> progressBar, Position position)

View File

@@ -6,13 +6,7 @@ namespace TerminalUI.Tests.Models;
public sealed partial class TestViewModel : INotifyPropertyChanged public sealed partial class TestViewModel : INotifyPropertyChanged
{ {
[Notify] private List<TestNestedCollectionItem> _items; [Notify] private List<TestNestedCollectionItem> _items = new()
[Notify] private string _text;
public TestViewModel()
{
_text = "Initial text";
_items = new List<TestNestedCollectionItem>
{ {
TestNestedCollectionItem.Create( TestNestedCollectionItem.Create(
3, 3,
@@ -23,7 +17,7 @@ public sealed partial class TestViewModel : INotifyPropertyChanged
new() new()
) )
}; };
} [Notify] private string _text = "Initial text";
public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;

View File

@@ -5,12 +5,12 @@ using TerminalUI.Styling;
namespace TerminalUI; namespace TerminalUI;
public class ApplicationContext : IApplicationContext public class ApplicationContext(IServiceProvider serviceProvider) : IApplicationContext
{ {
private readonly Lazy<IConsoleDriver> _consoleDriver; private readonly Lazy<IConsoleDriver> _consoleDriver = new Lazy<IConsoleDriver>(serviceProvider.GetRequiredService<IConsoleDriver>);
private readonly Lazy<IFocusManager> _focusManager; private readonly Lazy<IFocusManager> _focusManager = new Lazy<IFocusManager>(serviceProvider.GetRequiredService<IFocusManager>);
private readonly Lazy<ILoggerFactory?> _loggerFactory; private readonly Lazy<ILoggerFactory?> _loggerFactory = new Lazy<ILoggerFactory?>(serviceProvider.GetService<ILoggerFactory?>);
private readonly Lazy<IRenderEngine> _renderEngine; private readonly Lazy<IRenderEngine> _renderEngine = new Lazy<IRenderEngine>(serviceProvider.GetRequiredService<IRenderEngine>);
public IConsoleDriver ConsoleDriver => _consoleDriver.Value; public IConsoleDriver ConsoleDriver => _consoleDriver.Value;
public IFocusManager FocusManager => _focusManager.Value; public IFocusManager FocusManager => _focusManager.Value;
@@ -20,12 +20,4 @@ public class ApplicationContext : IApplicationContext
public bool IsRunning { get; set; } public bool IsRunning { get; set; }
public char EmptyCharacter { get; init; } = ' '; public char EmptyCharacter { get; init; } = ' ';
public bool SupportUtf8Output { get; set; } = true; public bool SupportUtf8Output { get; set; } = true;
public ApplicationContext(IServiceProvider serviceProvider)
{
_consoleDriver = new Lazy<IConsoleDriver>(serviceProvider.GetRequiredService<IConsoleDriver>);
_focusManager = new Lazy<IFocusManager>(serviceProvider.GetRequiredService<IFocusManager>);
_loggerFactory = new Lazy<ILoggerFactory?>(serviceProvider.GetService<ILoggerFactory?>);
_renderEngine = new Lazy<IRenderEngine>(serviceProvider.GetRequiredService<IRenderEngine>);
}
} }

View File

@@ -7,31 +7,24 @@ namespace TerminalUI.Controls;
public record ChildWithDataContextMapper<TSourceDataContext, TTargetDataContext>(IView<TTargetDataContext> Child, Func<TSourceDataContext?, TTargetDataContext?> DataContextMapper); public record ChildWithDataContextMapper<TSourceDataContext, TTargetDataContext>(IView<TTargetDataContext> Child, Func<TSourceDataContext?, TTargetDataContext?> DataContextMapper);
public record ChildWithDataContextBinding<TSourceDataContext, TTargetDataContext>(IView<TTargetDataContext> Child, Expression<Func<TSourceDataContext?, TTargetDataContext?>> DataContextExpression); public record ChildWithDataContextBinding<TSourceDataContext, TTargetDataContext>(IView<TTargetDataContext> Child, Expression<Func<TSourceDataContext?, TTargetDataContext?>> DataContextExpression);
public class ChildInitializer<T> : IEnumerable<IView> public class ChildInitializer<T>(IChildContainer<T> childContainer) : IEnumerable<IView>
{ {
private readonly IChildContainer<T> _childContainer; public void Add(IView<T> item) => childContainer.AddChild(item);
public ChildInitializer(IChildContainer<T> childContainer)
{
_childContainer = childContainer;
}
public void Add(IView<T> item) => _childContainer.AddChild(item);
public void Add<TDataContext>(ChildWithDataContextMapper<T, TDataContext> item) public void Add<TDataContext>(ChildWithDataContextMapper<T, TDataContext> item)
=> _childContainer.AddChild(item.Child, item.DataContextMapper); => childContainer.AddChild(item.Child, item.DataContextMapper);
public void Add<TDataContext>(ChildWithDataContextBinding<T, TDataContext> item) public void Add<TDataContext>(ChildWithDataContextBinding<T, TDataContext> item)
{ {
item.Child.Bind( item.Child.Bind(
_childContainer, childContainer,
item.DataContextExpression, item.DataContextExpression,
c => c.DataContext c => c.DataContext
); );
_childContainer.AddChild(item.Child); childContainer.AddChild(item.Child);
} }
public IEnumerator<IView> GetEnumerator() => _childContainer.Children.GetEnumerator(); public IEnumerator<IView> GetEnumerator() => childContainer.Children.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
} }

View File

@@ -2,37 +2,30 @@
namespace TerminalUI; namespace TerminalUI;
public class EventLoop : IEventLoop public class EventLoop(IApplicationContext applicationContext,
ILogger<EventLoop> logger)
: IEventLoop
{ {
private readonly IApplicationContext _applicationContext; private readonly ILogger<EventLoop> _logger = logger;
private readonly ILogger<EventLoop> _logger;
private readonly List<Action> _initializers = new(); private readonly List<Action> _initializers = new();
private readonly List<Action> _permanentQueue = new(); private readonly List<Action> _permanentQueue = new();
private readonly List<Action> _finalizers = new(); private readonly List<Action> _finalizers = new();
public int ThreadId { get; set; } = -1; public int ThreadId { get; set; } = -1;
public EventLoop(
IApplicationContext applicationContext,
ILogger<EventLoop> logger)
{
_applicationContext = applicationContext;
_logger = logger;
}
public void AddToPermanentQueue(Action action) => _permanentQueue.Add(action); public void AddToPermanentQueue(Action action) => _permanentQueue.Add(action);
public void AddInitializer(Action action) => _initializers.Add(action); public void AddInitializer(Action action) => _initializers.Add(action);
public void AddFinalizer(Action action) => _finalizers.Add(action); public void AddFinalizer(Action action) => _finalizers.Add(action);
public void Run() public void Run()
{ {
_applicationContext.IsRunning = true; applicationContext.IsRunning = true;
ThreadId = Thread.CurrentThread.ManagedThreadId; ThreadId = Thread.CurrentThread.ManagedThreadId;
foreach (var initializer in _initializers) foreach (var initializer in _initializers)
{ {
initializer(); initializer();
} }
while (_applicationContext.IsRunning) while (applicationContext.IsRunning)
{ {
ProcessQueues(); ProcessQueues();
Thread.Sleep(10); Thread.Sleep(10);

View File

@@ -5,9 +5,8 @@ using TerminalUI.Traits;
namespace TerminalUI; namespace TerminalUI;
public class FocusManager : IFocusManager public class FocusManager(IRenderEngine renderEngine) : IFocusManager
{ {
private readonly IRenderEngine _renderEngine;
private IFocusable? _focused; private IFocusable? _focused;
private DateTime _focusLostCandidateTime = DateTime.MinValue; private DateTime _focusLostCandidateTime = DateTime.MinValue;
@@ -52,11 +51,6 @@ public class FocusManager : IFocusManager
private set => _focused = value; private set => _focused = value;
} }
public FocusManager(IRenderEngine renderEngine)
{
_renderEngine = renderEngine;
}
public void SetFocus(IFocusable focusable) => Focused = focusable; public void SetFocus(IFocusable focusable) => Focused = focusable;
public void UnFocus(IFocusable focusable) public void UnFocus(IFocusable focusable)
@@ -127,8 +121,8 @@ public class FocusManager : IFocusManager
if (element is null) return; if (element is null) return;
_renderEngine.RequestRerender(element); renderEngine.RequestRerender(element);
_renderEngine.RequestRerender(view); renderEngine.RequestRerender(view);
Focused = element; Focused = element;
} }

View File

@@ -1,13 +1,7 @@
namespace TerminalUI.Models; namespace TerminalUI.Models;
public readonly ref struct Option<T> public readonly ref struct Option<T>(T value, bool isSome)
{ {
public readonly T Value; public readonly T Value = value;
public readonly bool IsSome; public readonly bool IsSome = isSome;
public Option(T value, bool isSome)
{
Value = value;
IsSome = isSome;
}
} }

View File

@@ -1,20 +1,12 @@
namespace TerminalUI.Models; namespace TerminalUI.Models;
public readonly struct SelectiveChar public readonly struct SelectiveChar(char utf8Char, char asciiChar)
{ {
public readonly char Utf8Char; public readonly char Utf8Char = utf8Char;
public readonly char AsciiChar; public readonly char AsciiChar = asciiChar;
public SelectiveChar(char c) public SelectiveChar(char c) : this(c, c)
{ {
Utf8Char = c;
AsciiChar = c;
}
public SelectiveChar(char utf8Char, char asciiChar)
{
Utf8Char = utf8Char;
AsciiChar = asciiChar;
} }
public char GetChar(bool enableUtf8) => enableUtf8 ? Utf8Char : AsciiChar; public char GetChar(bool enableUtf8) => enableUtf8 ? Utf8Char : AsciiChar;

View File

@@ -1,11 +1,6 @@
namespace TerminalUI.TextFormat; namespace TerminalUI.TextFormat;
public readonly struct TextFormatContext public readonly struct TextFormatContext(bool supportsAnsi)
{ {
public readonly bool SupportsAnsi; public readonly bool SupportsAnsi = supportsAnsi;
public TextFormatContext(bool supportsAnsi)
{
SupportsAnsi = supportsAnsi;
}
} }

View File

@@ -6,29 +6,15 @@ using Microsoft.Extensions.Options;
namespace FileTime.Server.Web; namespace FileTime.Server.Web;
public class PortWriterService : IHostedService public class PortWriterService(IServer server,
{
private readonly IServer _server;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly IOptions<PortWriterConfiguration> _configuration;
private readonly ILogger<PortWriterService> _logger;
public PortWriterService(
IServer server,
IHostApplicationLifetime hostApplicationLifetime, IHostApplicationLifetime hostApplicationLifetime,
IOptions<PortWriterConfiguration> configuration, IOptions<PortWriterConfiguration> configuration,
ILogger<PortWriterService> logger) ILogger<PortWriterService> logger)
{ : IHostedService
_server = server; {
_hostApplicationLifetime = hostApplicationLifetime;
_configuration = configuration;
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken) public Task StartAsync(CancellationToken cancellationToken)
{ {
_hostApplicationLifetime.ApplicationStarted.Register(WritePort); hostApplicationLifetime.ApplicationStarted.Register(WritePort);
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -37,28 +23,28 @@ public class PortWriterService : IHostedService
{ {
try try
{ {
var filename = _configuration.Value.Filename; var filename = configuration.Value.Filename;
if (filename is null) if (filename is null)
{ {
_logger.LogWarning("Could not save port to file as there were no file name given"); logger.LogWarning("Could not save port to file as there were no file name given");
return; return;
} }
var address = GetAddress(); var address = GetAddress();
if (address is null) if (address is null)
{ {
_logger.LogError("Could not get address"); logger.LogError("Could not get address");
return; return;
} }
var couldParsePort = int.TryParse(address.Split(':').LastOrDefault(), out var port); var couldParsePort = int.TryParse(address.Split(':').LastOrDefault(), out var port);
if (!couldParsePort) if (!couldParsePort)
{ {
_logger.LogError("Could not parse port from address {Address}", address); logger.LogError("Could not parse port from address {Address}", address);
return; return;
} }
_logger.LogInformation("Writing port to {PortFile}", filename); logger.LogInformation("Writing port to {PortFile}", filename);
using var tempFileStream = File.CreateText(filename); using var tempFileStream = File.CreateText(filename);
tempFileStream.Write(port.ToString()); tempFileStream.Write(port.ToString());
@@ -67,24 +53,24 @@ public class PortWriterService : IHostedService
await Task.Delay(5000); await Task.Delay(5000);
try try
{ {
_logger.LogInformation("Deleting port file {PortFile}", filename); logger.LogInformation("Deleting port file {PortFile}", filename);
File.Delete(filename); File.Delete(filename);
} }
catch (Exception e) catch (Exception e)
{ {
_logger.LogError(e, "Error while deleting port file {PortFile}", filename); logger.LogError(e, "Error while deleting port file {PortFile}", filename);
} }
}); });
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Could not save port to file"); logger.LogError(ex, "Could not save port to file");
} }
} }
private string? GetAddress() private string? GetAddress()
{ {
var features = _server.Features; var features = server.Features;
var addresses = features.Get<IServerAddressesFeature>(); var addresses = features.Get<IServerAddressesFeature>();
var address = addresses?.Addresses.FirstOrDefault(); var address = addresses?.Addresses.FirstOrDefault();
return address; return address;

View File

@@ -5,37 +5,26 @@ using SharpCompress.Common;
namespace FileTime.Tools.Compression; namespace FileTime.Tools.Compression;
public class CompressOperation<TEntry, TVolume> : ICompressOperation public class CompressOperation<TEntry, TVolume>(IContentAccessorFactory contentAccessorFactory,
AbstractWritableArchive<TEntry, TVolume> archive,
Action<Stream> saveTo)
: ICompressOperation
where TEntry : IArchiveEntry where TEntry : IArchiveEntry
where TVolume : IVolume where TVolume : IVolume
{ {
private readonly IContentAccessorFactory _contentAccessorFactory;
private readonly AbstractWritableArchive<TEntry, TVolume> _archive;
private readonly Action<Stream> _saveTo;
private bool _disposed; private bool _disposed;
public CompressOperation(
IContentAccessorFactory contentAccessorFactory,
AbstractWritableArchive<TEntry, TVolume> archive,
Action<Stream> saveTo
)
{
_contentAccessorFactory = contentAccessorFactory;
_archive = archive;
_saveTo = saveTo;
}
public async Task<IEnumerable<IDisposable>> CompressElement(IElement element, string key) public async Task<IEnumerable<IDisposable>> CompressElement(IElement element, string key)
{ {
var contentReader = await _contentAccessorFactory.GetContentReaderFactory(element.Provider).CreateContentReaderAsync(element); var contentReader = await contentAccessorFactory.GetContentReaderFactory(element.Provider).CreateContentReaderAsync(element);
var contentReaderStream = contentReader.GetStream(); var contentReaderStream = contentReader.GetStream();
_archive.AddEntry(key, contentReaderStream); archive.AddEntry(key, contentReaderStream);
return new IDisposable[] {contentReader, contentReaderStream}; return new IDisposable[] {contentReader, contentReaderStream};
} }
public void SaveTo(Stream stream) public void SaveTo(Stream stream)
=> _saveTo(stream); => saveTo(stream);
~CompressOperation() ~CompressOperation()
{ {
@@ -54,7 +43,7 @@ public class CompressOperation<TEntry, TVolume> : ICompressOperation
{ {
if (disposing) if (disposing)
{ {
_archive.Dispose(); archive.Dispose();
} }
} }

View File

@@ -6,31 +6,18 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.Compression.Compress; namespace FileTime.Tools.Compression.Compress;
public class CompressCommandFactory : ITransportationCommandFactory<CompressCommand> public class CompressCommandFactory(IUserCommunicationService userCommunicationService,
{
private readonly IUserCommunicationService _userCommunicationService;
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IContentAccessorFactory _contentAccessorFactory;
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
public CompressCommandFactory(
IUserCommunicationService userCommunicationService,
ITimelessContentProvider timelessContentProvider, ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory, IContentAccessorFactory contentAccessorFactory,
ICommandSchedulerNotifier commandSchedulerNotifier) ICommandSchedulerNotifier commandSchedulerNotifier)
{ : ITransportationCommandFactory<CompressCommand>
_userCommunicationService = userCommunicationService; {
_timelessContentProvider = timelessContentProvider;
_contentAccessorFactory = contentAccessorFactory;
_commandSchedulerNotifier = commandSchedulerNotifier;
}
public CompressCommand GenerateCommand(IReadOnlyCollection<FullName> sources, TransportMode mode, FullName targetFullName) public CompressCommand GenerateCommand(IReadOnlyCollection<FullName> sources, TransportMode mode, FullName targetFullName)
=> new( => new(
_userCommunicationService, userCommunicationService,
_timelessContentProvider, timelessContentProvider,
_contentAccessorFactory, contentAccessorFactory,
_commandSchedulerNotifier, commandSchedulerNotifier,
sources, sources,
mode, mode,
targetFullName targetFullName

View File

@@ -5,24 +5,14 @@ using SharpCompress.Archives;
namespace FileTime.Tools.Compression.ContentProvider; namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedContentProvider : SubContentProviderBase, ICompressedContentProvider public sealed class CompressedContentProvider(ITimelessContentProvider timelessContentProvider,
{
private readonly ITimelessContentProvider _timelessContentProvider;
public CompressedContentProvider(
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory, IContentAccessorFactory contentAccessorFactory,
IContentProvider parentContentProvider IContentProvider parentContentProvider)
) : SubContentProviderBase(timelessContentProvider,
: base(
timelessContentProvider,
contentAccessorFactory, contentAccessorFactory,
parentContentProvider, parentContentProvider,
"compression") "compression"), ICompressedContentProvider
{ {
_timelessContentProvider = timelessContentProvider;
}
public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default) public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default)
{ {
var parentElementContext = await GetParentElementReaderAsync(element); var parentElementContext = await GetParentElementReaderAsync(element);
@@ -43,7 +33,7 @@ public sealed class CompressedContentProvider : SubContentProviderBase, ICompres
public override async ValueTask<VolumeSizeInfo?> GetVolumeSizeInfoAsync(FullName path) public override async ValueTask<VolumeSizeInfo?> GetVolumeSizeInfoAsync(FullName path)
{ {
var item = await GetItemByFullNameAsync(path, _timelessContentProvider.CurrentPointInTime.Value!); var item = await GetItemByFullNameAsync(path, timelessContentProvider.CurrentPointInTime.Value!);
var parentElement = await GetParentElementAsync(item); var parentElement = await GetParentElementAsync(item);
return new VolumeSizeInfo(parentElement.Size, 0); return new VolumeSizeInfo(parentElement.Size, 0);
} }

View File

@@ -3,19 +3,10 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.Compression.ContentProvider; namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedContentProviderFactory : ICompressedContentProviderFactory public sealed class CompressedContentProviderFactory(ITimelessContentProvider timelessContentProvider,
{
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IContentAccessorFactory _contentAccessorFactory;
public CompressedContentProviderFactory(
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory) IContentAccessorFactory contentAccessorFactory)
{ : ICompressedContentProviderFactory
_timelessContentProvider = timelessContentProvider; {
_contentAccessorFactory = contentAccessorFactory;
}
public ICompressedContentProvider Create(IContentProvider parentContentProvider) public ICompressedContentProvider Create(IContentProvider parentContentProvider)
=> new CompressedContentProvider(_timelessContentProvider, _contentAccessorFactory, parentContentProvider); => new CompressedContentProvider(timelessContentProvider, contentAccessorFactory, parentContentProvider);
} }

View File

@@ -3,21 +3,14 @@ using SharpCompress.Archives;
namespace FileTime.Tools.Compression.ContentProvider; namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedContentReader : IContentReader public sealed class CompressedContentReader(IArchiveEntry entry, IDisposable[] disposables) : IContentReader
{ {
private readonly IDisposable[] _disposables; private readonly Stream _stream = entry.OpenEntryStream();
private readonly Stream _stream;
public CompressedContentReader(IArchiveEntry entry, IDisposable[] disposables)
{
_disposables = disposables;
_stream = entry.OpenEntryStream();
}
public void Dispose() public void Dispose()
{ {
_stream.Dispose(); _stream.Dispose();
foreach (var disposable in _disposables) foreach (var disposable in disposables)
{ {
disposable.Dispose(); disposable.Dispose();
} }

View File

@@ -4,13 +4,8 @@ using SharpCompress.Archives;
namespace FileTime.Tools.Compression.ContentProvider; namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedContentReaderFactory : SubContentReaderBase<CompressedContentProvider> public sealed class CompressedContentReaderFactory(IContentAccessorFactory contentAccessorFactory) : SubContentReaderBase<CompressedContentProvider>(contentAccessorFactory)
{ {
public CompressedContentReaderFactory(IContentAccessorFactory contentAccessorFactory)
: base(contentAccessorFactory)
{
}
public override async Task<IContentReader> CreateContentReaderAsync(IElement element) public override async Task<IContentReader> CreateContentReaderAsync(IElement element)
{ {
if (element.Provider is not CompressedContentProvider provider) if (element.Provider is not CompressedContentProvider provider)

View File

@@ -8,25 +8,13 @@ using IContainer = FileTime.Core.Models.IContainer;
namespace FileTime.Tools.Compression.ContentProvider; namespace FileTime.Tools.Compression.ContentProvider;
public sealed class CompressedSubContentProvider : ICompressedSubContentProvider public sealed class CompressedSubContentProvider(IContentAccessorFactory contentAccessorFactory,
ICompressedContentProviderFactory compressedContentProviderFactory,
ITimelessContentProvider timelessContentProvider)
: ICompressedSubContentProvider
{ {
private static readonly string[] SupportedExtensions = {".zip", ".gz", ".7z"}; private static readonly string[] SupportedExtensions = {".zip", ".gz", ".7z"};
private readonly IContentAccessorFactory _contentAccessorFactory;
private readonly ICompressedContentProviderFactory _compressedContentProviderFactory;
private readonly ITimelessContentProvider _timelessContentProvider;
public CompressedSubContentProvider(
IContentAccessorFactory contentAccessorFactory,
ICompressedContentProviderFactory compressedContentProviderFactory,
ITimelessContentProvider timelessContentProvider
)
{
_contentAccessorFactory = contentAccessorFactory;
_compressedContentProviderFactory = compressedContentProviderFactory;
_timelessContentProvider = timelessContentProvider;
}
public Task<bool> CanHandleAsync(IElement parentElement) public Task<bool> CanHandleAsync(IElement parentElement)
=> Task.FromResult( => Task.FromResult(
parentElement.NativePath?.Path is { } path parentElement.NativePath?.Path is { } path
@@ -40,7 +28,7 @@ public sealed class CompressedSubContentProvider : ICompressedSubContentProvider
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default) ItemInitializationSettings itemInitializationSettings = default)
{ {
var parentContentReader = await _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider).CreateContentReaderAsync(parentElement); var parentContentReader = await contentAccessorFactory.GetContentReaderFactory(parentElement.Provider).CreateContentReaderAsync(parentElement);
var parentContentReaderStream = parentContentReader.GetStream(); var parentContentReaderStream = parentContentReader.GetStream();
var archive = ArchiveFactory.Open(parentContentReaderStream); var archive = ArchiveFactory.Open(parentContentReaderStream);
var disposables = new IDisposable[] {parentContentReader, parentContentReaderStream, archive}; var disposables = new IDisposable[] {parentContentReader, parentContentReaderStream, archive};
@@ -117,7 +105,7 @@ public sealed class CompressedSubContentProvider : ICompressedSubContentProvider
} }
var parent = new AbsolutePath( var parent = new AbsolutePath(
_timelessContentProvider, timelessContentProvider,
parentElement.PointInTime, parentElement.PointInTime,
childFullName.GetParent()!, childFullName.GetParent()!,
AbsolutePathType.Container AbsolutePathType.Container
@@ -183,7 +171,7 @@ public sealed class CompressedSubContentProvider : ICompressedSubContentProvider
SupportsDelete.False, SupportsDelete.False,
false, false,
"", "",
_compressedContentProviderFactory.Create(parentElement.Provider), compressedContentProviderFactory.Create(parentElement.Provider),
false, false,
parentElement.PointInTime, parentElement.PointInTime,
exceptions, exceptions,
@@ -246,7 +234,7 @@ public sealed class CompressedSubContentProvider : ICompressedSubContentProvider
addedContainers.Add(itemName); addedContainers.Add(itemName);
children.Add(new AbsolutePath( children.Add(new AbsolutePath(
_timelessContentProvider, timelessContentProvider,
pointInTime, pointInTime,
container.FullName.GetChild(itemName), container.FullName.GetChild(itemName),
AbsolutePathType.Container) AbsolutePathType.Container)
@@ -256,7 +244,7 @@ public sealed class CompressedSubContentProvider : ICompressedSubContentProvider
{ {
//Element //Element
children.Add(new AbsolutePath( children.Add(new AbsolutePath(
_timelessContentProvider, timelessContentProvider,
pointInTime, pointInTime,
container.FullName.GetChild(itemName), container.FullName.GetChild(itemName),
AbsolutePathType.Element) AbsolutePathType.Element)
@@ -290,7 +278,7 @@ public sealed class CompressedSubContentProvider : ICompressedSubContentProvider
false, false,
"", "",
size, size,
_compressedContentProviderFactory.Create(parentElement.Provider), compressedContentProviderFactory.Create(parentElement.Provider),
parentElement.PointInTime, parentElement.PointInTime,
exceptions, exceptions,
new ReadOnlyExtensionCollection(new ExtensionCollection()) new ReadOnlyExtensionCollection(new ExtensionCollection())

View File

@@ -5,27 +5,16 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.Compression.Decompress; namespace FileTime.Tools.Compression.Decompress;
public class DecompressCommandFactory : ITransportationCommandFactory<DecompressCommand> public class DecompressCommandFactory(ITimelessContentProvider timelessContentProvider,
{
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IContentAccessorFactory _contentAccessorFactory;
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
public DecompressCommandFactory(
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory, IContentAccessorFactory contentAccessorFactory,
ICommandSchedulerNotifier commandSchedulerNotifier) ICommandSchedulerNotifier commandSchedulerNotifier)
{ : ITransportationCommandFactory<DecompressCommand>
_timelessContentProvider = timelessContentProvider; {
_contentAccessorFactory = contentAccessorFactory;
_commandSchedulerNotifier = commandSchedulerNotifier;
}
public DecompressCommand GenerateCommand(IReadOnlyCollection<FullName> sources, TransportMode mode, FullName targetFullName) public DecompressCommand GenerateCommand(IReadOnlyCollection<FullName> sources, TransportMode mode, FullName targetFullName)
=> new( => new(
_timelessContentProvider, timelessContentProvider,
_contentAccessorFactory, contentAccessorFactory,
_commandSchedulerNotifier, commandSchedulerNotifier,
sources, sources,
mode, mode,
targetFullName); targetFullName);

View File

@@ -5,24 +5,14 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.VirtualDiskSources; namespace FileTime.Tools.VirtualDiskSources;
public sealed class VirtualDiskContentProvider : SubContentProviderBase, IVirtualDiskContentProvider public sealed class VirtualDiskContentProvider(ITimelessContentProvider timelessContentProvider,
{
private readonly ITimelessContentProvider _timelessContentProvider;
public VirtualDiskContentProvider(
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory, IContentAccessorFactory contentAccessorFactory,
IContentProvider parentContentProvider) IContentProvider parentContentProvider)
: base( : SubContentProviderBase(timelessContentProvider,
timelessContentProvider,
contentAccessorFactory, contentAccessorFactory,
parentContentProvider, parentContentProvider,
"virtual-disk" "virtual-disk"), IVirtualDiskContentProvider
) {
{
_timelessContentProvider = timelessContentProvider;
}
public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default) public override async Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default)
{ {
var parentElementContext = await GetParentElementReaderAsync(element); var parentElementContext = await GetParentElementReaderAsync(element);
@@ -44,7 +34,7 @@ public sealed class VirtualDiskContentProvider : SubContentProviderBase, IVirtua
public override async ValueTask<VolumeSizeInfo?> GetVolumeSizeInfoAsync(FullName path) public override async ValueTask<VolumeSizeInfo?> GetVolumeSizeInfoAsync(FullName path)
{ {
var item = await GetItemByFullNameAsync(path, _timelessContentProvider.CurrentPointInTime.Value!); var item = await GetItemByFullNameAsync(path, timelessContentProvider.CurrentPointInTime.Value!);
var parentElement = await GetParentElementAsync(item); var parentElement = await GetParentElementAsync(item);
return new VolumeSizeInfo(parentElement.Size, 0); return new VolumeSizeInfo(parentElement.Size, 0);
} }

View File

@@ -3,19 +3,10 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.VirtualDiskSources; namespace FileTime.Tools.VirtualDiskSources;
public sealed class VirtualDiskContentProviderFactory : IVirtualDiskContentProviderFactory public sealed class VirtualDiskContentProviderFactory(ITimelessContentProvider timelessContentProvider,
{
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IContentAccessorFactory _contentAccessorFactory;
public VirtualDiskContentProviderFactory(
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory) IContentAccessorFactory contentAccessorFactory)
{ : IVirtualDiskContentProviderFactory
_timelessContentProvider = timelessContentProvider; {
_contentAccessorFactory = contentAccessorFactory;
}
public IVirtualDiskContentProvider Create(IContentProvider parentContentProvider) public IVirtualDiskContentProvider Create(IContentProvider parentContentProvider)
=> new VirtualDiskContentProvider(_timelessContentProvider, _contentAccessorFactory, parentContentProvider); => new VirtualDiskContentProvider(timelessContentProvider, contentAccessorFactory, parentContentProvider);
} }

View File

@@ -2,23 +2,14 @@
namespace FileTime.Tools.VirtualDiskSources; namespace FileTime.Tools.VirtualDiskSources;
public sealed class VirtualDiskContentReader : IContentReader public sealed class VirtualDiskContentReader(Stream stream, ICollection<IDisposable> disposables) : IContentReader
{ {
private readonly Stream _stream; public Stream GetStream() => stream;
private readonly ICollection<IDisposable> _disposables;
public VirtualDiskContentReader(Stream stream, ICollection<IDisposable> disposables)
{
_stream = stream;
_disposables = disposables;
}
public Stream GetStream() => _stream;
public void Dispose() public void Dispose()
{ {
_stream.Dispose(); stream.Dispose();
foreach (var disposable in _disposables) foreach (var disposable in disposables)
{ {
disposable.Dispose(); disposable.Dispose();
} }

View File

@@ -4,13 +4,8 @@ using FileTime.Core.Models;
namespace FileTime.Tools.VirtualDiskSources; namespace FileTime.Tools.VirtualDiskSources;
public sealed class VirtualDiskContentReaderFactory : SubContentReaderBase<VirtualDiskContentProvider> public sealed class VirtualDiskContentReaderFactory(IContentAccessorFactory contentAccessorFactory) : SubContentReaderBase<VirtualDiskContentProvider>(contentAccessorFactory)
{ {
public VirtualDiskContentReaderFactory(IContentAccessorFactory contentAccessorFactory)
: base(contentAccessorFactory)
{
}
public override async Task<IContentReader> CreateContentReaderAsync(IElement element) public override async Task<IContentReader> CreateContentReaderAsync(IElement element)
{ {
if (element.Provider is not VirtualDiskContentProvider provider) if (element.Provider is not VirtualDiskContentProvider provider)

View File

@@ -8,23 +8,11 @@ using FileTime.Core.Timeline;
namespace FileTime.Tools.VirtualDiskSources; namespace FileTime.Tools.VirtualDiskSources;
public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvider public sealed class VirtualDiskSubContentProvider(IContentAccessorFactory contentAccessorFactory,
{
private readonly IContentAccessorFactory _contentAccessorFactory;
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly IVirtualDiskContentProviderFactory _virtualDiskContentProviderFactory;
public VirtualDiskSubContentProvider(
IContentAccessorFactory contentAccessorFactory,
ITimelessContentProvider timelessContentProvider, ITimelessContentProvider timelessContentProvider,
IVirtualDiskContentProviderFactory virtualDiskContentProviderFactory IVirtualDiskContentProviderFactory virtualDiskContentProviderFactory)
) : IVirtualDiskSubContentProvider
{ {
_contentAccessorFactory = contentAccessorFactory;
_timelessContentProvider = timelessContentProvider;
_virtualDiskContentProviderFactory = virtualDiskContentProviderFactory;
}
public Task<bool> CanHandleAsync(IElement parentElement) public Task<bool> CanHandleAsync(IElement parentElement)
=> Task.FromResult(parentElement.NativePath?.Path.EndsWith(".iso", StringComparison.OrdinalIgnoreCase) ?? false); => Task.FromResult(parentElement.NativePath?.Path.EndsWith(".iso", StringComparison.OrdinalIgnoreCase) ?? false);
@@ -35,7 +23,7 @@ public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvid
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default) ItemInitializationSettings itemInitializationSettings = default)
{ {
var contentReaderFactory = _contentAccessorFactory.GetContentReaderFactory(parentElement.Provider); var contentReaderFactory = contentAccessorFactory.GetContentReaderFactory(parentElement.Provider);
var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement); var reader = await contentReaderFactory.CreateContentReaderAsync(parentElement);
await using var readerStream = reader.GetStream(); await using var readerStream = reader.GetStream();
@@ -80,7 +68,7 @@ public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvid
var childNativePath = new NativePath(childNativePathBase); var childNativePath = new NativePath(childNativePathBase);
var parent = new AbsolutePath( var parent = new AbsolutePath(
_timelessContentProvider, timelessContentProvider,
pointInTime, pointInTime,
childFullName.GetParent()!, childFullName.GetParent()!,
AbsolutePathType.Container AbsolutePathType.Container
@@ -152,7 +140,7 @@ public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvid
SupportsDelete.False, SupportsDelete.False,
false, false,
FormatAttributes(sourceContainer.Attributes), FormatAttributes(sourceContainer.Attributes),
_virtualDiskContentProviderFactory.Create(parentContentProvider), virtualDiskContentProviderFactory.Create(parentContentProvider),
false, false,
pointInTime, pointInTime,
exceptions, exceptions,
@@ -191,7 +179,7 @@ public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvid
foreach (var discDirectoryInfo in sourceContainer.GetDirectories()) foreach (var discDirectoryInfo in sourceContainer.GetDirectories())
{ {
children.Add(new AbsolutePath( children.Add(new AbsolutePath(
_timelessContentProvider, timelessContentProvider,
pointInTime, pointInTime,
container.FullName.GetChild(discDirectoryInfo.Name), container.FullName.GetChild(discDirectoryInfo.Name),
AbsolutePathType.Container) AbsolutePathType.Container)
@@ -201,7 +189,7 @@ public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvid
foreach (var fileInfo in sourceContainer.GetFiles()) foreach (var fileInfo in sourceContainer.GetFiles())
{ {
children.Add(new AbsolutePath( children.Add(new AbsolutePath(
_timelessContentProvider, timelessContentProvider,
pointInTime, pointInTime,
container.FullName.GetChild(fileInfo.Name), container.FullName.GetChild(fileInfo.Name),
AbsolutePathType.Element) AbsolutePathType.Element)
@@ -230,7 +218,7 @@ public sealed class VirtualDiskSubContentProvider : IVirtualDiskSubContentProvid
false, false,
FormatAttributes(childElement.Attributes), FormatAttributes(childElement.Attributes),
childElement.Length, childElement.Length,
_virtualDiskContentProviderFactory.Create(parentContentProvider), virtualDiskContentProviderFactory.Create(parentContentProvider),
pointInTime, pointInTime,
new ObservableCollection<Exception>(), new ObservableCollection<Exception>(),
new ReadOnlyExtensionCollection(new ExtensionCollection()) new ReadOnlyExtensionCollection(new ExtensionCollection())