Compression
This commit is contained in:
@@ -4,7 +4,7 @@ namespace FileTime.App.Core.Services;
|
|||||||
|
|
||||||
public interface IIdentifiableUserCommandService
|
public interface IIdentifiableUserCommandService
|
||||||
{
|
{
|
||||||
void AddIdentifiableUserCommandFactory(string identifier, IIdentifiableUserCommand commandFactory);
|
void AddIdentifiableUserCommand(IIdentifiableUserCommand command);
|
||||||
IIdentifiableUserCommand? GetCommand(string identifier);
|
IIdentifiableUserCommand? GetCommand(string identifier);
|
||||||
IReadOnlyCollection<string> GetCommandIdentifiers();
|
IReadOnlyCollection<string> GetCommandIdentifiers();
|
||||||
IReadOnlyDictionary<string, IIdentifiableUserCommand> IdentifiableUserCommands { get; }
|
IReadOnlyDictionary<string, IIdentifiableUserCommand> IdentifiableUserCommands { get; }
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||||
|
|
||||||
|
public abstract class AggregatedUserCommandHandler : IUserCommandHandler
|
||||||
|
{
|
||||||
|
private readonly List<IUserCommandHandler> _userCommandHandlers = new();
|
||||||
|
|
||||||
|
public bool CanHandleCommand(UserCommand.IUserCommand command) => _userCommandHandlers.Any(h => h.CanHandleCommand(command));
|
||||||
|
|
||||||
|
public async Task HandleCommandAsync(UserCommand.IUserCommand command)
|
||||||
|
{
|
||||||
|
var handler = _userCommandHandlers.Find(h => h.CanHandleCommand(command));
|
||||||
|
|
||||||
|
if (handler is null) return;
|
||||||
|
await handler.HandleCommandAsync(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AddCommandHandler(IUserCommandHandler userCommandHandler) => _userCommandHandlers.Add(userCommandHandler);
|
||||||
|
|
||||||
|
protected void AddCommandHandler(IEnumerable<IUserCommandHandler> commandHandlers)
|
||||||
|
{
|
||||||
|
foreach (var userCommandHandler in commandHandlers)
|
||||||
|
{
|
||||||
|
AddCommandHandler(userCommandHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ public class CommandSchedulerUserCommandHandlerService : UserCommandHandlerServi
|
|||||||
public CommandSchedulerUserCommandHandlerService(ICommandScheduler commandScheduler)
|
public CommandSchedulerUserCommandHandlerService(ICommandScheduler commandScheduler)
|
||||||
{
|
{
|
||||||
_commandScheduler = commandScheduler;
|
_commandScheduler = commandScheduler;
|
||||||
AddCommandHandlers(new IUserCommandHandler[]
|
AddCommandHandler(new IUserCommandHandler[]
|
||||||
{
|
{
|
||||||
new TypeUserCommandHandler<PauseCommandSchedulerCommand>(PauseCommandScheduler),
|
new TypeUserCommandHandler<PauseCommandSchedulerCommand>(PauseCommandScheduler),
|
||||||
new TypeUserCommandHandler<StartCommandSchedulerCommand>(StartCommandScheduler),
|
new TypeUserCommandHandler<StartCommandSchedulerCommand>(StartCommandScheduler),
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ public class IdentifiableUserCommandService : IIdentifiableUserCommandService
|
|||||||
IdentifiableUserCommands = _identifiableUserCommands.AsReadOnly();
|
IdentifiableUserCommands = _identifiableUserCommands.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddIdentifiableUserCommandFactory(string identifier, IIdentifiableUserCommand commandFactory)
|
public void AddIdentifiableUserCommand(IIdentifiableUserCommand command)
|
||||||
=> _identifiableUserCommands.Add(identifier, commandFactory);
|
=> _identifiableUserCommands.Add(command.UserCommandID, command);
|
||||||
|
|
||||||
public IIdentifiableUserCommand? GetCommand(string identifier)
|
public IIdentifiableUserCommand? GetCommand(string identifier)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
|
|||||||
|
|
||||||
_markedItems = appState.SelectedTab.Map(t => t?.MarkedItems).Switch();
|
_markedItems = appState.SelectedTab.Map(t => t?.MarkedItems).Switch();
|
||||||
|
|
||||||
AddCommandHandlers(new IUserCommandHandler[]
|
AddCommandHandler(new IUserCommandHandler[]
|
||||||
{
|
{
|
||||||
new TypeUserCommandHandler<CopyCommand>(CopyAsync),
|
new TypeUserCommandHandler<CopyCommand>(CopyAsync),
|
||||||
new TypeUserCommandHandler<DeleteCommand>(DeleteAsync),
|
new TypeUserCommandHandler<DeleteCommand>(DeleteAsync),
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
|
|
||||||
appState.ViewMode.Subscribe(v => _viewMode = v);
|
appState.ViewMode.Subscribe(v => _viewMode = v);
|
||||||
|
|
||||||
AddCommandHandlers(new IUserCommandHandler[]
|
AddCommandHandler(new IUserCommandHandler[]
|
||||||
{
|
{
|
||||||
new TypeUserCommandHandler<CloseTabCommand>(CloseTab),
|
new TypeUserCommandHandler<CloseTabCommand>(CloseTab),
|
||||||
new TypeUserCommandHandler<EnterRapidTravelCommand>(EnterRapidTravel),
|
new TypeUserCommandHandler<EnterRapidTravelCommand>(EnterRapidTravel),
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
SaveSelectedTab(t => _currentSelectedTab = t);
|
SaveSelectedTab(t => _currentSelectedTab = t);
|
||||||
|
|
||||||
AddCommandHandlers(new IUserCommandHandler[]
|
AddCommandHandler(new IUserCommandHandler[]
|
||||||
{
|
{
|
||||||
new TypeUserCommandHandler<OpenInDefaultFileExplorerCommand>(OpenInDefaultFileExplorer),
|
new TypeUserCommandHandler<OpenInDefaultFileExplorerCommand>(OpenInDefaultFileExplorer),
|
||||||
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
|
||||||
|
|
||||||
public sealed class UserCommandHandler : IUserCommandHandler
|
|
||||||
{
|
|
||||||
private readonly Func<UserCommand.IUserCommand, bool> _canHandle;
|
|
||||||
private readonly Func<UserCommand.IUserCommand, Task> _handle;
|
|
||||||
|
|
||||||
public UserCommandHandler(Func<UserCommand.IUserCommand, bool> canHandle, Func<UserCommand.IUserCommand, Task> handle)
|
|
||||||
{
|
|
||||||
_canHandle = canHandle;
|
|
||||||
_handle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanHandleCommand(UserCommand.IUserCommand command) => _canHandle(command);
|
|
||||||
public async Task HandleCommandAsync(UserCommand.IUserCommand command) => await _handle(command);
|
|
||||||
}
|
|
||||||
@@ -8,9 +8,8 @@ using FileTime.Core.Timeline;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||||
|
|
||||||
public abstract class UserCommandHandlerServiceBase : IUserCommandHandler
|
public abstract class UserCommandHandlerServiceBase : AggregatedUserCommandHandler
|
||||||
{
|
{
|
||||||
private readonly List<IUserCommandHandler> _userCommandHandlers = new();
|
|
||||||
private readonly IAppState? _appState;
|
private readonly IAppState? _appState;
|
||||||
private readonly ITimelessContentProvider? _timelessContentProvider;
|
private readonly ITimelessContentProvider? _timelessContentProvider;
|
||||||
|
|
||||||
@@ -22,28 +21,6 @@ public abstract class UserCommandHandlerServiceBase : IUserCommandHandler
|
|||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanHandleCommand(UserCommand.IUserCommand command) => _userCommandHandlers.Any(h => h.CanHandleCommand(command));
|
|
||||||
|
|
||||||
public async Task HandleCommandAsync(UserCommand.IUserCommand command)
|
|
||||||
{
|
|
||||||
var handler = _userCommandHandlers.Find(h => h.CanHandleCommand(command));
|
|
||||||
|
|
||||||
if (handler is null) return;
|
|
||||||
await handler.HandleCommandAsync(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void AddCommandHandler(IUserCommandHandler userCommandHandler) => _userCommandHandlers.Add(userCommandHandler);
|
|
||||||
|
|
||||||
protected void AddCommandHandlers(IEnumerable<IUserCommandHandler> commandHandlers)
|
|
||||||
{
|
|
||||||
foreach (var userCommandHandler in commandHandlers)
|
|
||||||
{
|
|
||||||
AddCommandHandler(userCommandHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void RemoveCommandHandler(IUserCommandHandler userCommandHandler) => _userCommandHandlers.Remove(userCommandHandler);
|
|
||||||
|
|
||||||
protected IDisposable SaveSelectedTab(Action<ITabViewModel?> handler) => RunWithAppState(appState => appState.SelectedTab.Subscribe(handler));
|
protected IDisposable SaveSelectedTab(Action<ITabViewModel?> handler) => RunWithAppState(appState => appState.SelectedTab.Subscribe(handler));
|
||||||
|
|
||||||
protected IDisposable SaveCurrentSelectedItem(Action<IDeclarativeProperty<IItemViewModel?>?> handler)
|
protected IDisposable SaveCurrentSelectedItem(Action<IDeclarativeProperty<IItemViewModel?>?> handler)
|
||||||
|
|||||||
@@ -69,5 +69,5 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
|||||||
public Task InitAsync() => Task.CompletedTask;
|
public Task InitAsync() => Task.CompletedTask;
|
||||||
|
|
||||||
private void AddUserCommand(IIdentifiableUserCommand command)
|
private void AddUserCommand(IIdentifiableUserCommand command)
|
||||||
=> _userCommandHandlerService.AddIdentifiableUserCommandFactory(command.UserCommandID, command);
|
=> _userCommandHandlerService.AddIdentifiableUserCommand(command);
|
||||||
}
|
}
|
||||||
@@ -7,4 +7,5 @@ public interface IContentReader : IDisposable
|
|||||||
|
|
||||||
Task<byte[]> ReadBytesAsync(int bufferSize, int? offset = null);
|
Task<byte[]> ReadBytesAsync(int bufferSize, int? offset = null);
|
||||||
void SetPosition(long position);
|
void SetPosition(long position);
|
||||||
|
Stream AsStream();
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,5 @@ public interface IContentWriter : IDisposable
|
|||||||
|
|
||||||
Task WriteBytesAsync(byte[] data, int? index = null, CancellationToken cancellationToken = default);
|
Task WriteBytesAsync(byte[] data, int? index = null, CancellationToken cancellationToken = default);
|
||||||
Task FlushAsync(CancellationToken cancellationToken = default);
|
Task FlushAsync(CancellationToken cancellationToken = default);
|
||||||
|
Stream AsStream();
|
||||||
}
|
}
|
||||||
@@ -3,5 +3,5 @@ namespace FileTime.Core.Interactions;
|
|||||||
public interface IOptionsInputElement : IInputElement
|
public interface IOptionsInputElement : IInputElement
|
||||||
{
|
{
|
||||||
object Value { get; set; }
|
object Value { get; set; }
|
||||||
IEnumerable<IOptionElement> Options { get; }
|
IReadOnlyCollection<IOptionElement> Options { get; }
|
||||||
}
|
}
|
||||||
@@ -5,19 +5,30 @@ namespace FileTime.Core.Interactions;
|
|||||||
|
|
||||||
public partial class OptionsInputElement<T> : InputElementBase, IOptionsInputElement, INotifyPropertyChanged
|
public partial class OptionsInputElement<T> : InputElementBase, IOptionsInputElement, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public IEnumerable<OptionElement<T>> Options { get; }
|
public IReadOnlyCollection<OptionElement<T>> Options { get; }
|
||||||
|
|
||||||
[Notify] private T? _value;
|
[Notify] private T? _value;
|
||||||
|
|
||||||
IEnumerable<IOptionElement> IOptionsInputElement.Options => Options;
|
IReadOnlyCollection<IOptionElement> IOptionsInputElement.Options => Options;
|
||||||
|
|
||||||
object? IOptionsInputElement.Value
|
object? IOptionsInputElement.Value
|
||||||
{
|
{
|
||||||
get => Value;
|
get => Options.FirstOrDefault(o => o.Value?.Equals(_value) ?? false);
|
||||||
set => Value = (T?)value;
|
set
|
||||||
|
{
|
||||||
|
if (value is T newValue)
|
||||||
|
{
|
||||||
|
Value = newValue;
|
||||||
|
}
|
||||||
|
else if (value is OptionElement<T> optionElement)
|
||||||
|
{
|
||||||
|
Value = optionElement.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OptionsInputElement(string label, IEnumerable<OptionElement<T>> options) : base(label, InputType.Options)
|
public OptionsInputElement(string label, IEnumerable<OptionElement<T>> options) : base(label, InputType.Options)
|
||||||
{
|
{
|
||||||
Options = options;
|
Options = options.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,11 +33,15 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
ICommandSchedulerNotifier commandSchedulerNotifier,
|
ICommandSchedulerNotifier commandSchedulerNotifier,
|
||||||
ILogger<CopyCommand> logger,
|
ILogger<CopyCommand> logger,
|
||||||
IReadOnlyCollection<FullName>? sources,
|
IReadOnlyCollection<FullName> sources,
|
||||||
TransportMode? mode,
|
TransportMode mode,
|
||||||
FullName? targetFullName)
|
FullName targetFullName)
|
||||||
: base("Copy - Calculating...")
|
: base("Copy - Calculating...")
|
||||||
{
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(sources);
|
||||||
|
ArgumentNullException.ThrowIfNull(mode);
|
||||||
|
ArgumentNullException.ThrowIfNull(targetFullName);
|
||||||
|
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_commandSchedulerNotifier = commandSchedulerNotifier;
|
_commandSchedulerNotifier = commandSchedulerNotifier;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@@ -54,12 +58,8 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
.Switch()
|
.Switch()
|
||||||
.Subscribe(SetCurrentProgress);
|
.Subscribe(SetCurrentProgress);
|
||||||
|
|
||||||
if (sources is null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
|
||||||
if (targetFullName is null) throw new ArgumentException(nameof(Target) + " can not be null");
|
|
||||||
if (mode is null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
|
||||||
|
|
||||||
Sources = new List<FullName>(sources).AsReadOnly();
|
Sources = new List<FullName>(sources).AsReadOnly();
|
||||||
TransportMode = mode.Value;
|
TransportMode = mode;
|
||||||
Target = targetFullName;
|
Target = targetFullName;
|
||||||
|
|
||||||
var recentSpeed = DeclarativePropertyHelpers.CombineLatest(
|
var recentSpeed = DeclarativePropertyHelpers.CombineLatest(
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Server.Common.Abst
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Server.Web", "Server\FileTime.Server.Web\FileTime.Server.Web.csproj", "{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Server.Web", "Server\FileTime.Server.Web\FileTime.Server.Web.csproj", "{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Tools.Compression", "Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj", "{58243F14-15A6-4601-A071-F99BE896D027}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Tools.Compression.Core", "Tools\FileTime.Tools.Compression.Core\FileTime.Tools.Compression.Core.csproj", "{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -285,6 +289,14 @@ Global
|
|||||||
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}.Release|Any CPU.Build.0 = Release|Any CPU
|
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{58243F14-15A6-4601-A071-F99BE896D027}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{58243F14-15A6-4601-A071-F99BE896D027}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{58243F14-15A6-4601-A071-F99BE896D027}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{58243F14-15A6-4601-A071-F99BE896D027}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -334,6 +346,8 @@ Global
|
|||||||
{181BC62C-EDEA-4DD1-8837-A4B1CBF8BE42} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
{181BC62C-EDEA-4DD1-8837-A4B1CBF8BE42} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
||||||
{C82B417F-94E6-4D4D-B261-0CAF40551D5E} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
{C82B417F-94E6-4D4D-B261-0CAF40551D5E} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
||||||
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
||||||
|
{58243F14-15A6-4601-A071-F99BE896D027} = {8C3CFEFE-78A5-4940-B388-D15FCE02ECE9}
|
||||||
|
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44} = {8C3CFEFE-78A5-4940-B388-D15FCE02ECE9}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using FileTime.GuiApp.Font;
|
|||||||
using FileTime.GuiApp.ViewModels;
|
using FileTime.GuiApp.ViewModels;
|
||||||
using FileTime.GuiApp.Views;
|
using FileTime.GuiApp.Views;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
|
using FileTime.Tools.Compression;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ public class App : Application
|
|||||||
.AddFrequencyNavigation()
|
.AddFrequencyNavigation()
|
||||||
.AddCommandPalette()
|
.AddCommandPalette()
|
||||||
.AddSearch()
|
.AddSearch()
|
||||||
|
.AddCompression()
|
||||||
.AddConfiguration(configuration)
|
.AddConfiguration(configuration)
|
||||||
.ConfigureFont(configuration)
|
.ConfigureFont(configuration)
|
||||||
.RegisterLogging()
|
.RegisterLogging()
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Search\FileTime.App.Search.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Search\FileTime.App.Search.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.CustomImpl\FileTime.GuiApp.CustomImpl.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.Font\FileTime.GuiApp.Font.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.Font\FileTime.GuiApp.Font.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp\FileTime.GuiApp.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp\FileTime.GuiApp.csproj" />
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
<Styles
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:interactions="clr-namespace:FileTime.Core.Interactions;assembly=FileTime.Core.Abstraction"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
<Styles.Resources>
|
<Styles.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
@@ -78,10 +81,11 @@
|
|||||||
<ControlTemplate>
|
<ControlTemplate>
|
||||||
<Border>
|
<Border>
|
||||||
<RadioButton
|
<RadioButton
|
||||||
Content="{TemplateBinding ContentPresenter.Content}"
|
|
||||||
Foreground="{DynamicResource ForegroundBrush}"
|
Foreground="{DynamicResource ForegroundBrush}"
|
||||||
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
|
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="{Binding Text}" x:DataType="interactions:IOptionElement" />
|
||||||
|
</RadioButton>
|
||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ public class LocalContentReader : IContentReader
|
|||||||
Position = position;
|
Position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream AsStream() => _binaryReader.BaseStream;
|
||||||
|
|
||||||
~LocalContentReader()
|
~LocalContentReader()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ public class LocalContentWriter : IContentWriter
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream AsStream() => _binaryWriter.BaseStream;
|
||||||
|
|
||||||
~LocalContentWriter()
|
~LocalContentWriter()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Models;
|
||||||
using FileTime.Server.Common;
|
using FileTime.Server.Common;
|
||||||
|
|
||||||
namespace FileTime.Providers.Remote;
|
namespace FileTime.Providers.Remote;
|
||||||
@@ -43,6 +44,8 @@ public class RemoteContentWriter : IRemoteContentWriter
|
|||||||
await _remoteConnection.FlushWriterAsync(_transactionId, cancellationToken);
|
await _remoteConnection.FlushWriterAsync(_transactionId, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Stream AsStream() => new ContentAccessStream(this);
|
||||||
|
|
||||||
private async Task InitializeRemoteWriter(NativePath nativePath)
|
private async Task InitializeRemoteWriter(NativePath nativePath)
|
||||||
{
|
{
|
||||||
_isRemoteWriterInitialized = true;
|
_isRemoteWriterInitialized = true;
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using SharpCompress.Archives;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public class CompressOperation<TEntry, TVolume> : ICompressOperation
|
||||||
|
where TEntry : IArchiveEntry
|
||||||
|
where TVolume : IVolume
|
||||||
|
{
|
||||||
|
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||||
|
private readonly AbstractWritableArchive<TEntry, TVolume> _archive;
|
||||||
|
private readonly Action<Stream> _saveTo;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (element.Provider.SupportsContentStreams)
|
||||||
|
{
|
||||||
|
var contentReader = await _contentAccessorFactory.GetContentReaderFactory(element.Provider).CreateContentReaderAsync(element);
|
||||||
|
|
||||||
|
var contentReaderStream = contentReader.AsStream();
|
||||||
|
|
||||||
|
_archive.AddEntry(key, contentReaderStream);
|
||||||
|
|
||||||
|
return new IDisposable[] {contentReader, contentReaderStream};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Enumerable.Empty<IDisposable>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveTo(Stream stream)
|
||||||
|
=> _saveTo(stream);
|
||||||
|
|
||||||
|
~CompressOperation()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_archive.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<RootNamespace>FileTime.Tools.Compression</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SharpCompress" Version="0.33.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public interface ICompressOperation : IDisposable
|
||||||
|
{
|
||||||
|
Task<IEnumerable<IDisposable>> CompressElement(IElement element, string key);
|
||||||
|
void SaveTo(Stream stream);
|
||||||
|
}
|
||||||
164
src/Tools/FileTime.Tools.Compression/CompressCommand.cs
Normal file
164
src/Tools/FileTime.Tools.Compression/CompressCommand.cs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
using FileTime.Core.Command;
|
||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Interactions;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using FileTime.Tools.Extensions;
|
||||||
|
using SharpCompress.Archives;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using SharpCompressCompressionType = SharpCompress.Common.CompressionType;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public class CompressCommand : CommandBase, IExecutableCommand, ITransportationCommand, IRequireInputCommand
|
||||||
|
{
|
||||||
|
private readonly IList<IInputElement> _inputs;
|
||||||
|
private readonly IUserCommunicationService _userCommunicationService;
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||||
|
private readonly OptionsInputElement<CompressionType> _compressionType;
|
||||||
|
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||||
|
private readonly TextInputElement _targetFileName;
|
||||||
|
public IReadOnlyList<FullName> Sources { get; }
|
||||||
|
public FullName Target { get; }
|
||||||
|
public TransportMode TransportMode { get; }
|
||||||
|
|
||||||
|
|
||||||
|
internal CompressCommand(
|
||||||
|
IUserCommunicationService userCommunicationService,
|
||||||
|
ITimelessContentProvider timelessContentProvider,
|
||||||
|
IContentAccessorFactory contentAccessorFactory,
|
||||||
|
IReadOnlyCollection<FullName> sources,
|
||||||
|
TransportMode mode,
|
||||||
|
FullName targetFullName)
|
||||||
|
{
|
||||||
|
_userCommunicationService = userCommunicationService;
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
|
ArgumentNullException.ThrowIfNull(sources);
|
||||||
|
ArgumentNullException.ThrowIfNull(mode);
|
||||||
|
ArgumentNullException.ThrowIfNull(targetFullName);
|
||||||
|
|
||||||
|
Sources = new List<FullName>(sources).AsReadOnly();
|
||||||
|
TransportMode = mode;
|
||||||
|
Target = targetFullName;
|
||||||
|
|
||||||
|
_targetFileName = new TextInputElement("File name");
|
||||||
|
_compressionType = new OptionsInputElement<CompressionType>(
|
||||||
|
"CompressionMethod",
|
||||||
|
Enum.GetValues<CompressionType>()
|
||||||
|
.Select(t => new OptionElement<CompressionType>(t.ToString(), t))
|
||||||
|
);
|
||||||
|
|
||||||
|
_inputs = new List<IInputElement>
|
||||||
|
{
|
||||||
|
_targetFileName,
|
||||||
|
_compressionType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||||
|
{
|
||||||
|
//TODO:
|
||||||
|
return Task.FromResult(CanCommandRun.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||||
|
{
|
||||||
|
var differences = new List<Difference>
|
||||||
|
{
|
||||||
|
new(DifferenceActionType.Create, new AbsolutePath(_timelessContentProvider, currentTime, Target, AbsolutePathType.Element))
|
||||||
|
};
|
||||||
|
return Task.FromResult(currentTime.WithDifferences(differences));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Cancel()
|
||||||
|
=> _cancellationTokenSource.Cancel();
|
||||||
|
|
||||||
|
public async Task Execute()
|
||||||
|
{
|
||||||
|
var disposables = Enumerable.Empty<IDisposable>();
|
||||||
|
|
||||||
|
ICompressOperation? compressOperation = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var compressionType = _compressionType.Value;
|
||||||
|
|
||||||
|
compressOperation = compressionType switch
|
||||||
|
{
|
||||||
|
CompressionType.Gzip => SharpCompress.Archives.GZip.GZipArchive.Create().Map(a => GetCompressOperation(a, (s) => a.SaveTo(s, new SharpCompress.Writers.WriterOptions(SharpCompressCompressionType.GZip)))),
|
||||||
|
CompressionType.Zip => SharpCompress.Archives.Zip.ZipArchive.Create().Map(a => GetCompressOperation(a, a.SaveTo)),
|
||||||
|
CompressionType.Tar => SharpCompress.Archives.Tar.TarArchive.Create().Map(a => GetCompressOperation(a, (s) => a.SaveTo(s, new SharpCompress.Writers.WriterOptions(SharpCompressCompressionType.None)))),
|
||||||
|
CompressionType.TarBz2 => SharpCompress.Archives.Tar.TarArchive.Create().Map(a => GetCompressOperation(a, (s) => a.SaveTo(s, new SharpCompress.Writers.WriterOptions(SharpCompressCompressionType.BZip2)))),
|
||||||
|
CompressionType.TarLz => SharpCompress.Archives.Tar.TarArchive.Create().Map(a => GetCompressOperation(a, (s) => a.SaveTo(s, new SharpCompress.Writers.WriterOptions(SharpCompressCompressionType.LZip)))),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
|
||||||
|
disposables = await TraverseTree(Sources, "", compressOperation);
|
||||||
|
|
||||||
|
var resolvedParent = await _timelessContentProvider.GetItemByFullNameAsync(
|
||||||
|
Target,
|
||||||
|
PointInTime.Present
|
||||||
|
);
|
||||||
|
|
||||||
|
var newItemName = Target.GetChild(_targetFileName.Value!);
|
||||||
|
await _contentAccessorFactory.GetItemCreator(resolvedParent.Provider).CreateElementAsync(resolvedParent.Provider, newItemName);
|
||||||
|
var targetElement = (IElement) await _timelessContentProvider.GetItemByFullNameAsync(newItemName, PointInTime.Present);
|
||||||
|
using var contentWriter = await _contentAccessorFactory.GetContentWriterFactory(resolvedParent.Provider).CreateContentWriterAsync(targetElement);
|
||||||
|
await using var contentWriterStream = contentWriter.AsStream();
|
||||||
|
compressOperation.SaveTo(contentWriterStream);
|
||||||
|
|
||||||
|
await contentWriterStream.FlushAsync(_cancellationTokenSource.Token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
compressOperation?.Dispose();
|
||||||
|
|
||||||
|
foreach (var disposable in disposables)
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<IDisposable>> TraverseTree(
|
||||||
|
IEnumerable<FullName> sources,
|
||||||
|
string basePath,
|
||||||
|
ICompressOperation operations,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var disposables = Enumerable.Empty<IDisposable>();
|
||||||
|
foreach (var source in sources)
|
||||||
|
{
|
||||||
|
var item = await _timelessContentProvider.GetItemByFullNameAsync(
|
||||||
|
source,
|
||||||
|
PointInTime.Present
|
||||||
|
);
|
||||||
|
|
||||||
|
if (item is IContainer container)
|
||||||
|
{
|
||||||
|
var items = container.Items;
|
||||||
|
|
||||||
|
var childItems = items.Select(i => i.Path).ToList();
|
||||||
|
var path = string.IsNullOrEmpty(basePath) ? container.Name : basePath + "\\" + container.Name;
|
||||||
|
disposables = disposables.Concat(await TraverseTree(childItems, path, operations, cancellationToken));
|
||||||
|
}
|
||||||
|
else if (item is IElement element)
|
||||||
|
{
|
||||||
|
var path = string.IsNullOrEmpty(basePath) ? element.Name : basePath + "\\" + element.Name;
|
||||||
|
disposables = disposables.Concat(await operations.CompressElement(element, path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return disposables;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompressOperation<TEntry, TVolume> GetCompressOperation<TEntry, TVolume>(AbstractWritableArchive<TEntry, TVolume> archive, Action<Stream> saveTo)
|
||||||
|
where TEntry : IArchiveEntry where TVolume : IVolume
|
||||||
|
=> new(_contentAccessorFactory, archive, saveTo);
|
||||||
|
|
||||||
|
public async Task ReadInputs()
|
||||||
|
=> await _userCommunicationService.ReadInputs(_inputs);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using FileTime.Core.Command;
|
||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Interactions;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public class CompressCommandFactory : ITransportationCommandFactory<CompressCommand>
|
||||||
|
{
|
||||||
|
private readonly IUserCommunicationService _userCommunicationService;
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||||
|
|
||||||
|
public CompressCommandFactory(
|
||||||
|
IUserCommunicationService userCommunicationService,
|
||||||
|
ITimelessContentProvider timelessContentProvider,
|
||||||
|
IContentAccessorFactory contentAccessorFactory)
|
||||||
|
{
|
||||||
|
_userCommunicationService = userCommunicationService;
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompressCommand GenerateCommand(IReadOnlyCollection<FullName> sources, TransportMode mode, FullName targetFullName)
|
||||||
|
=> new(
|
||||||
|
_userCommunicationService,
|
||||||
|
_timelessContentProvider,
|
||||||
|
_contentAccessorFactory,
|
||||||
|
sources,
|
||||||
|
mode,
|
||||||
|
targetFullName
|
||||||
|
);
|
||||||
|
}
|
||||||
15
src/Tools/FileTime.Tools.Compression/CompressUserCommand.cs
Normal file
15
src/Tools/FileTime.Tools.Compression/CompressUserCommand.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using FileTime.App.Core.UserCommand;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public class CompressUserCommand : IIdentifiableUserCommand
|
||||||
|
{
|
||||||
|
public const string CommandName = "compress";
|
||||||
|
public static readonly CompressUserCommand Instance = new();
|
||||||
|
private CompressUserCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserCommandID => CommandName;
|
||||||
|
public string Title => "Compress";
|
||||||
|
}
|
||||||
10
src/Tools/FileTime.Tools.Compression/CompressionType.cs
Normal file
10
src/Tools/FileTime.Tools.Compression/CompressionType.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public enum CompressionType
|
||||||
|
{
|
||||||
|
Gzip,
|
||||||
|
Zip,
|
||||||
|
Tar,
|
||||||
|
TarBz2,
|
||||||
|
TarLz
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using DeclarativeProperty;
|
||||||
|
using FileTime.App.Core.Services;
|
||||||
|
using FileTime.App.Core.Services.UserCommandHandler;
|
||||||
|
using FileTime.App.Core.ViewModels;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public class CompressionUserCommandHandler : AggregatedUserCommandHandler
|
||||||
|
{
|
||||||
|
private readonly IClipboardService _clipboardService;
|
||||||
|
private readonly IDeclarativeProperty<ObservableCollection<FullName>?> _markedItems;
|
||||||
|
private readonly IDeclarativeProperty<IItemViewModel?> _selectedItem;
|
||||||
|
|
||||||
|
public CompressionUserCommandHandler(
|
||||||
|
IAppState appState,
|
||||||
|
IClipboardService clipboardService)
|
||||||
|
{
|
||||||
|
_clipboardService = clipboardService;
|
||||||
|
_markedItems = appState.SelectedTab.Map(t => t.MarkedItems).Switch();
|
||||||
|
_selectedItem = appState.SelectedTab.Map(t => t.CurrentSelectedItem).Switch();
|
||||||
|
|
||||||
|
AddCommandHandler(new[]
|
||||||
|
{
|
||||||
|
new TypeUserCommandHandler<CompressUserCommand>(Compress)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Compress()
|
||||||
|
{
|
||||||
|
_clipboardService.Clear();
|
||||||
|
_clipboardService.SetCommand<CompressCommandFactory>();
|
||||||
|
|
||||||
|
if (_markedItems.Value is {Count: > 0} markedItems)
|
||||||
|
{
|
||||||
|
foreach (var markedItem in markedItems)
|
||||||
|
{
|
||||||
|
_clipboardService.AddContent(markedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_selectedItem.Value?.BaseItem?.FullName is { } fullname)
|
||||||
|
{
|
||||||
|
_clipboardService.AddContent(fullname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Core\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Tools.Compression.Core\FileTime.Tools.Compression.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\FileTime.Tools\FileTime.Tools.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
24
src/Tools/FileTime.Tools.Compression/Startup.cs
Normal file
24
src/Tools/FileTime.Tools.Compression/Startup.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using FileTime.App.Core.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace FileTime.Tools.Compression;
|
||||||
|
|
||||||
|
public class StartupHandler : IStartupHandler
|
||||||
|
{
|
||||||
|
public StartupHandler(IIdentifiableUserCommandService identifiableUserCommandService)
|
||||||
|
{
|
||||||
|
identifiableUserCommandService.AddIdentifiableUserCommand(CompressUserCommand.Instance);
|
||||||
|
}
|
||||||
|
public Task InitAsync() => Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Startup
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddCompression(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<IStartupHandler, StartupHandler>();
|
||||||
|
services.AddSingleton<CompressCommandFactory>();
|
||||||
|
services.AddSingleton<IUserCommandHandler, CompressionUserCommandHandler>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ namespace FileTime.Tools.Extensions;
|
|||||||
|
|
||||||
public static class ObjectExtensions
|
public static class ObjectExtensions
|
||||||
{
|
{
|
||||||
|
public static TResult Map<T, TResult>(this T obj, Func<T, TResult> mapper)
|
||||||
|
=> mapper(obj);
|
||||||
public static TResult? MapNull<T, TResult>(this T obj, Func<TResult?> nullHandler, Func<T, TResult?> valueHandler)
|
public static TResult? MapNull<T, TResult>(this T obj, Func<TResult?> nullHandler, Func<T, TResult?> valueHandler)
|
||||||
=> obj == null ? nullHandler() : valueHandler(obj);
|
=> obj == null ? nullHandler() : valueHandler(obj);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user