Timeless refactor

This commit is contained in:
2022-05-21 14:30:24 +02:00
parent ced0c88a10
commit 6ee5afa632
47 changed files with 571 additions and 181 deletions

View File

@@ -0,0 +1,8 @@
namespace FileTime.Core.Command;
public enum CanCommandRun
{
True,
False,
Forcable
}

View File

@@ -1,6 +1,9 @@
using FileTime.Core.Timeline;
namespace FileTime.Core.Command;
public interface ICommand
{
Task<CanCommandRun> CanRun(PointInTime currentTime);
Task<PointInTime?> SimulateCommand(PointInTime? currentTime);
}

View File

@@ -0,0 +1,8 @@
using FileTime.Core.Timeline;
namespace FileTime.Core.Command;
public interface IExecutableCommand : ICommand
{
Task Execute(ICommandScheduler commandScheduler);
}

View File

@@ -0,0 +1,53 @@
using FileTime.Core.Enums;
using FileTime.Core.Timeline;
namespace FileTime.Core.Models;
public class AbsolutePath
{
public ITimelessContentProvider TimelessProvider { get; }
public PointInTime PointInTime { get; }
public FullName Path { get; }
public AbsolutePathType Type { get; }
public AbsolutePath(
ITimelessContentProvider timelessProvider,
PointInTime pointInTime,
FullName path,
AbsolutePathType type)
{
TimelessProvider = timelessProvider;
Path = path;
Type = type;
PointInTime = pointInTime;
}
public AbsolutePath(ITimelessContentProvider timelessProvider, IItem item)
{
TimelessProvider = timelessProvider;
PointInTime = item.PointInTime;
Path = item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item));
Type = item.Type;
}
public async Task<IItem> ResolveAsync(bool forceResolve = false,
ItemInitializationSettings itemInitializationSettings = default)
{
return await TimelessProvider.GetItemByFullNameAsync(Path, PointInTime, forceResolve, Type,
itemInitializationSettings);
}
public async Task<IItem?> ResolveAsyncSafe(bool forceResolve = false,
ItemInitializationSettings itemInitializationSettings = default)
{
try
{
return await ResolveAsync(forceResolve, itemInitializationSettings);
}
catch
{
return null;
}
}
}

View File

@@ -1,15 +0,0 @@
using FileTime.Core.Enums;
using FileTime.Core.Services;
namespace FileTime.Core.Models;
public interface IAbsolutePath
{
IContentProvider ContentProvider { get; }
IContentProvider? VirtualContentProvider { get; }
FullName Path { get; }
AbsolutePathType Type { get; }
Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default);
Task<IItem?> ResolveAsyncSafe(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default);
}

View File

@@ -4,6 +4,6 @@ namespace FileTime.Core.Models;
public interface IContainer : IItem
{
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; }
IObservable<IObservable<IChangeSet<AbsolutePath>>?> Items { get; }
IObservable<bool> IsLoading { get; }
}

View File

@@ -1,6 +1,7 @@
using System.Reactive.Linq;
using FileTime.Core.Enums;
using FileTime.Core.Services;
using FileTime.Core.Timeline;
namespace FileTime.Core.Models;
@@ -10,7 +11,7 @@ public interface IItem
string DisplayName { get; }
FullName? FullName { get; }
NativePath? NativePath { get; }
IAbsolutePath? Parent { get; }
AbsolutePath? Parent { get; }
bool IsHidden { get; }
bool IsExists { get; }
DateTime? CreatedAt { get; }
@@ -19,6 +20,7 @@ public interface IItem
IContentProvider Provider { get; }
string? Attributes { get; }
AbsolutePathType Type { get; }
PointInTime PointInTime { get; }
IObservable<IEnumerable<Exception>> Exceptions { get; }
ReadOnlyExtensionCollection Extensions { get; }

View File

@@ -1,6 +1,7 @@
using FileTime.Core.Behaviors;
using FileTime.Core.Enums;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
namespace FileTime.Core.Services;
@@ -8,17 +9,18 @@ public interface IContentProvider : IContainer, IOnContainerEnter
{
Task<IItem> GetItemByFullNameAsync(
FullName fullName,
PointInTime pointInTime,
bool forceResolve = false,
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default);
Task<IItem> GetItemByNativePathAsync(
NativePath nativePath,
Task<IItem> GetItemByNativePathAsync(NativePath nativePath,
PointInTime pointInTime,
bool forceResolve = false,
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default);
Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
Task<List<AbsolutePath>> GetItemsByContainerAsync(FullName fullName, PointInTime pointInTime);
NativePath GetNativePath(FullName fullName);
Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default);

View File

@@ -7,12 +7,12 @@ namespace FileTime.Core.Services;
public interface ITab : IInitable<IContainer>
{
IObservable<IContainer?> CurrentLocation { get; }
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
IObservable<AbsolutePath?> CurrentSelectedItem { get; }
IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
void SetCurrentLocation(IContainer newLocation);
void AddItemFilter(ItemFilter filter);
void RemoveItemFilter(ItemFilter filter);
void RemoveItemFilter(string name);
void SetSelectedItem(IAbsolutePath newSelectedItem);
void SetSelectedItem(AbsolutePath newSelectedItem);
}

View File

@@ -0,0 +1,21 @@
using FileTime.Core.Command;
namespace FileTime.Core.Timeline;
public class CommandTimeState
{
public ICommand Command { get; }
public CanCommandRun CanRun { get; private set; } = CanCommandRun.False;
public bool ForceRun { get; set; }
public CommandTimeState(ICommand command, PointInTime? startTime)
{
Command = command;
Task.Run(async () => await UpdateState(startTime)).Wait();
}
public async Task UpdateState(PointInTime? startPoint)
{
CanRun = startPoint == null ? CanCommandRun.False : await Command.CanRun(startPoint);
}
}

View File

@@ -0,0 +1,16 @@
using FileTime.Core.Models;
using FileTime.Core.Services;
namespace FileTime.Core.Timeline;
public class Difference
{
public AbsolutePath AbsolutePath { get; }
public DifferenceActionType Action { get; }
public Difference(DifferenceActionType action, AbsolutePath absolutePath)
{
AbsolutePath = absolutePath;
Action = action;
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.Core.Timeline;
public enum DifferenceActionType
{
Create,
Delete
}

View File

@@ -0,0 +1,6 @@
namespace FileTime.Core.Timeline;
public interface ICommandScheduler
{
}

View File

@@ -0,0 +1,16 @@
using System.Reactive.Subjects;
using FileTime.Core.Enums;
using FileTime.Core.Models;
namespace FileTime.Core.Timeline;
public interface ITimelessContentProvider
{
BehaviorSubject<PointInTime> CurrentPointInTime { get; }
Task<IItem> GetItemByFullNameAsync(FullName fullName,
PointInTime? pointInTime,
bool forceResolve = false,
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default);
}

View File

@@ -0,0 +1,90 @@
using FileTime.Core.Command;
namespace FileTime.Core.Timeline;
public class ParallelCommands
{
private static ushort _idCounter;
public List<CommandTimeState> _commands;
public ushort Id { get; }
public IReadOnlyList<CommandTimeState> Commands { get; }
public PointInTime? Result { get; private set; }
public ParallelCommands(PointInTime? result)
: this(new List<CommandTimeState>(), result)
{
}
private ParallelCommands(List<CommandTimeState> commands, PointInTime? result)
{
Id = _idCounter++;
_commands = commands;
Commands = _commands.AsReadOnly();
Result = result;
}
public static async Task<ParallelCommands> Create(PointInTime? startTime, IEnumerable<ICommand> commands)
{
var commandStates = new List<CommandTimeState>();
var currentTime = startTime;
foreach (var command in commands)
{
CommandTimeState commandTimeState = new(command, currentTime);
if (currentTime != null)
{
var canRun = await command.CanRun(currentTime);
if (canRun == CanCommandRun.True)
{
currentTime = await command.SimulateCommand(currentTime);
}
else
{
currentTime = null;
}
}
commandStates.Add(commandTimeState);
}
return new ParallelCommands(commandStates, currentTime);
}
public async Task AddCommand(ICommand command)
{
_commands.Add(new CommandTimeState(command, Result));
if (Result != null)
{
Result = await command.SimulateCommand(Result);
}
}
public async Task<PointInTime?> RefreshResult(PointInTime? startPoint)
{
var result = startPoint;
foreach (var command in _commands)
{
await command.UpdateState(result);
if (result != null)
{
var canRun = await command.Command.CanRun(result);
if (canRun == CanCommandRun.True || (canRun == CanCommandRun.Forcable && command.ForceRun))
{
result = await command.Command.SimulateCommand(result);
}
else
{
result = null;
}
}
}
Result = result;
return Result;
}
public void RemoveAt(int number) => _commands.RemoveAt(number);
internal void Remove(CommandTimeState command) => _commands.Remove(command);
}

View File

@@ -0,0 +1,41 @@
namespace FileTime.Core.Timeline;
public class PointInTime
{
private readonly List<Difference> _differences;
public static readonly PointInTime Eternal = new PointInTime();
public static readonly PointInTime Present = new PointInTime();
public IReadOnlyList<Difference> Differences { get; }
private PointInTime() : this(new List<Difference>())
{
}
private PointInTime(IEnumerable<Difference> differences)
{
_differences = new List<Difference>(differences);
Differences = _differences.AsReadOnly();
}
private PointInTime(PointInTime previous, IEnumerable<Difference> differences)
: this(MergeDifferences(previous.Differences, differences))
{
}
public PointInTime WithDifferences(IEnumerable<Difference> differences) =>
new(this, differences);
private static List<Difference> MergeDifferences(IEnumerable<Difference> previouses,
IEnumerable<Difference> differences)
{
var merged = new List<Difference>();
merged.AddRange(previouses);
merged.AddRange(differences);
return merged;
}
public static PointInTime CreateEmpty() => new PointInTime();
}