Select item upon entering container
This commit is contained in:
@@ -36,7 +36,7 @@ public static class DynamicDataExtensions
|
|||||||
public void OnCompleted()
|
public void OnCompleted()
|
||||||
{
|
{
|
||||||
Disposable?.Dispose();
|
Disposable?.Dispose();
|
||||||
_taskCompletionSource.SetResult(default(TTaskResult));
|
_taskCompletionSource.SetResult(default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,13 +60,12 @@ public static class DynamicDataExtensions
|
|||||||
var context = new DisposableContext<IReadOnlyCollection<AbsolutePath>, IEnumerable<AbsolutePath>?>(r => r,
|
var context = new DisposableContext<IReadOnlyCollection<AbsolutePath>, IEnumerable<AbsolutePath>?>(r => r,
|
||||||
taskCompletionSource);
|
taskCompletionSource);
|
||||||
|
|
||||||
var disposable = stream
|
context.Disposable = stream
|
||||||
.Subscribe(
|
.Subscribe(
|
||||||
context.OnNext,
|
context.OnNext,
|
||||||
context.OnError,
|
context.OnError,
|
||||||
context.OnCompleted
|
context.OnCompleted
|
||||||
);
|
);
|
||||||
context.Disposable = disposable;
|
|
||||||
|
|
||||||
return taskCompletionSource.Task;
|
return taskCompletionSource.Task;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace FileTime.Core.Extensions;
|
||||||
|
|
||||||
|
public static class TaskExtensions
|
||||||
|
{
|
||||||
|
public static async Task<T?> AwaitWithTimeout<T>(this Task<T> task, int timeout, T? defaultValue = default)
|
||||||
|
{
|
||||||
|
if (await Task.WhenAny(task, Task.Delay(timeout)) == task)
|
||||||
|
{
|
||||||
|
return task.Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/Core/FileTime.Core.Abstraction/Helper/PathHelper.cs
Normal file
54
src/Core/FileTime.Core.Abstraction/Helper/PathHelper.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Core.Helper;
|
||||||
|
|
||||||
|
public static class PathHelper
|
||||||
|
{
|
||||||
|
public static string GetLongerPath(string? oldPath, string? newPath)
|
||||||
|
{
|
||||||
|
var oldPathParts = oldPath?.Split(Constants.SeparatorChar) ?? Array.Empty<string>();
|
||||||
|
var newPathParts = newPath?.Split(Constants.SeparatorChar) ?? Array.Empty<string>();
|
||||||
|
|
||||||
|
var commonPathParts = new List<string>();
|
||||||
|
|
||||||
|
var max = oldPathParts.Length > newPathParts.Length ? oldPathParts.Length : newPathParts.Length;
|
||||||
|
|
||||||
|
for (var i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
if (newPathParts.Length <= i)
|
||||||
|
{
|
||||||
|
commonPathParts.AddRange(oldPathParts.Skip(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (oldPathParts.Length <= i || oldPathParts[i] != newPathParts[i])
|
||||||
|
{
|
||||||
|
commonPathParts.AddRange(newPathParts.Skip(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (oldPathParts[i] == newPathParts[i])
|
||||||
|
{
|
||||||
|
commonPathParts.Add(oldPathParts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(Constants.SeparatorChar, commonPathParts);
|
||||||
|
}
|
||||||
|
public static string GetCommonPath(string? path1, string? path2)
|
||||||
|
{
|
||||||
|
var path1Parts = path1?.Split(Constants.SeparatorChar) ?? Array.Empty<string>();
|
||||||
|
var path2Parts = path2?.Split(Constants.SeparatorChar) ?? Array.Empty<string>();
|
||||||
|
|
||||||
|
var commonPathParts = new List<string>();
|
||||||
|
|
||||||
|
var max = path1Parts.Length > path2Parts.Length ? path2Parts.Length : path1Parts.Length;
|
||||||
|
|
||||||
|
for (var i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
if (path1Parts[i] != path2Parts[i]) break;
|
||||||
|
|
||||||
|
commonPathParts.Add(path1Parts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(Constants.SeparatorChar, commonPathParts);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,13 +9,12 @@ public class CommandTimeState
|
|||||||
public bool ForceRun { get; set; }
|
public bool ForceRun { get; set; }
|
||||||
public ExecutionState ExecutionState { get; set; }
|
public ExecutionState ExecutionState { get; set; }
|
||||||
|
|
||||||
public CommandTimeState(ICommand command, PointInTime? startTime)
|
public CommandTimeState(ICommand command)
|
||||||
{
|
{
|
||||||
Command = command;
|
Command = command;
|
||||||
Task.Run(async () => await UpdateState(startTime)).Wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateState(PointInTime? startPoint)
|
public async Task UpdateStateAsync(PointInTime? startPoint)
|
||||||
{
|
{
|
||||||
CanRun = startPoint == null ? CanCommandRun.False : await Command.CanRun(startPoint);
|
CanRun = startPoint == null ? CanCommandRun.False : await Command.CanRun(startPoint);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ public class ParallelCommands
|
|||||||
var currentTime = startTime;
|
var currentTime = startTime;
|
||||||
foreach (var command in commands)
|
foreach (var command in commands)
|
||||||
{
|
{
|
||||||
CommandTimeState commandTimeState = new(command, currentTime);
|
var commandTimeState = new CommandTimeState(command);
|
||||||
|
await commandTimeState.UpdateStateAsync(currentTime);
|
||||||
if (currentTime != null)
|
if (currentTime != null)
|
||||||
{
|
{
|
||||||
var canRun = await command.CanRun(currentTime);
|
var canRun = await command.CanRun(currentTime);
|
||||||
@@ -53,7 +54,9 @@ public class ParallelCommands
|
|||||||
|
|
||||||
public async Task AddCommand(ICommand command)
|
public async Task AddCommand(ICommand command)
|
||||||
{
|
{
|
||||||
_commands.Add(new CommandTimeState(command, Result));
|
var commandTimeState = new CommandTimeState(command);
|
||||||
|
await commandTimeState.UpdateStateAsync(Result);
|
||||||
|
_commands.Add(commandTimeState);
|
||||||
if (Result != null)
|
if (Result != null)
|
||||||
{
|
{
|
||||||
Result = await command.SimulateCommand(Result);
|
Result = await command.SimulateCommand(Result);
|
||||||
@@ -63,15 +66,15 @@ public class ParallelCommands
|
|||||||
public async Task<PointInTime?> RefreshResult(PointInTime? startPoint)
|
public async Task<PointInTime?> RefreshResult(PointInTime? startPoint)
|
||||||
{
|
{
|
||||||
var result = startPoint;
|
var result = startPoint;
|
||||||
foreach (var command in _commands)
|
foreach (var commandTimeState in _commands)
|
||||||
{
|
{
|
||||||
await command.UpdateState(result);
|
await commandTimeState.UpdateStateAsync(result);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
var canRun = await command.Command.CanRun(result);
|
var canRun = await commandTimeState.Command.CanRun(result);
|
||||||
if (canRun == CanCommandRun.True || (canRun == CanCommandRun.Forcable && command.ForceRun))
|
if (canRun == CanCommandRun.True || (canRun == CanCommandRun.Forcable && commandTimeState.ForceRun))
|
||||||
{
|
{
|
||||||
result = await command.Command.SimulateCommand(result);
|
result = await commandTimeState.Command.SimulateCommand(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, s
|
|||||||
var parent = await ResolveParentAsync();
|
var parent = await ResolveParentAsync();
|
||||||
if (parent is not IContainer parentContainer) return CanCommandRun.False;
|
if (parent is not IContainer parentContainer) return CanCommandRun.False;
|
||||||
|
|
||||||
var items = await parentContainer.Items.GetItemsAsync();
|
var items = await parentContainer.Items.GetItemsAsync().AwaitWithTimeout(10, Enumerable.Empty<AbsolutePath>());
|
||||||
if (items is null) return CanCommandRun.Forcable;
|
if (items is null) return CanCommandRun.Forcable;
|
||||||
|
|
||||||
var existingItem = items.FirstOrDefault(i => i.Path.GetName() == NewItemName);
|
var existingItem = items.FirstOrDefault(i => i.Path.GetName() == NewItemName);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Reactive.Linq;
|
|||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Alias;
|
using DynamicData.Alias;
|
||||||
|
using FileTime.Core.Helper;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ public class Tab : ITab
|
|||||||
private readonly BehaviorSubject<IContainer?> _currentLocationForced = new(null);
|
private readonly BehaviorSubject<IContainer?> _currentLocationForced = new(null);
|
||||||
private readonly BehaviorSubject<AbsolutePath?> _currentSelectedItem = new(null);
|
private readonly BehaviorSubject<AbsolutePath?> _currentSelectedItem = new(null);
|
||||||
private readonly SourceList<ItemFilter> _itemFilters = new();
|
private readonly SourceList<ItemFilter> _itemFilters = new();
|
||||||
|
private FullName? _lastDeepestSelected;
|
||||||
private AbsolutePath? _currentSelectedItemCached;
|
private AbsolutePath? _currentSelectedItemCached;
|
||||||
private PointInTime _currentPointInTime;
|
private PointInTime _currentPointInTime;
|
||||||
|
|
||||||
@@ -77,6 +79,11 @@ public class Tab : ITab
|
|||||||
{
|
{
|
||||||
_currentSelectedItemCached = s;
|
_currentSelectedItemCached = s;
|
||||||
_currentSelectedItem.OnNext(s);
|
_currentSelectedItem.OnNext(s);
|
||||||
|
|
||||||
|
if (s is not null)
|
||||||
|
{
|
||||||
|
_lastDeepestSelected = new FullName(PathHelper.GetLongerPath(_lastDeepestSelected?.Path, s.Path.Path));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +96,32 @@ public class Tab : ITab
|
|||||||
|
|
||||||
private AbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
|
private AbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
|
||||||
{
|
{
|
||||||
//TODO:
|
if (!items.Any()) return null;
|
||||||
return new AbsolutePath(_timelessContentProvider, items.First());
|
|
||||||
|
var newSelectedItem = new AbsolutePath(_timelessContentProvider, items.First());
|
||||||
|
if (_lastDeepestSelected is not null)
|
||||||
|
{
|
||||||
|
var parentPath = items.First().FullName?.GetParent()?.Path;
|
||||||
|
|
||||||
|
if (parentPath is not null && _lastDeepestSelected.Path.StartsWith(parentPath))
|
||||||
|
{
|
||||||
|
var itemNameToSelect = _lastDeepestSelected.Path
|
||||||
|
.Split(Constants.SeparatorChar)
|
||||||
|
.Skip((parentPath?.Split(Constants.SeparatorChar).Length) ?? 0)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
var itemToSelect = items.FirstOrDefault(i => i.FullName?.GetName() == itemNameToSelect);
|
||||||
|
|
||||||
|
if (itemToSelect != null)
|
||||||
|
{
|
||||||
|
newSelectedItem = new AbsolutePath(_timelessContentProvider, itemToSelect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastDeepestSelected = new FullName(PathHelper.GetLongerPath(_lastDeepestSelected?.Path, newSelectedItem.Path.Path));
|
||||||
|
|
||||||
|
return newSelectedItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class LocalCommandExecutor : ILocalCommandExecutor
|
|||||||
{
|
{
|
||||||
await _commandRunner.RunCommandAsync(context.Command);
|
await _commandRunner.RunCommandAsync(context.Command);
|
||||||
}
|
}
|
||||||
catch(Exception ex){}
|
catch (Exception ex) { }
|
||||||
|
|
||||||
CommandFinished.Invoke(this, context.Command);
|
CommandFinished.Invoke(this, context.Command);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user