File scoped namespace
This commit is contained in:
@@ -1,2 +1,4 @@
|
|||||||
[*.cs]
|
[*.cs]
|
||||||
dotnet_diagnostic.RCS1196.severity = none
|
dotnet_diagnostic.RCS1196.severity = none
|
||||||
|
csharp_style_namespace_declarations = file_scoped:error
|
||||||
|
dotnet_diagnostic.IDE0161.severity = error
|
||||||
@@ -1,66 +1,65 @@
|
|||||||
namespace FileTime.App.Core.Command
|
namespace FileTime.App.Core.Command;
|
||||||
{
|
|
||||||
public enum Commands
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
|
|
||||||
AutoRefresh,
|
public enum Commands
|
||||||
ChangeTimelineMode,
|
{
|
||||||
CloseTab,
|
None,
|
||||||
Compress,
|
|
||||||
Copy,
|
AutoRefresh,
|
||||||
CopyHash,
|
ChangeTimelineMode,
|
||||||
CopyPath,
|
CloseTab,
|
||||||
CreateContainer,
|
Compress,
|
||||||
CreateElement,
|
Copy,
|
||||||
Cut,
|
CopyHash,
|
||||||
Edit,
|
CopyPath,
|
||||||
EnterRapidTravel,
|
CreateContainer,
|
||||||
FindByName,
|
CreateElement,
|
||||||
FindByNameRegex,
|
Cut,
|
||||||
GoToHome,
|
Edit,
|
||||||
GoToPath,
|
EnterRapidTravel,
|
||||||
GoToProvider,
|
FindByName,
|
||||||
GoToRoot,
|
FindByNameRegex,
|
||||||
GoUp,
|
GoToHome,
|
||||||
HardDelete,
|
GoToPath,
|
||||||
Mark,
|
GoToProvider,
|
||||||
MoveCursorDown,
|
GoToRoot,
|
||||||
MoveCursorDownPage,
|
GoUp,
|
||||||
MoveCursorUp,
|
HardDelete,
|
||||||
MoveCursorUpPage,
|
Mark,
|
||||||
MoveToFirst,
|
MoveCursorDown,
|
||||||
MoveToLast,
|
MoveCursorDownPage,
|
||||||
NextTimelineBlock,
|
MoveCursorUp,
|
||||||
NextTimelineCommand,
|
MoveCursorUpPage,
|
||||||
Open,
|
MoveToFirst,
|
||||||
OpenInFileBrowser,
|
MoveToLast,
|
||||||
OpenOrRun,
|
NextTimelineBlock,
|
||||||
PasteMerge,
|
NextTimelineCommand,
|
||||||
PasteOverwrite,
|
Open,
|
||||||
PasteSkip,
|
OpenInFileBrowser,
|
||||||
PinFavorite,
|
OpenOrRun,
|
||||||
PreviousTimelineBlock,
|
PasteMerge,
|
||||||
PreviousTimelineCommand,
|
PasteOverwrite,
|
||||||
Refresh,
|
PasteSkip,
|
||||||
Rename,
|
PinFavorite,
|
||||||
RunCommand,
|
PreviousTimelineBlock,
|
||||||
ScanContainerSize,
|
PreviousTimelineCommand,
|
||||||
ShowAllShotcut,
|
Refresh,
|
||||||
SoftDelete,
|
Rename,
|
||||||
SwitchToLastTab,
|
RunCommand,
|
||||||
SwitchToTab1,
|
ScanContainerSize,
|
||||||
SwitchToTab2,
|
ShowAllShotcut,
|
||||||
SwitchToTab3,
|
SoftDelete,
|
||||||
SwitchToTab4,
|
SwitchToLastTab,
|
||||||
SwitchToTab5,
|
SwitchToTab1,
|
||||||
SwitchToTab6,
|
SwitchToTab2,
|
||||||
SwitchToTab7,
|
SwitchToTab3,
|
||||||
SwitchToTab8,
|
SwitchToTab4,
|
||||||
TimelinePause,
|
SwitchToTab5,
|
||||||
TimelineRefresh,
|
SwitchToTab6,
|
||||||
TimelineStart,
|
SwitchToTab7,
|
||||||
ToggleAdvancedIcons,
|
SwitchToTab8,
|
||||||
ToggleHidden,
|
TimelinePause,
|
||||||
}
|
TimelineRefresh,
|
||||||
|
TimelineStart,
|
||||||
|
ToggleAdvancedIcons,
|
||||||
|
ToggleHidden,
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Models
|
namespace FileTime.App.Core.Models;
|
||||||
|
|
||||||
|
public class BindedCollection<T> : IDisposable
|
||||||
{
|
{
|
||||||
public class BindedCollection<T> : IDisposable
|
private readonly IDisposable _disposable;
|
||||||
|
public ReadOnlyObservableCollection<T> Collection { get; }
|
||||||
|
public BindedCollection(IObservable<IChangeSet<T>> dynamicList)
|
||||||
{
|
{
|
||||||
private readonly IDisposable _disposable;
|
_disposable = dynamicList
|
||||||
public ReadOnlyObservableCollection<T> Collection { get; }
|
.Bind(out var collection)
|
||||||
public BindedCollection(IObservable<IChangeSet<T>> dynamicList)
|
.DisposeMany()
|
||||||
{
|
.Subscribe();
|
||||||
_disposable = dynamicList
|
|
||||||
.Bind(out var collection)
|
|
||||||
.DisposeMany()
|
|
||||||
.Subscribe();
|
|
||||||
|
|
||||||
Collection = collection;
|
Collection = collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_disposable.Dispose();
|
_disposable.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
namespace FileTime.App.Core.Models.Enums
|
namespace FileTime.App.Core.Models.Enums;
|
||||||
|
|
||||||
|
public enum ItemAttributeType
|
||||||
{
|
{
|
||||||
public enum ItemAttributeType
|
File,
|
||||||
{
|
Element,
|
||||||
File,
|
Container,
|
||||||
Element,
|
SizeContainer
|
||||||
Container,
|
|
||||||
SizeContainer
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace FileTime.App.Core.Models.Enums
|
namespace FileTime.App.Core.Models.Enums;
|
||||||
|
|
||||||
|
public enum ItemViewMode
|
||||||
{
|
{
|
||||||
public enum ItemViewMode
|
Default,
|
||||||
{
|
Alternative,
|
||||||
Default,
|
Selected,
|
||||||
Alternative,
|
Marked,
|
||||||
Selected,
|
MarkedSelected,
|
||||||
Marked,
|
MarkedAlternative
|
||||||
MarkedSelected,
|
|
||||||
MarkedAlternative
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace FileTime.App.Core.Models.Enums
|
namespace FileTime.App.Core.Models.Enums;
|
||||||
|
|
||||||
|
public enum ViewMode
|
||||||
{
|
{
|
||||||
public enum ViewMode
|
Default,
|
||||||
{
|
RapidTravel
|
||||||
Default,
|
|
||||||
RapidTravel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
namespace FileTime.App.Core.Models
|
namespace FileTime.App.Core.Models;
|
||||||
{
|
|
||||||
public class ItemNamePart
|
|
||||||
{
|
|
||||||
public string Text { get; set; }
|
|
||||||
public bool IsSpecial { get; set; }
|
|
||||||
|
|
||||||
public ItemNamePart(string text, bool isSpecial = false)
|
public class ItemNamePart
|
||||||
{
|
{
|
||||||
Text = text;
|
public string Text { get; set; }
|
||||||
IsSpecial = isSpecial;
|
public bool IsSpecial { get; set; }
|
||||||
}
|
|
||||||
|
public ItemNamePart(string text, bool isSpecial = false)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
IsSpecial = isSpecial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
{
|
|
||||||
public interface IClipboardService
|
|
||||||
{
|
|
||||||
Type? CommandType { get; }
|
|
||||||
IReadOnlyList<IAbsolutePath> Content { get; }
|
|
||||||
|
|
||||||
void AddContent(IAbsolutePath absolutePath);
|
public interface IClipboardService
|
||||||
void RemoveContent(IAbsolutePath absolutePath);
|
{
|
||||||
void Clear();
|
Type? CommandType { get; }
|
||||||
void SetCommand<T>() where T : ITransportationCommand;
|
IReadOnlyList<IAbsolutePath> Content { get; }
|
||||||
}
|
|
||||||
|
void AddContent(IAbsolutePath absolutePath);
|
||||||
|
void RemoveContent(IAbsolutePath absolutePath);
|
||||||
|
void Clear();
|
||||||
|
void SetCommand<T>() where T : ITransportationCommand;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using FileTime.App.Core.Command;
|
using FileTime.App.Core.Command;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public interface ICommandHandler
|
||||||
{
|
{
|
||||||
public interface ICommandHandler
|
bool CanHandleCommand(Commands command);
|
||||||
{
|
Task HandleCommandAsync(Commands command);
|
||||||
bool CanHandleCommand(Commands command);
|
|
||||||
Task HandleCommandAsync(Commands command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using FileTime.App.Core.Command;
|
using FileTime.App.Core.Command;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public interface ICommandHandlerService
|
||||||
{
|
{
|
||||||
public interface ICommandHandlerService
|
Task HandleCommandAsync(Commands command);
|
||||||
{
|
|
||||||
Task HandleCommandAsync(Commands command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
using FileTime.App.Core.Models;
|
using FileTime.App.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public interface IItemNameConverterService
|
||||||
{
|
{
|
||||||
public interface IItemNameConverterService
|
List<ItemNamePart> GetDisplayName(string name, string? searchText);
|
||||||
{
|
string GetFileExtension(string fullName);
|
||||||
List<ItemNamePart> GetDisplayName(string name, string? searchText);
|
string GetFileName(string fullName);
|
||||||
string GetFileExtension(string fullName);
|
|
||||||
string GetFileName(string fullName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System.Reactive.Concurrency;
|
using System.Reactive.Concurrency;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public interface IRxSchedulerService
|
||||||
{
|
{
|
||||||
public interface IRxSchedulerService
|
IScheduler GetWorkerScheduler();
|
||||||
{
|
IScheduler GetUIScheduler();
|
||||||
IScheduler GetWorkerScheduler();
|
|
||||||
IScheduler GetUIScheduler();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using FileTime.App.Core.Models.Enums;
|
using FileTime.App.Core.Models.Enums;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
{
|
|
||||||
public interface IAppState
|
|
||||||
{
|
|
||||||
ObservableCollection<ITabViewModel> Tabs { get; }
|
|
||||||
IObservable<ITabViewModel?> SelectedTab { get; }
|
|
||||||
IObservable<string?> SearchText { get; }
|
|
||||||
ViewMode ViewMode { get; }
|
|
||||||
|
|
||||||
void AddTab(ITabViewModel tabViewModel);
|
public interface IAppState
|
||||||
void RemoveTab(ITabViewModel tabViewModel);
|
{
|
||||||
void SetSearchText(string? searchText);
|
ObservableCollection<ITabViewModel> Tabs { get; }
|
||||||
}
|
IObservable<ITabViewModel?> SelectedTab { get; }
|
||||||
|
IObservable<string?> SearchText { get; }
|
||||||
|
ViewMode ViewMode { get; }
|
||||||
|
|
||||||
|
void AddTab(ITabViewModel tabViewModel);
|
||||||
|
void RemoveTab(ITabViewModel tabViewModel);
|
||||||
|
void SetSearchText(string? searchText);
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
public interface IContainerSizeContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel>
|
||||||
{
|
{
|
||||||
public interface IContainerSizeContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel>
|
long Size { get; set; }
|
||||||
{
|
|
||||||
long Size { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
public interface IContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel>
|
||||||
{
|
{
|
||||||
public interface IContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel>
|
IContainer? Container { get; }
|
||||||
{
|
|
||||||
IContainer? Container { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
public interface IElementViewModel : IItemViewModel, IInitable<IElement, ITabViewModel>
|
||||||
{
|
{
|
||||||
public interface IElementViewModel : IItemViewModel, IInitable<IElement, ITabViewModel>
|
long? Size { get; set; }
|
||||||
{
|
|
||||||
long? Size { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
public interface IFileViewModel : IElementViewModel, IInitable<IFileElement, ITabViewModel>
|
||||||
{
|
{
|
||||||
public interface IFileViewModel : IElementViewModel, IInitable<IFileElement, ITabViewModel>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,19 +3,18 @@ using FileTime.App.Core.Models.Enums;
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
public interface IItemViewModel : IInitable<IItem, ITabViewModel>
|
||||||
{
|
{
|
||||||
public interface IItemViewModel : IInitable<IItem, ITabViewModel>
|
IItem? BaseItem { get; set; }
|
||||||
{
|
IObservable<IReadOnlyList<ItemNamePart>>? DisplayName { get; set; }
|
||||||
IItem? BaseItem { get; set; }
|
string? DisplayNameText { get; set; }
|
||||||
IObservable<IReadOnlyList<ItemNamePart>>? DisplayName { get; set; }
|
IObservable<bool>? IsSelected { get; set; }
|
||||||
string? DisplayNameText { get; set; }
|
IObservable<bool>? IsMarked { get; set; }
|
||||||
IObservable<bool>? IsSelected { get; set; }
|
IObservable<bool> IsAlternative { get; }
|
||||||
IObservable<bool>? IsMarked { get; set; }
|
IObservable<ItemViewMode> ViewMode { get; set; }
|
||||||
IObservable<bool> IsAlternative { get; }
|
DateTime? CreatedAt { get; set; }
|
||||||
IObservable<ItemViewMode> ViewMode { get; set; }
|
string? Attributes { get; set; }
|
||||||
DateTime? CreatedAt { get; set; }
|
bool EqualsTo(IItemViewModel? itemViewModel);
|
||||||
string? Attributes { get; set; }
|
|
||||||
bool EqualsTo(IItemViewModel? itemViewModel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,26 +5,25 @@ using FileTime.Core.Models;
|
|||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
public interface ITabViewModel : IInitable<ITab, int>
|
||||||
{
|
{
|
||||||
public interface ITabViewModel : IInitable<ITab, int>
|
ITab? Tab { get; }
|
||||||
{
|
int TabNumber { get; }
|
||||||
ITab? Tab { get; }
|
IObservable<bool> IsSelected { get; }
|
||||||
int TabNumber { get; }
|
IObservable<IContainer?> CurrentLocation { get; }
|
||||||
IObservable<bool> IsSelected { get; }
|
IObservable<IItemViewModel?> CurrentSelectedItem { get; }
|
||||||
IObservable<IContainer?> CurrentLocation { get; }
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; }
|
||||||
IObservable<IItemViewModel?> CurrentSelectedItem { get; }
|
IObservable<IChangeSet<IAbsolutePath>> MarkedItems { get; }
|
||||||
IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; }
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; }
|
||||||
IObservable<IChangeSet<IAbsolutePath>> MarkedItems { get; }
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; }
|
||||||
IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; }
|
BindedCollection<IItemViewModel>? CurrentItemsCollection { get; }
|
||||||
IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; }
|
BindedCollection<IItemViewModel>? SelectedsChildrenCollection { get; }
|
||||||
BindedCollection<IItemViewModel>? CurrentItemsCollection { get; }
|
BindedCollection<IItemViewModel>? ParentsChildrenCollection { get; }
|
||||||
BindedCollection<IItemViewModel>? SelectedsChildrenCollection { get; }
|
IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; }
|
||||||
BindedCollection<IItemViewModel>? ParentsChildrenCollection { get; }
|
void ClearMarkedItems();
|
||||||
IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; }
|
void RemoveMarkedItem(IAbsolutePath item);
|
||||||
void ClearMarkedItems();
|
void AddMarkedItem(IAbsolutePath item);
|
||||||
void RemoveMarkedItem(IAbsolutePath item);
|
void ToggleMarkedItem(IAbsolutePath item);
|
||||||
void AddMarkedItem(IAbsolutePath item);
|
|
||||||
void ToggleMarkedItem(IAbsolutePath item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Extensions
|
namespace FileTime.App.Core.Extensions;
|
||||||
|
|
||||||
|
public static class ObservableExtensions
|
||||||
{
|
{
|
||||||
public static class ObservableExtensions
|
public static IObservable<T> WhereNotNull<T>(this IObservable<T?> source) => source.Where(c => c != null)!;
|
||||||
{
|
|
||||||
public static IObservable<T> WhereNotNull<T>(this IObservable<T?> source) => source.Where(c => c != null)!;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Extensions
|
namespace FileTime.App.Core.Extensions;
|
||||||
|
|
||||||
|
public static class ViewModelExtensions
|
||||||
{
|
{
|
||||||
public static class ViewModelExtensions
|
public static IAbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel)
|
||||||
{
|
{
|
||||||
public static IAbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel)
|
var item = itemViewModel.BaseItem ?? throw new ArgumentException($"{nameof(itemViewModel)} does not have {nameof(IItemViewModel.BaseItem)}");
|
||||||
{
|
return new AbsolutePath(item);
|
||||||
var item = itemViewModel.BaseItem ?? throw new ArgumentException($"{nameof(itemViewModel)} does not have {nameof(IItemViewModel.BaseItem)}");
|
|
||||||
return new AbsolutePath(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="morelinq" Version="3.3.2" />
|
<PackageReference Include="morelinq" Version="3.3.2" />
|
||||||
<PackageReference Include="MvvmGen" Version="1.1.5" />
|
<PackageReference Include="MvvmGen" Version="1.1.5" />
|
||||||
|
|||||||
@@ -1,51 +1,50 @@
|
|||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public class ClipboardService : IClipboardService
|
||||||
{
|
{
|
||||||
public class ClipboardService : IClipboardService
|
private List<IAbsolutePath> _content;
|
||||||
|
public IReadOnlyList<IAbsolutePath> Content { get; private set; }
|
||||||
|
public Type? CommandType { get; private set; }
|
||||||
|
|
||||||
|
public ClipboardService()
|
||||||
{
|
{
|
||||||
private List<IAbsolutePath> _content;
|
_content = new List<IAbsolutePath>();
|
||||||
public IReadOnlyList<IAbsolutePath> Content { get; private set; }
|
Content = _content.AsReadOnly();
|
||||||
public Type? CommandType { get; private set; }
|
}
|
||||||
|
|
||||||
public ClipboardService()
|
public void AddContent(IAbsolutePath absolutePath)
|
||||||
|
{
|
||||||
|
foreach (var content in _content)
|
||||||
{
|
{
|
||||||
_content = new List<IAbsolutePath>();
|
if (content.Equals(absolutePath)) return;
|
||||||
Content = _content.AsReadOnly();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddContent(IAbsolutePath absolutePath)
|
_content.Add(absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveContent(IAbsolutePath absolutePath)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _content.Count; i++)
|
||||||
{
|
{
|
||||||
foreach (var content in _content)
|
if (_content[i].Equals(absolutePath))
|
||||||
{
|
{
|
||||||
if (content.Equals(absolutePath)) return;
|
_content.RemoveAt(i--);
|
||||||
}
|
}
|
||||||
|
|
||||||
_content.Add(absolutePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveContent(IAbsolutePath absolutePath)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < _content.Count; i++)
|
|
||||||
{
|
|
||||||
if (_content[i].Equals(absolutePath))
|
|
||||||
{
|
|
||||||
_content.RemoveAt(i--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_content = new List<IAbsolutePath>();
|
|
||||||
Content = _content.AsReadOnly();
|
|
||||||
CommandType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCommand<T>() where T : ITransportationCommand
|
|
||||||
{
|
|
||||||
CommandType = typeof(T);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_content = new List<IAbsolutePath>();
|
||||||
|
Content = _content.AsReadOnly();
|
||||||
|
CommandType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCommand<T>() where T : ITransportationCommand
|
||||||
|
{
|
||||||
|
CommandType = typeof(T);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,51 +4,50 @@ using FileTime.App.Core.Command;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services.CommandHandler
|
namespace FileTime.App.Core.Services.CommandHandler;
|
||||||
|
|
||||||
|
public abstract class CommandHandlerBase : ICommandHandler
|
||||||
{
|
{
|
||||||
public abstract class CommandHandlerBase : ICommandHandler
|
private readonly Dictionary<Commands, Func<Task>> _commandHandlers = new();
|
||||||
|
private readonly IAppState? _appState;
|
||||||
|
|
||||||
|
protected CommandHandlerBase(IAppState? appState = null)
|
||||||
{
|
{
|
||||||
private readonly Dictionary<Commands, Func<Task>> _commandHandlers = new();
|
_appState = appState;
|
||||||
private readonly IAppState? _appState;
|
}
|
||||||
|
|
||||||
protected CommandHandlerBase(IAppState? appState = null)
|
public bool CanHandleCommand(Commands command) => _commandHandlers.ContainsKey(command);
|
||||||
|
|
||||||
|
public async Task HandleCommandAsync(Commands command) => await _commandHandlers[command].Invoke();
|
||||||
|
|
||||||
|
protected void AddCommandHandler(Commands command, Func<Task> handler) => _commandHandlers.Add(command, handler);
|
||||||
|
protected void AddCommandHandlers(IEnumerable<(Commands command, Func<Task> handler)> commandHandlers)
|
||||||
|
{
|
||||||
|
foreach (var (command, handler) in commandHandlers)
|
||||||
{
|
{
|
||||||
_appState = appState;
|
AddCommandHandler(command, handler);
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanHandleCommand(Commands command) => _commandHandlers.ContainsKey(command);
|
|
||||||
|
|
||||||
public async Task HandleCommandAsync(Commands command) => await _commandHandlers[command].Invoke();
|
|
||||||
|
|
||||||
protected void AddCommandHandler(Commands command, Func<Task> handler) => _commandHandlers.Add(command, handler);
|
|
||||||
protected void AddCommandHandlers(IEnumerable<(Commands command, Func<Task> handler)> commandHandlers)
|
|
||||||
{
|
|
||||||
foreach (var (command, handler) in commandHandlers)
|
|
||||||
{
|
|
||||||
AddCommandHandler(command, handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void RemoveCommandHandler(Commands command) => _commandHandlers.Remove(command);
|
|
||||||
|
|
||||||
protected IDisposable SaveSelectedTab(Action<ITabViewModel?> handler) => RunWithAppState(appState => appState.SelectedTab.Subscribe(handler));
|
|
||||||
protected IDisposable SaveCurrentSelectedItem(Action<IItemViewModel?> handler)
|
|
||||||
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t == null ? Observable.Return<IItemViewModel?>(null) : t.CurrentSelectedItem).Switch().Subscribe(handler));
|
|
||||||
|
|
||||||
protected IDisposable SaveCurrentLocation(Action<IContainer?> handler)
|
|
||||||
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation).Switch().Subscribe(handler));
|
|
||||||
|
|
||||||
protected IDisposable SaveCurrentItems(Action<IEnumerable<IItemViewModel>> handler)
|
|
||||||
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t?.CurrentItemsCollectionObservable ?? Observable.Return((IEnumerable<IItemViewModel>?)Enumerable.Empty<IItemViewModel>())).Switch().Subscribe(i => handler(i ?? Enumerable.Empty<IItemViewModel>())));
|
|
||||||
|
|
||||||
protected IDisposable SaveMarkedItems(Action<IChangeSet<IAbsolutePath>> handler)
|
|
||||||
=> RunWithAppState(appstate => appstate.SelectedTab.Select(t => t == null ? Observable.Empty<IChangeSet<IAbsolutePath>>() : t.MarkedItems).Switch().Subscribe(handler));
|
|
||||||
|
|
||||||
private IDisposable RunWithAppState(Func<IAppState, IDisposable> act)
|
|
||||||
{
|
|
||||||
if (_appState == null) throw new NullReferenceException($"AppState is nit initialized in {nameof(CommandHandlerBase)}.");
|
|
||||||
|
|
||||||
return act(_appState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void RemoveCommandHandler(Commands command) => _commandHandlers.Remove(command);
|
||||||
|
|
||||||
|
protected IDisposable SaveSelectedTab(Action<ITabViewModel?> handler) => RunWithAppState(appState => appState.SelectedTab.Subscribe(handler));
|
||||||
|
protected IDisposable SaveCurrentSelectedItem(Action<IItemViewModel?> handler)
|
||||||
|
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t == null ? Observable.Return<IItemViewModel?>(null) : t.CurrentSelectedItem).Switch().Subscribe(handler));
|
||||||
|
|
||||||
|
protected IDisposable SaveCurrentLocation(Action<IContainer?> handler)
|
||||||
|
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation).Switch().Subscribe(handler));
|
||||||
|
|
||||||
|
protected IDisposable SaveCurrentItems(Action<IEnumerable<IItemViewModel>> handler)
|
||||||
|
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t?.CurrentItemsCollectionObservable ?? Observable.Return((IEnumerable<IItemViewModel>?)Enumerable.Empty<IItemViewModel>())).Switch().Subscribe(i => handler(i ?? Enumerable.Empty<IItemViewModel>())));
|
||||||
|
|
||||||
|
protected IDisposable SaveMarkedItems(Action<IChangeSet<IAbsolutePath>> handler)
|
||||||
|
=> RunWithAppState(appstate => appstate.SelectedTab.Select(t => t == null ? Observable.Empty<IChangeSet<IAbsolutePath>>() : t.MarkedItems).Switch().Subscribe(handler));
|
||||||
|
|
||||||
|
private IDisposable RunWithAppState(Func<IAppState, IDisposable> act)
|
||||||
|
{
|
||||||
|
if (_appState == null) throw new NullReferenceException($"AppState is nit initialized in {nameof(CommandHandlerBase)}.");
|
||||||
|
|
||||||
|
return act(_appState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,91 +6,90 @@ using FileTime.Core.Command;
|
|||||||
using FileTime.Core.Command.Copy;
|
using FileTime.Core.Command.Copy;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services.CommandHandler
|
namespace FileTime.App.Core.Services.CommandHandler;
|
||||||
|
|
||||||
|
public class ItemManipulationCommandHandler : CommandHandlerBase
|
||||||
{
|
{
|
||||||
public class ItemManipulationCommandHandler : CommandHandlerBase
|
private ITabViewModel? _selectedTab;
|
||||||
|
private IItemViewModel? _currentSelectedItem;
|
||||||
|
private readonly ICommandHandlerService _commandHandlerService;
|
||||||
|
private readonly IClipboardService _clipboardService;
|
||||||
|
private BindedCollection<IAbsolutePath>? _markedItems;
|
||||||
|
|
||||||
|
public ItemManipulationCommandHandler(
|
||||||
|
IAppState appState,
|
||||||
|
ICommandHandlerService commandHandlerService,
|
||||||
|
IClipboardService clipboardService) : base(appState)
|
||||||
{
|
{
|
||||||
private ITabViewModel? _selectedTab;
|
_commandHandlerService = commandHandlerService;
|
||||||
private IItemViewModel? _currentSelectedItem;
|
_clipboardService = clipboardService;
|
||||||
private readonly ICommandHandlerService _commandHandlerService;
|
|
||||||
private readonly IClipboardService _clipboardService;
|
|
||||||
private BindedCollection<IAbsolutePath>? _markedItems;
|
|
||||||
|
|
||||||
public ItemManipulationCommandHandler(
|
SaveSelectedTab(t =>
|
||||||
IAppState appState,
|
|
||||||
ICommandHandlerService commandHandlerService,
|
|
||||||
IClipboardService clipboardService) : base(appState)
|
|
||||||
{
|
{
|
||||||
_commandHandlerService = commandHandlerService;
|
_selectedTab = t;
|
||||||
_clipboardService = clipboardService;
|
_markedItems?.Dispose();
|
||||||
|
_markedItems = t == null ? null : new BindedCollection<IAbsolutePath>(t.MarkedItems);
|
||||||
|
});
|
||||||
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
|
|
||||||
SaveSelectedTab(t =>
|
AddCommandHandlers(new (Commands, Func<Task>)[]
|
||||||
{
|
|
||||||
_selectedTab = t;
|
|
||||||
_markedItems?.Dispose();
|
|
||||||
_markedItems = t == null ? null : new BindedCollection<IAbsolutePath>(t.MarkedItems);
|
|
||||||
});
|
|
||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
|
||||||
|
|
||||||
AddCommandHandlers(new (Commands, Func<Task>)[]
|
|
||||||
{
|
|
||||||
(Commands.Copy, Copy),
|
|
||||||
(Commands.Mark, MarkItem),
|
|
||||||
(Commands.PasteMerge, PasteMerge),
|
|
||||||
(Commands.PasteOverwrite, PasteOverwrite),
|
|
||||||
(Commands.PasteSkip, PasteSkip),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task MarkItem()
|
|
||||||
{
|
{
|
||||||
if (_selectedTab == null || _currentSelectedItem?.BaseItem?.FullName == null) return;
|
(Commands.Copy, Copy),
|
||||||
|
(Commands.Mark, MarkItem),
|
||||||
|
(Commands.PasteMerge, PasteMerge),
|
||||||
|
(Commands.PasteOverwrite, PasteOverwrite),
|
||||||
|
(Commands.PasteSkip, PasteSkip),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_selectedTab.ToggleMarkedItem(new AbsolutePath(_currentSelectedItem.BaseItem));
|
private async Task MarkItem()
|
||||||
await _commandHandlerService.HandleCommandAsync(Commands.MoveCursorDown);
|
{
|
||||||
}
|
if (_selectedTab == null || _currentSelectedItem?.BaseItem?.FullName == null) return;
|
||||||
|
|
||||||
private Task Copy()
|
_selectedTab.ToggleMarkedItem(new AbsolutePath(_currentSelectedItem.BaseItem));
|
||||||
|
await _commandHandlerService.HandleCommandAsync(Commands.MoveCursorDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Copy()
|
||||||
|
{
|
||||||
|
_clipboardService.Clear();
|
||||||
|
_clipboardService.SetCommand<CopyCommand>();
|
||||||
|
|
||||||
|
if ((_markedItems?.Collection.Count ?? 0) > 0)
|
||||||
{
|
{
|
||||||
_clipboardService.Clear();
|
foreach (var item in _markedItems!.Collection)
|
||||||
_clipboardService.SetCommand<CopyCommand>();
|
|
||||||
|
|
||||||
if ((_markedItems?.Collection.Count ?? 0) > 0)
|
|
||||||
{
|
{
|
||||||
foreach (var item in _markedItems!.Collection)
|
_clipboardService.AddContent(item);
|
||||||
{
|
|
||||||
_clipboardService.AddContent(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
_selectedTab?.ClearMarkedItems();
|
|
||||||
}
|
|
||||||
else if (_currentSelectedItem?.BaseItem != null)
|
|
||||||
{
|
|
||||||
_clipboardService.AddContent(new AbsolutePath(_currentSelectedItem.BaseItem));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
_selectedTab?.ClearMarkedItems();
|
||||||
|
}
|
||||||
|
else if (_currentSelectedItem?.BaseItem != null)
|
||||||
|
{
|
||||||
|
_clipboardService.AddContent(new AbsolutePath(_currentSelectedItem.BaseItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PasteMerge()
|
return Task.CompletedTask;
|
||||||
{
|
}
|
||||||
await Paste(TransportMode.Merge);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PasteOverwrite()
|
private async Task PasteMerge()
|
||||||
{
|
{
|
||||||
await Paste(TransportMode.Overwrite);
|
await Paste(TransportMode.Merge);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PasteSkip()
|
private async Task PasteOverwrite()
|
||||||
{
|
{
|
||||||
await Paste(TransportMode.Skip);
|
await Paste(TransportMode.Overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Paste(TransportMode skip)
|
private async Task PasteSkip()
|
||||||
{
|
{
|
||||||
if (_clipboardService.CommandType is null) return Task.CompletedTask;
|
await Paste(TransportMode.Skip);
|
||||||
return Task.CompletedTask;
|
}
|
||||||
}
|
|
||||||
|
private Task Paste(TransportMode skip)
|
||||||
|
{
|
||||||
|
if (_clipboardService.CommandType is null) return Task.CompletedTask;
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,65 +4,64 @@ using FileTime.App.Core.Extensions;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services.CommandHandler
|
namespace FileTime.App.Core.Services.CommandHandler;
|
||||||
|
|
||||||
|
public class NavigationCommandHandler : CommandHandlerBase
|
||||||
{
|
{
|
||||||
public class NavigationCommandHandler : CommandHandlerBase
|
private ITabViewModel? _selectedTab;
|
||||||
|
private IContainer? _currentLocation;
|
||||||
|
private IItemViewModel? _currentSelectedItem;
|
||||||
|
private IEnumerable<IItemViewModel> _currentItems = Enumerable.Empty<IItemViewModel>();
|
||||||
|
|
||||||
|
public NavigationCommandHandler(IAppState appState) : base(appState)
|
||||||
{
|
{
|
||||||
private ITabViewModel? _selectedTab;
|
SaveSelectedTab(t => _selectedTab = t);
|
||||||
private IContainer? _currentLocation;
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
private IItemViewModel? _currentSelectedItem;
|
SaveCurrentLocation(l => _currentLocation = l);
|
||||||
private IEnumerable<IItemViewModel> _currentItems = Enumerable.Empty<IItemViewModel>();
|
SaveCurrentItems(i => _currentItems = i);
|
||||||
|
|
||||||
public NavigationCommandHandler(IAppState appState) : base(appState)
|
AddCommandHandlers(new (Commands, Func<Task>)[]
|
||||||
{
|
{
|
||||||
SaveSelectedTab(t => _selectedTab = t);
|
(Commands.GoUp, GoUp),
|
||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
(Commands.MoveCursorDown, MoveCursorDown),
|
||||||
SaveCurrentLocation(l => _currentLocation = l);
|
(Commands.MoveCursorUp, MoveCursorUp),
|
||||||
SaveCurrentItems(i => _currentItems = i);
|
(Commands.Open, OpenContainer),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
AddCommandHandlers(new (Commands, Func<Task>)[]
|
private Task OpenContainer()
|
||||||
{
|
{
|
||||||
(Commands.GoUp, GoUp),
|
if (_currentSelectedItem is not IContainerViewModel containerViewModel || containerViewModel.Container is null) return Task.CompletedTask;
|
||||||
(Commands.MoveCursorDown, MoveCursorDown),
|
|
||||||
(Commands.MoveCursorUp, MoveCursorUp),
|
|
||||||
(Commands.Open, OpenContainer),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task OpenContainer()
|
_selectedTab?.Tab?.SetCurrentLocation(containerViewModel.Container);
|
||||||
{
|
return Task.CompletedTask;
|
||||||
if (_currentSelectedItem is not IContainerViewModel containerViewModel || containerViewModel.Container is null) return Task.CompletedTask;
|
}
|
||||||
|
|
||||||
_selectedTab?.Tab?.SetCurrentLocation(containerViewModel.Container);
|
private async Task GoUp()
|
||||||
return Task.CompletedTask;
|
{
|
||||||
}
|
if (_currentLocation?.Parent is not IAbsolutePath parentPath || await parentPath.ResolveAsyncSafe() is not IContainer newContainer) return;
|
||||||
|
_selectedTab?.Tab?.SetCurrentLocation(newContainer);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task GoUp()
|
private Task MoveCursorDown()
|
||||||
{
|
{
|
||||||
if (_currentLocation?.Parent is not IAbsolutePath parentPath || await parentPath.ResolveAsyncSafe() is not IContainer newContainer) return;
|
SelectNewSelectedItem(i => i.SkipWhile(i => !i.EqualsTo(_currentSelectedItem)).Skip(1).FirstOrDefault());
|
||||||
_selectedTab?.Tab?.SetCurrentLocation(newContainer);
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task MoveCursorDown()
|
private Task MoveCursorUp()
|
||||||
{
|
{
|
||||||
SelectNewSelectedItem(i => i.SkipWhile(i => !i.EqualsTo(_currentSelectedItem)).Skip(1).FirstOrDefault());
|
SelectNewSelectedItem(i => i.TakeWhile(i => !i.EqualsTo(_currentSelectedItem)).LastOrDefault());
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task MoveCursorUp()
|
private void SelectNewSelectedItem(Func<IEnumerable<IItemViewModel>, IItemViewModel?> getNewSelected)
|
||||||
{
|
{
|
||||||
SelectNewSelectedItem(i => i.TakeWhile(i => !i.EqualsTo(_currentSelectedItem)).LastOrDefault());
|
if (_selectedTab is null || _currentLocation is null) return;
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SelectNewSelectedItem(Func<IEnumerable<IItemViewModel>, IItemViewModel?> getNewSelected)
|
var newSelectedItem = getNewSelected(_currentItems);
|
||||||
{
|
if (newSelectedItem == null) return;
|
||||||
if (_selectedTab is null || _currentLocation is null) return;
|
|
||||||
|
|
||||||
var newSelectedItem = getNewSelected(_currentItems);
|
_selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath());
|
||||||
if (newSelectedItem == null) return;
|
|
||||||
|
|
||||||
_selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,80 +1,79 @@
|
|||||||
using FileTime.App.Core.Command;
|
using FileTime.App.Core.Command;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public class CommandHandlerService : ICommandHandlerService
|
||||||
{
|
{
|
||||||
public class CommandHandlerService : ICommandHandlerService
|
private readonly Lazy<IEnumerable<ICommandHandler>> _commandHandlers;
|
||||||
|
|
||||||
|
public CommandHandlerService(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
private readonly Lazy<IEnumerable<ICommandHandler>> _commandHandlers;
|
_commandHandlers = new Lazy<IEnumerable<ICommandHandler>>(() => serviceProvider.GetServices<ICommandHandler>());
|
||||||
|
|
||||||
public CommandHandlerService(IServiceProvider serviceProvider)
|
//(Commands.AutoRefresh, ToggleAutoRefresh),
|
||||||
|
//(Commands.ChangeTimelineMode, ChangeTimelineMode),
|
||||||
|
//(Commands.CloseTab, CloseTab),
|
||||||
|
//(Commands.Compress, Compress),
|
||||||
|
//(Commands.Copy, Copy),
|
||||||
|
//(Commands.CopyHash, CopyHash),
|
||||||
|
//(Commands.CopyPath, CopyPath),
|
||||||
|
//(Commands.CreateContainer, CreateContainer),
|
||||||
|
//(Commands.CreateElement, CreateElement),
|
||||||
|
//(Commands.Cut, Cut),
|
||||||
|
//(Commands.Edit, Edit),
|
||||||
|
//(Commands.EnterRapidTravel, EnterRapidTravelMode),
|
||||||
|
//(Commands.FindByName, FindByName),
|
||||||
|
//(Commands.FindByNameRegex, FindByNameRegex),
|
||||||
|
//(Commands.GoToHome, GotToHome),
|
||||||
|
//(Commands.GoToPath, GoToContainer),
|
||||||
|
//(Commands.GoToProvider, GotToProvider),
|
||||||
|
//(Commands.GoToRoot, GotToRoot),
|
||||||
|
//(Commands.HardDelete, HardDelete),
|
||||||
|
//(Commands.Mark, MarkCurrentItem),
|
||||||
|
//(Commands.MoveCursorDownPage, MoveCursorDownPage),
|
||||||
|
//(Commands.MoveCursorUpPage, MoveCursorUpPage),
|
||||||
|
//(Commands.MoveToFirst, MoveToFirst),
|
||||||
|
//(Commands.MoveToLast, MoveToLast),
|
||||||
|
//(Commands.NextTimelineBlock, SelectNextTimelineBlock),
|
||||||
|
//(Commands.NextTimelineCommand, SelectNextTimelineCommand),
|
||||||
|
//(Commands.OpenInFileBrowser, OpenInDefaultFileExplorer),
|
||||||
|
//(Commands.OpenOrRun, OpenOrRun),
|
||||||
|
//(Commands.PasteMerge, PasteMerge),
|
||||||
|
//(Commands.PasteOverwrite, PasteOverwrite),
|
||||||
|
//(Commands.PasteSkip, PasteSkip),
|
||||||
|
//(Commands.PinFavorite, PinFavorite),
|
||||||
|
//(Commands.PreviousTimelineBlock, SelectPreviousTimelineBlock),
|
||||||
|
//(Commands.PreviousTimelineCommand, SelectPreviousTimelineCommand),
|
||||||
|
//(Commands.Refresh, RefreshCurrentLocation),
|
||||||
|
//(Commands.Rename, Rename),
|
||||||
|
//(Commands.RunCommand, RunCommandInContainer),
|
||||||
|
//(Commands.ScanContainerSize, ScanContainerSize),
|
||||||
|
//(Commands.ShowAllShotcut, ShowAllShortcut),
|
||||||
|
//(Commands.SoftDelete, SoftDelete),
|
||||||
|
//(Commands.SwitchToLastTab, async() => await SwitchToTab(-1)),
|
||||||
|
//(Commands.SwitchToTab1, async() => await SwitchToTab(1)),
|
||||||
|
//(Commands.SwitchToTab2, async() => await SwitchToTab(2)),
|
||||||
|
//(Commands.SwitchToTab3, async() => await SwitchToTab(3)),
|
||||||
|
//(Commands.SwitchToTab4, async() => await SwitchToTab(4)),
|
||||||
|
//(Commands.SwitchToTab5, async() => await SwitchToTab(5)),
|
||||||
|
//(Commands.SwitchToTab6, async() => await SwitchToTab(6)),
|
||||||
|
//(Commands.SwitchToTab7, async() => await SwitchToTab(7)),
|
||||||
|
//(Commands.SwitchToTab8, async() => await SwitchToTab(8)),
|
||||||
|
//(Commands.TimelinePause, PauseTimeline),
|
||||||
|
//(Commands.TimelineRefresh, RefreshTimeline),
|
||||||
|
//(Commands.TimelineStart, ContinueTimeline),
|
||||||
|
//(Commands.ToggleAdvancedIcons, ToggleAdvancedIcons),
|
||||||
|
//(Commands.ToggleHidden, ToggleHidden),
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleCommandAsync(Commands command)
|
||||||
|
{
|
||||||
|
var handler = _commandHandlers.Value.FirstOrDefault(h => h.CanHandleCommand(command));
|
||||||
|
|
||||||
|
if (handler != null)
|
||||||
{
|
{
|
||||||
_commandHandlers = new Lazy<IEnumerable<ICommandHandler>>(() => serviceProvider.GetServices<ICommandHandler>());
|
await handler.HandleCommandAsync(command);
|
||||||
|
|
||||||
//(Commands.AutoRefresh, ToggleAutoRefresh),
|
|
||||||
//(Commands.ChangeTimelineMode, ChangeTimelineMode),
|
|
||||||
//(Commands.CloseTab, CloseTab),
|
|
||||||
//(Commands.Compress, Compress),
|
|
||||||
//(Commands.Copy, Copy),
|
|
||||||
//(Commands.CopyHash, CopyHash),
|
|
||||||
//(Commands.CopyPath, CopyPath),
|
|
||||||
//(Commands.CreateContainer, CreateContainer),
|
|
||||||
//(Commands.CreateElement, CreateElement),
|
|
||||||
//(Commands.Cut, Cut),
|
|
||||||
//(Commands.Edit, Edit),
|
|
||||||
//(Commands.EnterRapidTravel, EnterRapidTravelMode),
|
|
||||||
//(Commands.FindByName, FindByName),
|
|
||||||
//(Commands.FindByNameRegex, FindByNameRegex),
|
|
||||||
//(Commands.GoToHome, GotToHome),
|
|
||||||
//(Commands.GoToPath, GoToContainer),
|
|
||||||
//(Commands.GoToProvider, GotToProvider),
|
|
||||||
//(Commands.GoToRoot, GotToRoot),
|
|
||||||
//(Commands.HardDelete, HardDelete),
|
|
||||||
//(Commands.Mark, MarkCurrentItem),
|
|
||||||
//(Commands.MoveCursorDownPage, MoveCursorDownPage),
|
|
||||||
//(Commands.MoveCursorUpPage, MoveCursorUpPage),
|
|
||||||
//(Commands.MoveToFirst, MoveToFirst),
|
|
||||||
//(Commands.MoveToLast, MoveToLast),
|
|
||||||
//(Commands.NextTimelineBlock, SelectNextTimelineBlock),
|
|
||||||
//(Commands.NextTimelineCommand, SelectNextTimelineCommand),
|
|
||||||
//(Commands.OpenInFileBrowser, OpenInDefaultFileExplorer),
|
|
||||||
//(Commands.OpenOrRun, OpenOrRun),
|
|
||||||
//(Commands.PasteMerge, PasteMerge),
|
|
||||||
//(Commands.PasteOverwrite, PasteOverwrite),
|
|
||||||
//(Commands.PasteSkip, PasteSkip),
|
|
||||||
//(Commands.PinFavorite, PinFavorite),
|
|
||||||
//(Commands.PreviousTimelineBlock, SelectPreviousTimelineBlock),
|
|
||||||
//(Commands.PreviousTimelineCommand, SelectPreviousTimelineCommand),
|
|
||||||
//(Commands.Refresh, RefreshCurrentLocation),
|
|
||||||
//(Commands.Rename, Rename),
|
|
||||||
//(Commands.RunCommand, RunCommandInContainer),
|
|
||||||
//(Commands.ScanContainerSize, ScanContainerSize),
|
|
||||||
//(Commands.ShowAllShotcut, ShowAllShortcut),
|
|
||||||
//(Commands.SoftDelete, SoftDelete),
|
|
||||||
//(Commands.SwitchToLastTab, async() => await SwitchToTab(-1)),
|
|
||||||
//(Commands.SwitchToTab1, async() => await SwitchToTab(1)),
|
|
||||||
//(Commands.SwitchToTab2, async() => await SwitchToTab(2)),
|
|
||||||
//(Commands.SwitchToTab3, async() => await SwitchToTab(3)),
|
|
||||||
//(Commands.SwitchToTab4, async() => await SwitchToTab(4)),
|
|
||||||
//(Commands.SwitchToTab5, async() => await SwitchToTab(5)),
|
|
||||||
//(Commands.SwitchToTab6, async() => await SwitchToTab(6)),
|
|
||||||
//(Commands.SwitchToTab7, async() => await SwitchToTab(7)),
|
|
||||||
//(Commands.SwitchToTab8, async() => await SwitchToTab(8)),
|
|
||||||
//(Commands.TimelinePause, PauseTimeline),
|
|
||||||
//(Commands.TimelineRefresh, RefreshTimeline),
|
|
||||||
//(Commands.TimelineStart, ContinueTimeline),
|
|
||||||
//(Commands.ToggleAdvancedIcons, ToggleAdvancedIcons),
|
|
||||||
//(Commands.ToggleHidden, ToggleHidden),
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task HandleCommandAsync(Commands command)
|
|
||||||
{
|
|
||||||
var handler = _commandHandlers.Value.FirstOrDefault(h => h.CanHandleCommand(command));
|
|
||||||
|
|
||||||
if (handler != null)
|
|
||||||
{
|
|
||||||
await handler.HandleCommandAsync(command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,56 +1,55 @@
|
|||||||
using FileTime.App.Core.Models;
|
using FileTime.App.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public class ItemNameConverterService : IItemNameConverterService
|
||||||
{
|
{
|
||||||
public class ItemNameConverterService : IItemNameConverterService
|
public List<ItemNamePart> GetDisplayName(string name, string? searchText)
|
||||||
{
|
{
|
||||||
public List<ItemNamePart> GetDisplayName(string name, string? searchText)
|
var nameParts = new List<ItemNamePart>();
|
||||||
|
searchText = searchText?.ToLower();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(searchText))
|
||||||
{
|
{
|
||||||
var nameParts = new List<ItemNamePart>();
|
var nameLeft = name;
|
||||||
searchText = searchText?.ToLower();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(searchText))
|
while (nameLeft.ToLower().IndexOf(searchText, StringComparison.Ordinal) is int rapidTextStart && rapidTextStart != -1)
|
||||||
{
|
{
|
||||||
var nameLeft = name;
|
var before = rapidTextStart > 0 ? nameLeft.Substring(0, rapidTextStart) : null;
|
||||||
|
var rapidTravel = nameLeft.Substring(rapidTextStart, searchText.Length);
|
||||||
|
|
||||||
while (nameLeft.ToLower().IndexOf(searchText, StringComparison.Ordinal) is int rapidTextStart && rapidTextStart != -1)
|
nameLeft = nameLeft.Substring(rapidTextStart + searchText.Length);
|
||||||
|
|
||||||
|
if (before != null)
|
||||||
{
|
{
|
||||||
var before = rapidTextStart > 0 ? nameLeft.Substring(0, rapidTextStart) : null;
|
nameParts.Add(new ItemNamePart(before));
|
||||||
var rapidTravel = nameLeft.Substring(rapidTextStart, searchText.Length);
|
|
||||||
|
|
||||||
nameLeft = nameLeft.Substring(rapidTextStart + searchText.Length);
|
|
||||||
|
|
||||||
if (before != null)
|
|
||||||
{
|
|
||||||
nameParts.Add(new ItemNamePart(before));
|
|
||||||
}
|
|
||||||
|
|
||||||
nameParts.Add(new ItemNamePart(rapidTravel, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nameLeft.Length > 0)
|
nameParts.Add(new ItemNamePart(rapidTravel, true));
|
||||||
{
|
|
||||||
nameParts.Add(new ItemNamePart(nameLeft));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (nameLeft.Length > 0)
|
||||||
{
|
{
|
||||||
nameParts.Add(new ItemNamePart(name));
|
nameParts.Add(new ItemNamePart(nameLeft));
|
||||||
}
|
}
|
||||||
return nameParts;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public string GetFileName(string fullName)
|
|
||||||
{
|
{
|
||||||
var parts = fullName.Split('.');
|
nameParts.Add(new ItemNamePart(name));
|
||||||
var fileName = string.Join('.', parts[..^1]);
|
|
||||||
return string.IsNullOrEmpty(fileName) ? fullName : fileName;
|
|
||||||
}
|
}
|
||||||
|
return nameParts;
|
||||||
|
}
|
||||||
|
|
||||||
public string GetFileExtension(string fullName)
|
public string GetFileName(string fullName)
|
||||||
{
|
{
|
||||||
var parts = fullName.Split('.');
|
var parts = fullName.Split('.');
|
||||||
return parts.Length == 1 || (parts.Length == 2 && string.IsNullOrEmpty(parts[0])) ? "" : parts[^1];
|
var fileName = string.Join('.', parts[..^1]);
|
||||||
}
|
return string.IsNullOrEmpty(fileName) ? fullName : fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetFileExtension(string fullName)
|
||||||
|
{
|
||||||
|
var parts = fullName.Split('.');
|
||||||
|
return parts.Length == 1 || (parts.Length == 2 && string.IsNullOrEmpty(parts[0])) ? "" : parts[^1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,27 +3,26 @@ using FileTime.App.Core.Services.CommandHandler;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.App.Core
|
namespace FileTime.App.Core;
|
||||||
{
|
|
||||||
public static class Startup
|
|
||||||
{
|
|
||||||
public static IServiceCollection AddCoreAppServices(this IServiceCollection serviceCollection)
|
|
||||||
{
|
|
||||||
return serviceCollection
|
|
||||||
.AddTransient<ITabViewModel, TabViewModel>()
|
|
||||||
.AddTransient<IContainerViewModel, ContainerViewModel>()
|
|
||||||
.AddTransient<IElementViewModel, ElementViewModel>()
|
|
||||||
.AddTransient<IItemNameConverterService, ItemNameConverterService>()
|
|
||||||
.AddSingleton<ICommandHandlerService, CommandHandlerService>()
|
|
||||||
.AddSingleton<IClipboardService, ClipboardService>()
|
|
||||||
.AddCommandHandlers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)
|
public static class Startup
|
||||||
{
|
{
|
||||||
return serviceCollection
|
public static IServiceCollection AddCoreAppServices(this IServiceCollection serviceCollection)
|
||||||
.AddSingleton<ICommandHandler, NavigationCommandHandler>()
|
{
|
||||||
.AddSingleton<ICommandHandler, ItemManipulationCommandHandler>();
|
return serviceCollection
|
||||||
}
|
.AddTransient<ITabViewModel, TabViewModel>()
|
||||||
|
.AddTransient<IContainerViewModel, ContainerViewModel>()
|
||||||
|
.AddTransient<IElementViewModel, ElementViewModel>()
|
||||||
|
.AddTransient<IItemNameConverterService, ItemNameConverterService>()
|
||||||
|
.AddSingleton<ICommandHandlerService, CommandHandlerService>()
|
||||||
|
.AddSingleton<IClipboardService, ClipboardService>()
|
||||||
|
.AddCommandHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)
|
||||||
|
{
|
||||||
|
return serviceCollection
|
||||||
|
.AddSingleton<ICommandHandler, NavigationCommandHandler>()
|
||||||
|
.AddSingleton<ICommandHandler, ItemManipulationCommandHandler>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,50 +5,49 @@ using FileTime.App.Core.Models.Enums;
|
|||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
using MoreLinq;
|
using MoreLinq;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel]
|
||||||
|
public abstract partial class AppStateBase : IAppState
|
||||||
{
|
{
|
||||||
[ViewModel]
|
private readonly BehaviorSubject<string?> _searchText = new(null);
|
||||||
public abstract partial class AppStateBase : IAppState
|
private readonly BehaviorSubject<ITabViewModel?> _selectedTab = new(null);
|
||||||
|
private readonly BehaviorSubject<IEnumerable<ITabViewModel>> _tabs = new(Enumerable.Empty<ITabViewModel>());
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private ViewMode _viewMode;
|
||||||
|
|
||||||
|
public ObservableCollection<ITabViewModel> Tabs { get; } = new();
|
||||||
|
public IObservable<string?> SearchText { get; private set; }
|
||||||
|
|
||||||
|
public IObservable<ITabViewModel?> SelectedTab { get; private set; }
|
||||||
|
|
||||||
|
partial void OnInitialize()
|
||||||
{
|
{
|
||||||
private readonly BehaviorSubject<string?> _searchText = new(null);
|
Tabs.CollectionChanged += (_, _) => _tabs.OnNext(Tabs);
|
||||||
private readonly BehaviorSubject<ITabViewModel?> _selectedTab = new(null);
|
SearchText = _searchText.AsObservable();
|
||||||
private readonly BehaviorSubject<IEnumerable<ITabViewModel>> _tabs = new(Enumerable.Empty<ITabViewModel>());
|
SelectedTab = Observable.CombineLatest(_tabs, _selectedTab, GetSelectedTab);
|
||||||
|
}
|
||||||
|
|
||||||
[Property]
|
public void AddTab(ITabViewModel tabViewModel)
|
||||||
private ViewMode _viewMode;
|
{
|
||||||
|
Tabs.Add(tabViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
public ObservableCollection<ITabViewModel> Tabs { get; } = new();
|
public void RemoveTab(ITabViewModel tabViewModel)
|
||||||
public IObservable<string?> SearchText { get; private set; }
|
{
|
||||||
|
if (!Tabs.Contains(tabViewModel)) return;
|
||||||
|
|
||||||
public IObservable<ITabViewModel?> SelectedTab { get; private set; }
|
Tabs.Remove(tabViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
partial void OnInitialize()
|
public void SetSearchText(string? searchText) => _searchText.OnNext(searchText);
|
||||||
{
|
|
||||||
Tabs.CollectionChanged += (_, _) => _tabs.OnNext(Tabs);
|
|
||||||
SearchText = _searchText.AsObservable();
|
|
||||||
SelectedTab = Observable.CombineLatest(_tabs, _selectedTab, GetSelectedTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTab(ITabViewModel tabViewModel)
|
public void SetSelectedTab(ITabViewModel tabToSelect) => _selectedTab.OnNext(tabToSelect);
|
||||||
{
|
|
||||||
Tabs.Add(tabViewModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveTab(ITabViewModel tabViewModel)
|
private ITabViewModel? GetSelectedTab(IEnumerable<ITabViewModel> tabs, ITabViewModel? expectedSelectedTab)
|
||||||
{
|
{
|
||||||
if (!Tabs.Contains(tabViewModel)) return;
|
var (prefered, others) = tabs.OrderBy(t => t.TabNumber).Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0));
|
||||||
|
return prefered.Concat(others).FirstOrDefault();
|
||||||
Tabs.Remove(tabViewModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetSearchText(string? searchText) => _searchText.OnNext(searchText);
|
|
||||||
|
|
||||||
public void SetSelectedTab(ITabViewModel tabToSelect) => _selectedTab.OnNext(tabToSelect);
|
|
||||||
|
|
||||||
private ITabViewModel? GetSelectedTab(IEnumerable<ITabViewModel> tabs, ITabViewModel? expectedSelectedTab)
|
|
||||||
{
|
|
||||||
var (prefered, others) = tabs.OrderBy(t => t.TabNumber).Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0));
|
|
||||||
return prefered.Concat(others).FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,21 +2,20 @@ using FileTime.App.Core.Services;
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel(GenerateConstructor = false)]
|
||||||
|
public partial class ContainerSizeContainerViewModel : ItemViewModel, IContainerSizeContainerViewModel
|
||||||
{
|
{
|
||||||
[ViewModel(GenerateConstructor = false)]
|
[Property]
|
||||||
public partial class ContainerSizeContainerViewModel : ItemViewModel, IContainerSizeContainerViewModel
|
private long _size;
|
||||||
|
|
||||||
|
public ContainerSizeContainerViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
||||||
{
|
{
|
||||||
[Property]
|
}
|
||||||
private long _size;
|
|
||||||
|
|
||||||
public ContainerSizeContainerViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
public void Init(IContainer item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
}
|
Init((IItem)item, parentTab);
|
||||||
|
|
||||||
public void Init(IContainer item, ITabViewModel parentTab)
|
|
||||||
{
|
|
||||||
Init((IItem)item, parentTab);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,20 +2,19 @@ using FileTime.App.Core.Services;
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel(GenerateConstructor = false)]
|
||||||
|
public partial class ContainerViewModel : ItemViewModel, IContainerViewModel
|
||||||
{
|
{
|
||||||
[ViewModel(GenerateConstructor = false)]
|
public IContainer? Container => BaseItem as IContainer;
|
||||||
public partial class ContainerViewModel : ItemViewModel, IContainerViewModel
|
|
||||||
|
public ContainerViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
||||||
{
|
{
|
||||||
public IContainer? Container => BaseItem as IContainer;
|
}
|
||||||
|
|
||||||
public ContainerViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
public void Init(IContainer item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
}
|
Init((IItem)item, parentTab);
|
||||||
|
|
||||||
public void Init(IContainer item, ITabViewModel parentTab)
|
|
||||||
{
|
|
||||||
Init((IItem)item, parentTab);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,21 +2,20 @@ using FileTime.App.Core.Services;
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel(GenerateConstructor = false)]
|
||||||
|
public partial class ElementViewModel : ItemViewModel, IElementViewModel
|
||||||
{
|
{
|
||||||
[ViewModel(GenerateConstructor = false)]
|
[Property]
|
||||||
public partial class ElementViewModel : ItemViewModel, IElementViewModel
|
private long? _size;
|
||||||
|
|
||||||
|
public ElementViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
||||||
{
|
{
|
||||||
[Property]
|
}
|
||||||
private long? _size;
|
|
||||||
|
|
||||||
public ElementViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
public void Init(IElement item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
}
|
Init((IItem)item, parentTab);
|
||||||
|
|
||||||
public void Init(IElement item, ITabViewModel parentTab)
|
|
||||||
{
|
|
||||||
Init((IItem)item, parentTab);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,17 @@ using FileTime.App.Core.Services;
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
{
|
|
||||||
[ViewModel(GenerateConstructor = false)]
|
|
||||||
public partial class FileViewModel : ElementViewModel, IFileViewModel
|
|
||||||
{
|
|
||||||
public FileViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(IFileElement item, ITabViewModel parentTab)
|
[ViewModel(GenerateConstructor = false)]
|
||||||
{
|
public partial class FileViewModel : ElementViewModel, IFileViewModel
|
||||||
Init((IElement)item, parentTab);
|
{
|
||||||
}
|
public FileViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(IFileElement item, ITabViewModel parentTab)
|
||||||
|
{
|
||||||
|
Init((IElement)item, parentTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,54 +7,54 @@ using FileTime.Core.Models;
|
|||||||
using MoreLinq;
|
using MoreLinq;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel]
|
||||||
|
[Inject(typeof(IAppState), "_appState")]
|
||||||
|
[Inject(typeof(IItemNameConverterService), "_itemNameConverterService")]
|
||||||
|
public abstract partial class ItemViewModel : IItemViewModel
|
||||||
{
|
{
|
||||||
[ViewModel]
|
[Property]
|
||||||
[Inject(typeof(IAppState), "_appState")]
|
private IItem? _baseItem;
|
||||||
[Inject(typeof(IItemNameConverterService), "_itemNameConverterService")]
|
|
||||||
public abstract partial class ItemViewModel : IItemViewModel
|
[Property]
|
||||||
|
private IObservable<IReadOnlyList<ItemNamePart>>? _displayName;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private string? _displayNameText;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private IObservable<bool>? _isSelected;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private IObservable<bool>? _isMarked;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private IObservable<ItemViewMode> _viewMode;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private DateTime? _createdAt;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private string? _attributes;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private IObservable<bool> _isAlternative;
|
||||||
|
|
||||||
|
public void Init(IItem item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
[Property]
|
BaseItem = item;
|
||||||
private IItem? _baseItem;
|
DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s));
|
||||||
|
DisplayNameText = item.DisplayName;
|
||||||
|
IsMarked = parentTab.MarkedItems.ToCollection().Select(m => m.Any(i => i.Path.Path == item.FullName?.Path));
|
||||||
|
IsSelected = parentTab.CurrentSelectedItem.Select(EqualsTo);
|
||||||
|
IsAlternative = parentTab.CurrentItemsCollectionObservable.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0);
|
||||||
|
ViewMode = Observable.CombineLatest(IsMarked, IsSelected, IsAlternative, GenerateViewMode);
|
||||||
|
Attributes = item.Attributes;
|
||||||
|
CreatedAt = item.CreatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
[Property]
|
private ItemViewMode GenerateViewMode(bool isMarked, bool isSelected, bool sAlternative)
|
||||||
private IObservable<IReadOnlyList<ItemNamePart>>? _displayName;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private string? _displayNameText;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private IObservable<bool>? _isSelected;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private IObservable<bool>? _isMarked;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private IObservable<ItemViewMode> _viewMode;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private DateTime? _createdAt;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private string? _attributes;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private IObservable<bool> _isAlternative;
|
|
||||||
|
|
||||||
public void Init(IItem item, ITabViewModel parentTab)
|
|
||||||
{
|
|
||||||
BaseItem = item;
|
|
||||||
DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s));
|
|
||||||
DisplayNameText = item.DisplayName;
|
|
||||||
IsMarked = parentTab.MarkedItems.ToCollection().Select(m => m.Any(i => i.Path.Path == item.FullName?.Path));
|
|
||||||
IsSelected = parentTab.CurrentSelectedItem.Select(EqualsTo);
|
|
||||||
IsAlternative = parentTab.CurrentItemsCollectionObservable.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0);
|
|
||||||
ViewMode = Observable.CombineLatest(IsMarked, IsSelected, IsAlternative, GenerateViewMode);
|
|
||||||
Attributes = item.Attributes;
|
|
||||||
CreatedAt = item.CreatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ItemViewMode GenerateViewMode(bool isMarked, bool isSelected, bool sAlternative)
|
|
||||||
=> (isMarked, isSelected, sAlternative) switch
|
=> (isMarked, isSelected, sAlternative) switch
|
||||||
{
|
{
|
||||||
(true, true, _) => ItemViewMode.MarkedSelected,
|
(true, true, _) => ItemViewMode.MarkedSelected,
|
||||||
@@ -65,9 +65,8 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
_ => ItemViewMode.Default
|
_ => ItemViewMode.Default
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool EqualsTo(IItemViewModel? itemViewModel)
|
public bool EqualsTo(IItemViewModel? itemViewModel)
|
||||||
{
|
{
|
||||||
return BaseItem?.FullName?.Path is string path && path == itemViewModel?.BaseItem?.FullName?.Path;
|
return BaseItem?.FullName?.Path is string path && path == itemViewModel?.BaseItem?.FullName?.Path;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,118 +9,118 @@ using FileTime.Tools.Extensions;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel]
|
||||||
|
public partial class TabViewModel : ITabViewModel, IDisposable
|
||||||
{
|
{
|
||||||
[ViewModel]
|
private readonly IServiceProvider _serviceProvider;
|
||||||
public partial class TabViewModel : ITabViewModel, IDisposable
|
private readonly IItemNameConverterService _itemNameConverterService;
|
||||||
|
private readonly IAppState _appState;
|
||||||
|
private readonly IRxSchedulerService _rxSchedulerService;
|
||||||
|
private readonly SourceList<IAbsolutePath> _markedItems = new();
|
||||||
|
private readonly List<IDisposable> _disposables = new();
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
|
public ITab? Tab { get; private set; }
|
||||||
|
public int TabNumber { get; private set; }
|
||||||
|
|
||||||
|
public IObservable<bool> IsSelected { get; }
|
||||||
|
|
||||||
|
public IObservable<IContainer?> CurrentLocation { get; private set; } = null!;
|
||||||
|
public IObservable<IItemViewModel?> CurrentSelectedItem { get; private set; } = null!;
|
||||||
|
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; private set; } = null!;
|
||||||
|
public IObservable<IChangeSet<IAbsolutePath>> MarkedItems { get; }
|
||||||
|
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; private set; } = null!;
|
||||||
|
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; private set; } = null!;
|
||||||
|
|
||||||
|
public IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; private set; } = null!;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private BindedCollection<IItemViewModel>? _currentItemsCollection;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private BindedCollection<IItemViewModel>? _parentsChildrenCollection;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private BindedCollection<IItemViewModel>? _selectedsChildrenCollection;
|
||||||
|
|
||||||
|
public TabViewModel(
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
|
IItemNameConverterService itemNameConverterService,
|
||||||
|
IAppState appState,
|
||||||
|
IRxSchedulerService rxSchedulerService)
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
private readonly IItemNameConverterService _itemNameConverterService;
|
_itemNameConverterService = itemNameConverterService;
|
||||||
private readonly IAppState _appState;
|
_appState = appState;
|
||||||
private readonly IRxSchedulerService _rxSchedulerService;
|
|
||||||
private readonly SourceList<IAbsolutePath> _markedItems = new();
|
|
||||||
private readonly List<IDisposable> _disposables = new();
|
|
||||||
private bool disposed;
|
|
||||||
|
|
||||||
public ITab? Tab { get; private set; }
|
MarkedItems = _markedItems.Connect().StartWithEmpty();
|
||||||
public int TabNumber { get; private set; }
|
IsSelected = _appState.SelectedTab.Select(s => s == this);
|
||||||
|
_rxSchedulerService = rxSchedulerService;
|
||||||
|
}
|
||||||
|
|
||||||
public IObservable<bool> IsSelected { get; }
|
public void Init(ITab tab, int tabNumber)
|
||||||
|
{
|
||||||
|
Tab = tab;
|
||||||
|
TabNumber = tabNumber;
|
||||||
|
|
||||||
public IObservable<IContainer?> CurrentLocation { get; private set; } = null!;
|
CurrentLocation = tab.CurrentLocation.AsObservable();
|
||||||
public IObservable<IItemViewModel?> CurrentSelectedItem { get; private set; } = null!;
|
CurrentItems = tab.CurrentItems
|
||||||
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; private set; } = null!;
|
.Select(items => items?.Transform(MapItemToViewModel))
|
||||||
public IObservable<IChangeSet<IAbsolutePath>> MarkedItems { get; }
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; private set; } = null!;
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; private set; } = null!;
|
.Publish(null)
|
||||||
|
.RefCount();
|
||||||
|
|
||||||
public IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; private set; } = null!;
|
CurrentSelectedItem =
|
||||||
|
Observable.CombineLatest(
|
||||||
[Property]
|
|
||||||
private BindedCollection<IItemViewModel>? _currentItemsCollection;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private BindedCollection<IItemViewModel>? _parentsChildrenCollection;
|
|
||||||
|
|
||||||
[Property]
|
|
||||||
private BindedCollection<IItemViewModel>? _selectedsChildrenCollection;
|
|
||||||
|
|
||||||
public TabViewModel(
|
|
||||||
IServiceProvider serviceProvider,
|
|
||||||
IItemNameConverterService itemNameConverterService,
|
|
||||||
IAppState appState,
|
|
||||||
IRxSchedulerService rxSchedulerService)
|
|
||||||
{
|
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
_itemNameConverterService = itemNameConverterService;
|
|
||||||
_appState = appState;
|
|
||||||
|
|
||||||
MarkedItems = _markedItems.Connect().StartWithEmpty();
|
|
||||||
IsSelected = _appState.SelectedTab.Select(s => s == this);
|
|
||||||
_rxSchedulerService = rxSchedulerService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(ITab tab, int tabNumber)
|
|
||||||
{
|
|
||||||
Tab = tab;
|
|
||||||
TabNumber = tabNumber;
|
|
||||||
|
|
||||||
CurrentLocation = tab.CurrentLocation.AsObservable();
|
|
||||||
CurrentItems = tab.CurrentItems
|
|
||||||
.Select(items => items?.Transform(MapItemToViewModel))
|
|
||||||
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
|
||||||
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
|
||||||
.Publish(null)
|
|
||||||
.RefCount();
|
|
||||||
|
|
||||||
CurrentSelectedItem =
|
|
||||||
Observable.CombineLatest(
|
|
||||||
CurrentItems,
|
CurrentItems,
|
||||||
tab.CurrentSelectedItem,
|
tab.CurrentSelectedItem,
|
||||||
(currentItems, currentSelectedItemPath) =>
|
(currentItems, currentSelectedItemPath) =>
|
||||||
currentItems == null
|
currentItems == null
|
||||||
? Observable.Return((IItemViewModel?)null)
|
? Observable.Return((IItemViewModel?)null)
|
||||||
: currentItems
|
: currentItems
|
||||||
.ToCollection()
|
.ToCollection()
|
||||||
.Select(items => items.FirstOrDefault(i => i.BaseItem?.FullName == currentSelectedItemPath?.Path))
|
.Select(items => items.FirstOrDefault(i => i.BaseItem?.FullName == currentSelectedItemPath?.Path))
|
||||||
)
|
)
|
||||||
.Switch()
|
.Switch()
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
SelectedsChildren = InitSelectedsChildren();
|
SelectedsChildren = InitSelectedsChildren();
|
||||||
ParentsChildren = InitParentsChildren();
|
ParentsChildren = InitParentsChildren();
|
||||||
|
|
||||||
CurrentItemsCollectionObservable = CurrentItems
|
CurrentItemsCollectionObservable = CurrentItems
|
||||||
.Select(c => c != null ? c.ToCollection() : Observable.Return((IReadOnlyCollection<IItemViewModel>?)null))
|
.Select(c => c != null ? c.ToCollection() : Observable.Return((IReadOnlyCollection<IItemViewModel>?)null))
|
||||||
.Switch()
|
.Switch()
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
CurrentItems.Subscribe(children =>
|
CurrentItems.Subscribe(children =>
|
||||||
{
|
{
|
||||||
CurrentItemsCollection?.Dispose();
|
CurrentItemsCollection?.Dispose();
|
||||||
CurrentItemsCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
CurrentItemsCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
||||||
});
|
});
|
||||||
|
|
||||||
ParentsChildren.Subscribe(children =>
|
ParentsChildren.Subscribe(children =>
|
||||||
{
|
{
|
||||||
ParentsChildrenCollection?.Dispose();
|
ParentsChildrenCollection?.Dispose();
|
||||||
ParentsChildrenCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
ParentsChildrenCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
||||||
});
|
});
|
||||||
|
|
||||||
SelectedsChildren.Subscribe(children =>
|
SelectedsChildren.Subscribe(children =>
|
||||||
{
|
{
|
||||||
SelectedsChildrenCollection?.Dispose();
|
SelectedsChildrenCollection?.Dispose();
|
||||||
SelectedsChildrenCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
SelectedsChildrenCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
||||||
});
|
});
|
||||||
|
|
||||||
tab.CurrentLocation.Subscribe((_) => _markedItems.Clear());
|
tab.CurrentLocation.Subscribe((_) => _markedItems.Clear());
|
||||||
|
|
||||||
IObservable<IObservable<IChangeSet<IItemViewModel>>?> InitSelectedsChildren()
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> InitSelectedsChildren()
|
||||||
{
|
{
|
||||||
var currentSelectedItemThrottled = CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount();
|
var currentSelectedItemThrottled = CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount();
|
||||||
return Observable.Merge(
|
return Observable.Merge(
|
||||||
currentSelectedItemThrottled
|
currentSelectedItemThrottled
|
||||||
.WhereNotNull()
|
.WhereNotNull()
|
||||||
.OfType<IContainerViewModel>()
|
.OfType<IContainerViewModel>()
|
||||||
@@ -136,17 +136,17 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
IObservable<IObservable<IChangeSet<IItemViewModel>>?> InitParentsChildren()
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> InitParentsChildren()
|
||||||
{
|
{
|
||||||
var parentThrottled = CurrentLocation
|
var parentThrottled = CurrentLocation
|
||||||
.Select(l => l?.Parent)
|
.Select(l => l?.Parent)
|
||||||
.DistinctUntilChanged()
|
.DistinctUntilChanged()
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
return Observable.Merge(
|
return Observable.Merge(
|
||||||
parentThrottled
|
parentThrottled
|
||||||
.Where(p => p is not null)
|
.Where(p => p is not null)
|
||||||
.Select(p => Observable.FromAsync(async () => (IContainer)await p!.ResolveAsync()))
|
.Select(p => Observable.FromAsync(async () => (IContainer)await p!.ResolveAsync()))
|
||||||
@@ -162,85 +162,84 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<IItem> MapItem(IAbsolutePath item)
|
|
||||||
=> await item.ResolveAsync(forceResolve: true, itemInitializationSettings: new ItemInitializationSettings(true));
|
|
||||||
|
|
||||||
private IItemViewModel MapItemToViewModel(IItem item)
|
|
||||||
{
|
|
||||||
if (item is IContainer container)
|
|
||||||
{
|
|
||||||
var containerViewModel = _serviceProvider.GetInitableResolver<IContainer, ITabViewModel>(container, this).GetRequiredService<IContainerViewModel>();
|
|
||||||
|
|
||||||
return containerViewModel;
|
|
||||||
}
|
|
||||||
else if (item is IFileElement fileElement)
|
|
||||||
{
|
|
||||||
var fileViewModel = _serviceProvider.GetInitableResolver<IFileElement, ITabViewModel>(fileElement, this).GetRequiredService<IFileViewModel>();
|
|
||||||
fileViewModel.Size = fileElement.Size;
|
|
||||||
|
|
||||||
return fileViewModel;
|
|
||||||
}
|
|
||||||
else if (item is IElement element)
|
|
||||||
{
|
|
||||||
var elementViewModel = _serviceProvider.GetInitableResolver<IElement, ITabViewModel>(element, this).GetRequiredService<IElementViewModel>();
|
|
||||||
|
|
||||||
return elementViewModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"{nameof(item)} is not {nameof(IContainer)} neither {nameof(IElement)}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddMarkedItem(IAbsolutePath item) => _markedItems.Add(item);
|
|
||||||
|
|
||||||
public void RemoveMarkedItem(IAbsolutePath item)
|
|
||||||
{
|
|
||||||
var itemsToRemove = _markedItems.Items.Where(i => i.Path.Path == item.Path.Path).ToList();
|
|
||||||
|
|
||||||
_markedItems.RemoveMany(itemsToRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleMarkedItem(IAbsolutePath item)
|
|
||||||
{
|
|
||||||
if (_markedItems.Items.Any(i => i.Path.Path == item.Path.Path))
|
|
||||||
{
|
|
||||||
RemoveMarkedItem(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddMarkedItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearMarkedItems()
|
|
||||||
{
|
|
||||||
_markedItems.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
~TabViewModel() => Dispose(false);
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!disposed && disposing)
|
|
||||||
{
|
|
||||||
foreach (var disposable in _disposables)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
disposable.Dispose();
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
disposed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<IItem> MapItem(IAbsolutePath item)
|
||||||
|
=> await item.ResolveAsync(forceResolve: true, itemInitializationSettings: new ItemInitializationSettings(true));
|
||||||
|
|
||||||
|
private IItemViewModel MapItemToViewModel(IItem item)
|
||||||
|
{
|
||||||
|
if (item is IContainer container)
|
||||||
|
{
|
||||||
|
var containerViewModel = _serviceProvider.GetInitableResolver<IContainer, ITabViewModel>(container, this).GetRequiredService<IContainerViewModel>();
|
||||||
|
|
||||||
|
return containerViewModel;
|
||||||
|
}
|
||||||
|
else if (item is IFileElement fileElement)
|
||||||
|
{
|
||||||
|
var fileViewModel = _serviceProvider.GetInitableResolver<IFileElement, ITabViewModel>(fileElement, this).GetRequiredService<IFileViewModel>();
|
||||||
|
fileViewModel.Size = fileElement.Size;
|
||||||
|
|
||||||
|
return fileViewModel;
|
||||||
|
}
|
||||||
|
else if (item is IElement element)
|
||||||
|
{
|
||||||
|
var elementViewModel = _serviceProvider.GetInitableResolver<IElement, ITabViewModel>(element, this).GetRequiredService<IElementViewModel>();
|
||||||
|
|
||||||
|
return elementViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"{nameof(item)} is not {nameof(IContainer)} neither {nameof(IElement)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMarkedItem(IAbsolutePath item) => _markedItems.Add(item);
|
||||||
|
|
||||||
|
public void RemoveMarkedItem(IAbsolutePath item)
|
||||||
|
{
|
||||||
|
var itemsToRemove = _markedItems.Items.Where(i => i.Path.Path == item.Path.Path).ToList();
|
||||||
|
|
||||||
|
_markedItems.RemoveMany(itemsToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleMarkedItem(IAbsolutePath item)
|
||||||
|
{
|
||||||
|
if (_markedItems.Items.Any(i => i.Path.Path == item.Path.Path))
|
||||||
|
{
|
||||||
|
RemoveMarkedItem(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddMarkedItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearMarkedItems()
|
||||||
|
{
|
||||||
|
_markedItems.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
~TabViewModel() => Dispose(false);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposed && disposing)
|
||||||
|
{
|
||||||
|
foreach (var disposable in _disposables)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,18 +3,17 @@ using FileTime.Core.Services;
|
|||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.App.DependencyInjection
|
namespace FileTime.App.DependencyInjection;
|
||||||
{
|
|
||||||
public static class DependencyInjection
|
|
||||||
{
|
|
||||||
public static IServiceCollection RegisterDefaultServices(IServiceCollection? serviceCollection = null)
|
|
||||||
{
|
|
||||||
serviceCollection ??= new ServiceCollection();
|
|
||||||
|
|
||||||
return serviceCollection
|
public static class DependencyInjection
|
||||||
.AddTransient<ITab, Tab>()
|
{
|
||||||
.AddCoreAppServices()
|
public static IServiceCollection RegisterDefaultServices(IServiceCollection? serviceCollection = null)
|
||||||
.AddLocalServices();
|
{
|
||||||
}
|
serviceCollection ??= new ServiceCollection();
|
||||||
|
|
||||||
|
return serviceCollection
|
||||||
|
.AddTransient<ITab, Tab>()
|
||||||
|
.AddCoreAppServices()
|
||||||
|
.AddLocalServices();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,11 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -6,4 +6,8 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj" />
|
<ProjectReference Include="..\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Behaviors
|
namespace FileTime.Core.Behaviors;
|
||||||
|
|
||||||
|
public interface IOnContainerEnter
|
||||||
{
|
{
|
||||||
public interface IOnContainerEnter
|
Task OnEnter();
|
||||||
{
|
|
||||||
Task OnEnter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Command
|
namespace FileTime.Core.Command;
|
||||||
{
|
|
||||||
public interface ICommand
|
public interface ICommand
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Command
|
namespace FileTime.Core.Command;
|
||||||
{
|
|
||||||
public interface ITransportationCommand : ICommand
|
public interface ITransportationCommand : ICommand
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace FileTime.Core.Enums
|
namespace FileTime.Core.Enums;
|
||||||
|
|
||||||
|
public enum AbsolutePathType
|
||||||
{
|
{
|
||||||
public enum AbsolutePathType
|
Unknown,
|
||||||
{
|
Container,
|
||||||
Unknown,
|
Element
|
||||||
Container,
|
|
||||||
Element
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace FileTime.Core.Enums
|
namespace FileTime.Core.Enums;
|
||||||
|
|
||||||
|
public enum SupportsDelete
|
||||||
{
|
{
|
||||||
public enum SupportsDelete
|
False,
|
||||||
{
|
True,
|
||||||
False,
|
HardDeleteOnly,
|
||||||
True,
|
|
||||||
HardDeleteOnly,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DynamicData" Version="7.6.7" />
|
<PackageReference Include="DynamicData" Version="7.6.7" />
|
||||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public static class Constants
|
||||||
{
|
{
|
||||||
public static class Constants
|
public const char SeparatorChar = '/';
|
||||||
{
|
|
||||||
public const char SeparatorChar = '/';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
{
|
|
||||||
public record FullName(string Path)
|
|
||||||
{
|
|
||||||
public FullName? GetParent()
|
|
||||||
{
|
|
||||||
if (Path is null) return null;
|
|
||||||
|
|
||||||
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
|
public record FullName(string Path)
|
||||||
return pathParts.Length switch
|
{
|
||||||
{
|
public FullName? GetParent()
|
||||||
> 1 => new(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
|
{
|
||||||
_ => null
|
if (Path is null) return null;
|
||||||
};
|
|
||||||
}
|
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
|
||||||
|
return pathParts.Length switch
|
||||||
|
{
|
||||||
|
> 1 => new(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
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);
|
public interface IAbsolutePath
|
||||||
Task<IItem?> ResolveAsyncSafe(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default);
|
{
|
||||||
}
|
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);
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using DynamicData;
|
using DynamicData;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public interface IContainer : IItem
|
||||||
{
|
{
|
||||||
public interface IContainer : IItem
|
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; }
|
||||||
{
|
IObservable<bool> IsLoading { get; }
|
||||||
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; }
|
|
||||||
IObservable<bool> IsLoading { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
{
|
|
||||||
public interface IElement : IItem
|
public interface IElement : IItem
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public interface IFileElement : IElement
|
||||||
{
|
{
|
||||||
public interface IFileElement : IElement
|
long Size { get; }
|
||||||
{
|
|
||||||
long Size { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,22 @@
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public interface IItem
|
||||||
{
|
{
|
||||||
public interface IItem
|
string Name { get; }
|
||||||
{
|
string DisplayName { get; }
|
||||||
string Name { get; }
|
FullName? FullName { get; }
|
||||||
string DisplayName { get; }
|
NativePath? NativePath { get; }
|
||||||
FullName? FullName { get; }
|
IAbsolutePath? Parent { get; }
|
||||||
NativePath? NativePath { get; }
|
bool IsHidden { get; }
|
||||||
IAbsolutePath? Parent { get; }
|
bool IsExists { get; }
|
||||||
bool IsHidden { get; }
|
DateTime? CreatedAt { get; }
|
||||||
bool IsExists { get; }
|
SupportsDelete CanDelete { get; }
|
||||||
DateTime? CreatedAt { get; }
|
bool CanRename { get; }
|
||||||
SupportsDelete CanDelete { get; }
|
IContentProvider Provider { get; }
|
||||||
bool CanRename { get; }
|
string? Attributes { get; }
|
||||||
IContentProvider Provider { get; }
|
AbsolutePathType Type { get; }
|
||||||
string? Attributes { get; }
|
IObservable<IEnumerable<Exception>> Exceptions { get; }
|
||||||
AbsolutePathType Type { get; }
|
|
||||||
IObservable<IEnumerable<Exception>> Exceptions { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
{
|
|
||||||
public readonly struct ItemInitializationSettings
|
|
||||||
{
|
|
||||||
public readonly bool SkipChildInitialization;
|
|
||||||
|
|
||||||
public ItemInitializationSettings(bool skipChildInitialization)
|
public readonly struct ItemInitializationSettings
|
||||||
{
|
{
|
||||||
SkipChildInitialization = skipChildInitialization;
|
public readonly bool SkipChildInitialization;
|
||||||
}
|
|
||||||
|
public ItemInitializationSettings(bool skipChildInitialization)
|
||||||
|
{
|
||||||
|
SkipChildInitialization = skipChildInitialization;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
{
|
|
||||||
public record ItemsTransformator(
|
public record ItemsTransformator(
|
||||||
string Name,
|
string Name,
|
||||||
Func<IEnumerable<IItem>, Task<IEnumerable<IItem>>> Transformator
|
Func<IEnumerable<IItem>, Task<IEnumerable<IItem>>> Transformator
|
||||||
);
|
);
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
{
|
|
||||||
public record NativePath(string Path);
|
public record NativePath(string Path);
|
||||||
}
|
|
||||||
@@ -2,22 +2,21 @@ using FileTime.Core.Behaviors;
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Core.Services
|
namespace FileTime.Core.Services;
|
||||||
|
|
||||||
|
public interface IContentProvider : IContainer, IOnContainerEnter
|
||||||
{
|
{
|
||||||
public interface IContentProvider : IContainer, IOnContainerEnter
|
Task<IItem> GetItemByFullNameAsync(
|
||||||
{
|
FullName fullName,
|
||||||
Task<IItem> GetItemByFullNameAsync(
|
bool forceResolve = false,
|
||||||
FullName fullName,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
bool forceResolve = false,
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
|
||||||
ItemInitializationSettings itemInitializationSettings = default);
|
|
||||||
|
|
||||||
Task<IItem> GetItemByNativePathAsync(
|
Task<IItem> GetItemByNativePathAsync(
|
||||||
NativePath nativePath,
|
NativePath nativePath,
|
||||||
bool forceResolve = false,
|
bool forceResolve = false,
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default);
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
|
||||||
Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,17 @@ using DynamicData;
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
namespace FileTime.Core.Services
|
namespace FileTime.Core.Services;
|
||||||
{
|
|
||||||
public interface ITab : IInitable<IContainer>
|
|
||||||
{
|
|
||||||
IObservable<IContainer?> CurrentLocation { get; }
|
|
||||||
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
|
||||||
IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
|
|
||||||
|
|
||||||
void SetCurrentLocation(IContainer newLocation);
|
public interface ITab : IInitable<IContainer>
|
||||||
void AddSelectedItemsTransformator(ItemsTransformator transformator);
|
{
|
||||||
void RemoveSelectedItemsTransformator(ItemsTransformator transformator);
|
IObservable<IContainer?> CurrentLocation { get; }
|
||||||
void RemoveSelectedItemsTransformatorByName(string name);
|
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
||||||
void SetSelectedItem(IAbsolutePath newSelectedItem);
|
IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
|
||||||
}
|
|
||||||
|
void SetCurrentLocation(IContainer newLocation);
|
||||||
|
void AddSelectedItemsTransformator(ItemsTransformator transformator);
|
||||||
|
void RemoveSelectedItemsTransformator(ItemsTransformator transformator);
|
||||||
|
void RemoveSelectedItemsTransformatorByName(string name);
|
||||||
|
void SetSelectedItem(IAbsolutePath newSelectedItem);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
namespace FileTime.Core.Command.Copy
|
namespace FileTime.Core.Command.Copy;
|
||||||
{
|
|
||||||
public class CopyCommand : ITransportationCommand
|
public class CopyCommand : ITransportationCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,10 @@
|
|||||||
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace FileTime.Core.Command
|
namespace FileTime.Core.Command;
|
||||||
|
|
||||||
|
public enum TransportMode
|
||||||
{
|
{
|
||||||
public enum TransportMode
|
Merge,
|
||||||
{
|
Overwrite,
|
||||||
Merge,
|
Skip
|
||||||
Overwrite,
|
|
||||||
Skip
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,45 +1,44 @@
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public class AbsolutePath : IAbsolutePath
|
||||||
{
|
{
|
||||||
public class AbsolutePath : IAbsolutePath
|
public IContentProvider ContentProvider { get; }
|
||||||
|
public IContentProvider? VirtualContentProvider { get; }
|
||||||
|
|
||||||
|
public FullName Path { get; }
|
||||||
|
public AbsolutePathType Type { get; }
|
||||||
|
|
||||||
|
public AbsolutePath(IContentProvider contentProvider, FullName path, AbsolutePathType type, IContentProvider? virtualContentProvider = null)
|
||||||
{
|
{
|
||||||
public IContentProvider ContentProvider { get; }
|
ContentProvider = contentProvider;
|
||||||
public IContentProvider? VirtualContentProvider { get; }
|
Path = path;
|
||||||
|
VirtualContentProvider = virtualContentProvider;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
public FullName Path { get; }
|
public AbsolutePath(IItem item, IContentProvider? virtualContentProvider = null)
|
||||||
public AbsolutePathType Type { get; }
|
{
|
||||||
|
ContentProvider = item.Provider;
|
||||||
|
Path = item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item));
|
||||||
|
VirtualContentProvider = virtualContentProvider;
|
||||||
|
Type = item.Type;
|
||||||
|
}
|
||||||
|
|
||||||
public AbsolutePath(IContentProvider contentProvider, FullName path, AbsolutePathType type, IContentProvider? virtualContentProvider = null)
|
public async Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
||||||
|
{
|
||||||
|
var provider = VirtualContentProvider ?? ContentProvider;
|
||||||
|
return await provider.GetItemByFullNameAsync(Path, forceResolve, Type, itemInitializationSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IItem?> ResolveAsyncSafe(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
ContentProvider = contentProvider;
|
return await ResolveAsync(forceResolve, itemInitializationSettings);
|
||||||
Path = path;
|
|
||||||
VirtualContentProvider = virtualContentProvider;
|
|
||||||
Type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbsolutePath(IItem item, IContentProvider? virtualContentProvider = null)
|
|
||||||
{
|
|
||||||
ContentProvider = item.Provider;
|
|
||||||
Path = item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item));
|
|
||||||
VirtualContentProvider = virtualContentProvider;
|
|
||||||
Type = item.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
|
||||||
{
|
|
||||||
var provider = VirtualContentProvider ?? ContentProvider;
|
|
||||||
return await provider.GetItemByFullNameAsync(Path, forceResolve, Type, itemInitializationSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IItem?> ResolveAsyncSafe(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return await ResolveAsync(forceResolve, itemInitializationSettings);
|
|
||||||
}
|
|
||||||
catch { return null; }
|
|
||||||
}
|
}
|
||||||
|
catch { return null; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,26 +4,25 @@ using DynamicData;
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public record Container(
|
||||||
|
string Name,
|
||||||
|
string DisplayName,
|
||||||
|
FullName FullName,
|
||||||
|
NativePath NativePath,
|
||||||
|
IAbsolutePath? Parent,
|
||||||
|
bool IsHidden,
|
||||||
|
bool IsExists,
|
||||||
|
DateTime? CreatedAt,
|
||||||
|
SupportsDelete CanDelete,
|
||||||
|
bool CanRename,
|
||||||
|
string? Attributes,
|
||||||
|
IContentProvider Provider,
|
||||||
|
IObservable<IEnumerable<Exception>> Exceptions,
|
||||||
|
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items) : IContainer
|
||||||
{
|
{
|
||||||
public record Container(
|
BehaviorSubject<bool> IsLoading { get; } = new BehaviorSubject<bool>(false);
|
||||||
string Name,
|
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
||||||
string DisplayName,
|
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||||
FullName FullName,
|
|
||||||
NativePath NativePath,
|
|
||||||
IAbsolutePath? Parent,
|
|
||||||
bool IsHidden,
|
|
||||||
bool IsExists,
|
|
||||||
DateTime? CreatedAt,
|
|
||||||
SupportsDelete CanDelete,
|
|
||||||
bool CanRename,
|
|
||||||
string? Attributes,
|
|
||||||
IContentProvider Provider,
|
|
||||||
IObservable<IEnumerable<Exception>> Exceptions,
|
|
||||||
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items) : IContainer
|
|
||||||
{
|
|
||||||
BehaviorSubject<bool> IsLoading { get; } = new BehaviorSubject<bool>(false);
|
|
||||||
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
|
||||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,22 @@
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
|
public record Element(
|
||||||
|
string Name,
|
||||||
|
string DisplayName,
|
||||||
|
FullName FullName,
|
||||||
|
NativePath NativePath,
|
||||||
|
IAbsolutePath? Parent,
|
||||||
|
bool IsHidden,
|
||||||
|
bool IsExists,
|
||||||
|
DateTime? CreatedAt,
|
||||||
|
SupportsDelete CanDelete,
|
||||||
|
bool CanRename,
|
||||||
|
string? Attributes,
|
||||||
|
IContentProvider Provider,
|
||||||
|
IObservable<IEnumerable<Exception>> Exceptions) : IElement
|
||||||
{
|
{
|
||||||
public record Element(
|
public AbsolutePathType Type => AbsolutePathType.Element;
|
||||||
string Name,
|
|
||||||
string DisplayName,
|
|
||||||
FullName FullName,
|
|
||||||
NativePath NativePath,
|
|
||||||
IAbsolutePath? Parent,
|
|
||||||
bool IsHidden,
|
|
||||||
bool IsExists,
|
|
||||||
DateTime? CreatedAt,
|
|
||||||
SupportsDelete CanDelete,
|
|
||||||
bool CanRename,
|
|
||||||
string? Attributes,
|
|
||||||
IContentProvider Provider,
|
|
||||||
IObservable<IEnumerable<Exception>> Exceptions) : IElement
|
|
||||||
{
|
|
||||||
public AbsolutePathType Type => AbsolutePathType.Element;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models;
|
||||||
{
|
|
||||||
public record FileElement(
|
public record FileElement(
|
||||||
string Name,
|
string Name,
|
||||||
string DisplayName,
|
string DisplayName,
|
||||||
FullName FullName,
|
FullName FullName,
|
||||||
@@ -33,4 +33,3 @@ namespace FileTime.Core.Models
|
|||||||
Provider,
|
Provider,
|
||||||
Exceptions
|
Exceptions
|
||||||
), IFileElement;
|
), IFileElement;
|
||||||
}
|
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -4,64 +4,63 @@ using DynamicData;
|
|||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Core.Services
|
namespace FileTime.Core.Services;
|
||||||
|
|
||||||
|
public abstract class ContentProviderBase : IContentProvider
|
||||||
{
|
{
|
||||||
public abstract class ContentProviderBase : IContentProvider
|
protected BehaviorSubject<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; } = new (null);
|
||||||
|
|
||||||
|
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> IContainer.Items => Items;
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public string DisplayName { get; }
|
||||||
|
|
||||||
|
public FullName? FullName => null;
|
||||||
|
|
||||||
|
public NativePath? NativePath => null;
|
||||||
|
|
||||||
|
public bool IsHidden => false;
|
||||||
|
|
||||||
|
public bool IsExists => true;
|
||||||
|
|
||||||
|
public SupportsDelete CanDelete => SupportsDelete.False;
|
||||||
|
|
||||||
|
public bool CanRename => false;
|
||||||
|
|
||||||
|
public IContentProvider Provider => this;
|
||||||
|
|
||||||
|
public IAbsolutePath? Parent => null;
|
||||||
|
|
||||||
|
public DateTime? CreatedAt => null;
|
||||||
|
|
||||||
|
public string? Attributes => null;
|
||||||
|
|
||||||
|
protected BehaviorSubject<bool> IsLoading { get; } = new(false);
|
||||||
|
|
||||||
|
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
||||||
|
|
||||||
|
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||||
|
|
||||||
|
public IObservable<IEnumerable<Exception>> Exceptions => Observable.Return(Enumerable.Empty<Exception>());
|
||||||
|
|
||||||
|
protected ContentProviderBase(string name)
|
||||||
{
|
{
|
||||||
protected BehaviorSubject<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; } = new (null);
|
DisplayName = Name = name;
|
||||||
|
|
||||||
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> IContainer.Items => Items;
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
public string DisplayName { get; }
|
|
||||||
|
|
||||||
public FullName? FullName => null;
|
|
||||||
|
|
||||||
public NativePath? NativePath => null;
|
|
||||||
|
|
||||||
public bool IsHidden => false;
|
|
||||||
|
|
||||||
public bool IsExists => true;
|
|
||||||
|
|
||||||
public SupportsDelete CanDelete => SupportsDelete.False;
|
|
||||||
|
|
||||||
public bool CanRename => false;
|
|
||||||
|
|
||||||
public IContentProvider Provider => this;
|
|
||||||
|
|
||||||
public IAbsolutePath? Parent => null;
|
|
||||||
|
|
||||||
public DateTime? CreatedAt => null;
|
|
||||||
|
|
||||||
public string? Attributes => null;
|
|
||||||
|
|
||||||
protected BehaviorSubject<bool> IsLoading { get; } = new(false);
|
|
||||||
|
|
||||||
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
|
||||||
|
|
||||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
|
||||||
|
|
||||||
public IObservable<IEnumerable<Exception>> Exceptions => Observable.Return(Enumerable.Empty<Exception>());
|
|
||||||
|
|
||||||
protected ContentProviderBase(string name)
|
|
||||||
{
|
|
||||||
DisplayName = Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task OnEnter() => Task.CompletedTask;
|
|
||||||
public virtual async Task<IItem> GetItemByFullNameAsync(
|
|
||||||
FullName fullName,
|
|
||||||
bool forceResolve = false,
|
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
|
||||||
ItemInitializationSettings itemInitializationSettings = default)
|
|
||||||
=> await GetItemByNativePathAsync(GetNativePath(fullName), forceResolve, forceResolvePathType, itemInitializationSettings);
|
|
||||||
public abstract Task<IItem> GetItemByNativePathAsync(
|
|
||||||
NativePath nativePath,
|
|
||||||
bool forceResolve = false,
|
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
|
||||||
ItemInitializationSettings itemInitializationSettings = default);
|
|
||||||
public abstract Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
|
||||||
public abstract NativePath GetNativePath(FullName fullName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual Task OnEnter() => Task.CompletedTask;
|
||||||
|
public virtual async Task<IItem> GetItemByFullNameAsync(
|
||||||
|
FullName fullName,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
|
=> await GetItemByNativePathAsync(GetNativePath(fullName), forceResolve, forceResolvePathType, itemInitializationSettings);
|
||||||
|
public abstract Task<IItem> GetItemByNativePathAsync(
|
||||||
|
NativePath nativePath,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default);
|
||||||
|
public abstract Task<List<IAbsolutePath>> GetItemsByContainerAsync(FullName fullName);
|
||||||
|
public abstract NativePath GetNativePath(FullName fullName);
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
|
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
|
||||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||||
|
|||||||
@@ -3,24 +3,24 @@ using System.Reactive.Subjects;
|
|||||||
using DynamicData;
|
using DynamicData;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Core.Services
|
namespace FileTime.Core.Services;
|
||||||
|
|
||||||
|
public class Tab : ITab
|
||||||
{
|
{
|
||||||
public class Tab : ITab
|
private readonly BehaviorSubject<IContainer?> _currentLocation = new(null);
|
||||||
|
private readonly BehaviorSubject<IAbsolutePath?> _currentSelectedItem = new(null);
|
||||||
|
private readonly List<ItemsTransformator> _transformators = new();
|
||||||
|
private IAbsolutePath? _currentSelectedItemCached;
|
||||||
|
|
||||||
|
public IObservable<IContainer?> CurrentLocation { get; }
|
||||||
|
public IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
|
||||||
|
public IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
||||||
|
|
||||||
|
public Tab()
|
||||||
{
|
{
|
||||||
private readonly BehaviorSubject<IContainer?> _currentLocation = new(null);
|
CurrentLocation = _currentLocation.DistinctUntilChanged().Publish(null).RefCount();
|
||||||
private readonly BehaviorSubject<IAbsolutePath?> _currentSelectedItem = new(null);
|
CurrentItems =
|
||||||
private readonly List<ItemsTransformator> _transformators = new();
|
Observable.Merge(
|
||||||
private IAbsolutePath? _currentSelectedItemCached;
|
|
||||||
|
|
||||||
public IObservable<IContainer?> CurrentLocation { get; }
|
|
||||||
public IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
|
|
||||||
public IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
|
||||||
|
|
||||||
public Tab()
|
|
||||||
{
|
|
||||||
CurrentLocation = _currentLocation.DistinctUntilChanged().Publish(null).RefCount();
|
|
||||||
CurrentItems =
|
|
||||||
Observable.Merge(
|
|
||||||
CurrentLocation
|
CurrentLocation
|
||||||
.Where(c => c is not null)
|
.Where(c => c is not null)
|
||||||
.Select(c => c!.Items)
|
.Select(c => c!.Items)
|
||||||
@@ -33,13 +33,13 @@ namespace FileTime.Core.Services
|
|||||||
.Publish((IObservable<IChangeSet<IItem>>?)null)
|
.Publish((IObservable<IChangeSet<IItem>>?)null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
CurrentSelectedItem =
|
CurrentSelectedItem =
|
||||||
Observable.CombineLatest(
|
Observable.CombineLatest(
|
||||||
CurrentItems
|
CurrentItems
|
||||||
.Select(c =>
|
.Select(c =>
|
||||||
c == null
|
c == null
|
||||||
? Observable.Return<IReadOnlyCollection<IItem>?>(null)
|
? Observable.Return<IReadOnlyCollection<IItem>?>(null)
|
||||||
: c.ToCollection()
|
: c.ToCollection()
|
||||||
)
|
)
|
||||||
.Switch(),
|
.Switch(),
|
||||||
_currentSelectedItem,
|
_currentSelectedItem,
|
||||||
@@ -55,41 +55,40 @@ namespace FileTime.Core.Services
|
|||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
CurrentSelectedItem.Subscribe(s =>
|
CurrentSelectedItem.Subscribe(s =>
|
||||||
{
|
|
||||||
_currentSelectedItemCached = s;
|
|
||||||
_currentSelectedItem.OnNext(s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IItem> MapItem(IAbsolutePath item) => await item.ResolveAsync(true);
|
|
||||||
|
|
||||||
public void Init(IContainer currentLocation)
|
|
||||||
{
|
{
|
||||||
_currentLocation.OnNext(currentLocation);
|
_currentSelectedItemCached = s;
|
||||||
}
|
_currentSelectedItem.OnNext(s);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static IAbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
|
private async Task<IItem> MapItem(IAbsolutePath item) => await item.ResolveAsync(true);
|
||||||
{
|
|
||||||
//TODO:
|
|
||||||
return new AbsolutePath(items.First());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
public void Init(IContainer currentLocation)
|
||||||
|
{
|
||||||
|
_currentLocation.OnNext(currentLocation);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetSelectedItem(IAbsolutePath newSelectedItem) => _currentSelectedItem.OnNext(newSelectedItem);
|
private static IAbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
|
||||||
|
{
|
||||||
|
//TODO:
|
||||||
|
return new AbsolutePath(items.First());
|
||||||
|
}
|
||||||
|
|
||||||
public void AddSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Add(transformator);
|
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
||||||
public void RemoveSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Remove(transformator);
|
|
||||||
public void RemoveSelectedItemsTransformatorByName(string name) => _transformators.RemoveAll(t => t.Name == name);
|
|
||||||
|
|
||||||
public async Task OpenSelected()
|
public void SetSelectedItem(IAbsolutePath newSelectedItem) => _currentSelectedItem.OnNext(newSelectedItem);
|
||||||
{
|
|
||||||
if (_currentSelectedItemCached == null) return;
|
|
||||||
var resolvedSelectedItem = await _currentSelectedItemCached.ContentProvider.GetItemByFullNameAsync(_currentSelectedItemCached.Path);
|
|
||||||
|
|
||||||
if (resolvedSelectedItem is not IContainer resolvedContainer) return;
|
public void AddSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Add(transformator);
|
||||||
SetCurrentLocation(resolvedContainer);
|
public void RemoveSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Remove(transformator);
|
||||||
}
|
public void RemoveSelectedItemsTransformatorByName(string name) => _transformators.RemoveAll(t => t.Name == name);
|
||||||
|
|
||||||
|
public async Task OpenSelected()
|
||||||
|
{
|
||||||
|
if (_currentSelectedItemCached == null) return;
|
||||||
|
var resolvedSelectedItem = await _currentSelectedItemCached.ContentProvider.GetItemByFullNameAsync(_currentSelectedItemCached.Path);
|
||||||
|
|
||||||
|
if (resolvedSelectedItem is not IContainer resolvedContainer) return;
|
||||||
|
SetCurrentLocation(resolvedContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,89 +1,88 @@
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using FileTime.App.Core.Command;
|
using FileTime.App.Core.Command;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public class CommandBindingConfiguration
|
||||||
{
|
{
|
||||||
public class CommandBindingConfiguration
|
public List<KeyConfig> Keys { get; set; } = new List<KeyConfig>();
|
||||||
|
|
||||||
|
public Commands Command { get; set; } = Commands.None;
|
||||||
|
|
||||||
|
public string KeysDisplayText => GetKeysDisplayText();
|
||||||
|
|
||||||
|
public CommandBindingConfiguration() { }
|
||||||
|
|
||||||
|
public CommandBindingConfiguration(Commands command, IEnumerable<KeyConfig> keys)
|
||||||
{
|
{
|
||||||
public List<KeyConfig> Keys { get; set; } = new List<KeyConfig>();
|
Keys = new List<KeyConfig>(keys);
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
public Commands Command { get; set; } = Commands.None;
|
public CommandBindingConfiguration(Commands command, KeyConfig key)
|
||||||
|
{
|
||||||
|
Keys = new List<KeyConfig>() { key };
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
public string KeysDisplayText => GetKeysDisplayText();
|
public CommandBindingConfiguration(Commands command, IEnumerable<Key> keys)
|
||||||
|
{
|
||||||
|
Keys = keys.Select(k => new KeyConfig(k)).ToList();
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandBindingConfiguration() { }
|
public CommandBindingConfiguration(Commands command, Key key)
|
||||||
|
{
|
||||||
|
Keys = new List<KeyConfig>() { new KeyConfig(key) };
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandBindingConfiguration(Commands command, IEnumerable<KeyConfig> keys)
|
public string GetKeysDisplayText()
|
||||||
|
{
|
||||||
|
var s = "";
|
||||||
|
|
||||||
|
foreach (var k in Keys)
|
||||||
{
|
{
|
||||||
Keys = new List<KeyConfig>(keys);
|
var keyString = k.Key.ToString();
|
||||||
Command = command;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBindingConfiguration(Commands command, KeyConfig key)
|
if (keyString.Length == 1)
|
||||||
{
|
|
||||||
Keys = new List<KeyConfig>() { key };
|
|
||||||
Command = command;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBindingConfiguration(Commands command, IEnumerable<Key> keys)
|
|
||||||
{
|
|
||||||
Keys = keys.Select(k => new KeyConfig(k)).ToList();
|
|
||||||
Command = command;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBindingConfiguration(Commands command, Key key)
|
|
||||||
{
|
|
||||||
Keys = new List<KeyConfig>() { new KeyConfig(key) };
|
|
||||||
Command = command;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetKeysDisplayText()
|
|
||||||
{
|
|
||||||
var s = "";
|
|
||||||
|
|
||||||
foreach (var k in Keys)
|
|
||||||
{
|
{
|
||||||
var keyString = k.Key.ToString();
|
s += AddKeyWithCtrlOrAlt(k, s, (_, _, _) => k.Shift ? keyString.ToUpper() : keyString.ToLower());
|
||||||
|
}
|
||||||
if (keyString.Length == 1)
|
else
|
||||||
{
|
{
|
||||||
s += AddKeyWithCtrlOrAlt(k, s, (_, _, _) => k.Shift ? keyString.ToUpper() : keyString.ToLower());
|
s += AddKeyWithCtrlOrAlt(k, s, AddSpecialKey);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s += AddKeyWithCtrlOrAlt(k, s, AddSpecialKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func<KeyConfig, string, bool, string> keyProcessor)
|
return s;
|
||||||
{
|
}
|
||||||
var s = "";
|
|
||||||
|
|
||||||
bool ctrlOrAlt = key.Ctrl || key.Alt;
|
private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func<KeyConfig, string, bool, string> keyProcessor)
|
||||||
|
{
|
||||||
|
var s = "";
|
||||||
|
|
||||||
if (ctrlOrAlt && currentText.Length > 0 && currentText.Last() != ' ') s += " ";
|
bool ctrlOrAlt = key.Ctrl || key.Alt;
|
||||||
|
|
||||||
if (key.Ctrl) s += "CTRL+";
|
if (ctrlOrAlt && currentText.Length > 0 && currentText.Last() != ' ') s += " ";
|
||||||
if (key.Alt) s += "ALT+";
|
|
||||||
s += keyProcessor(key, currentText, ctrlOrAlt);
|
|
||||||
|
|
||||||
if (ctrlOrAlt) s += " ";
|
if (key.Ctrl) s += "CTRL+";
|
||||||
|
if (key.Alt) s += "ALT+";
|
||||||
|
s += keyProcessor(key, currentText, ctrlOrAlt);
|
||||||
|
|
||||||
return s;
|
if (ctrlOrAlt) s += " ";
|
||||||
}
|
|
||||||
|
|
||||||
private static string AddSpecialKey(KeyConfig key, string currentText, bool wasCtrlOrAlt)
|
return s;
|
||||||
{
|
}
|
||||||
var s = "";
|
|
||||||
|
|
||||||
if (currentText.Length > 0 && currentText.Last() != ' ' && !wasCtrlOrAlt) s += " ";
|
private static string AddSpecialKey(KeyConfig key, string currentText, bool wasCtrlOrAlt)
|
||||||
s += key.Key.ToString();
|
{
|
||||||
if (!wasCtrlOrAlt) s += " ";
|
var s = "";
|
||||||
|
|
||||||
return s;
|
if (currentText.Length > 0 && currentText.Last() != ' ' && !wasCtrlOrAlt) s += " ";
|
||||||
}
|
s += key.Key.ToString();
|
||||||
|
if (!wasCtrlOrAlt) s += " ";
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public class KeyBindingConfiguration
|
||||||
{
|
{
|
||||||
public class KeyBindingConfiguration
|
public bool UseDefaultBindings { get; set; } = true;
|
||||||
{
|
public List<CommandBindingConfiguration> DefaultKeyBindings { get; set; } = new();
|
||||||
public bool UseDefaultBindings { get; set; } = true;
|
public List<CommandBindingConfiguration> KeyBindings { get; set; } = new();
|
||||||
public List<CommandBindingConfiguration> DefaultKeyBindings { get; set; } = new();
|
|
||||||
public List<CommandBindingConfiguration> KeyBindings { get; set; } = new();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,32 +1,31 @@
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public class KeyConfig
|
||||||
{
|
{
|
||||||
public class KeyConfig
|
public Key Key { get; set; }
|
||||||
|
public bool Shift { get; set; }
|
||||||
|
public bool Alt { get; set; }
|
||||||
|
public bool Ctrl { get; set; }
|
||||||
|
|
||||||
|
public KeyConfig() { }
|
||||||
|
|
||||||
|
public KeyConfig(
|
||||||
|
Key key,
|
||||||
|
bool shift = false,
|
||||||
|
bool alt = false,
|
||||||
|
bool ctrl = false)
|
||||||
{
|
{
|
||||||
public Key Key { get; set; }
|
Key = key;
|
||||||
public bool Shift { get; set; }
|
Shift = shift;
|
||||||
public bool Alt { get; set; }
|
Alt = alt;
|
||||||
public bool Ctrl { get; set; }
|
Ctrl = ctrl;
|
||||||
|
|
||||||
public KeyConfig() { }
|
|
||||||
|
|
||||||
public KeyConfig(
|
|
||||||
Key key,
|
|
||||||
bool shift = false,
|
|
||||||
bool alt = false,
|
|
||||||
bool ctrl = false)
|
|
||||||
{
|
|
||||||
Key = key;
|
|
||||||
Shift = shift;
|
|
||||||
Alt = alt;
|
|
||||||
Ctrl = ctrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AreEquals(KeyConfig otherKeyConfig) =>
|
|
||||||
Key == otherKeyConfig.Key
|
|
||||||
&& Alt == otherKeyConfig.Alt
|
|
||||||
&& Shift == otherKeyConfig.Shift
|
|
||||||
&& Ctrl == otherKeyConfig.Ctrl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AreEquals(KeyConfig otherKeyConfig) =>
|
||||||
|
Key == otherKeyConfig.Key
|
||||||
|
&& Alt == otherKeyConfig.Alt
|
||||||
|
&& Shift == otherKeyConfig.Shift
|
||||||
|
&& Ctrl == otherKeyConfig.Ctrl;
|
||||||
}
|
}
|
||||||
@@ -3,125 +3,124 @@ using FileTime.App.Core.Command;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public static class MainConfiguration
|
||||||
{
|
{
|
||||||
public static class MainConfiguration
|
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
||||||
|
|
||||||
|
public static Dictionary<string, string> Configuration { get; }
|
||||||
|
|
||||||
|
static MainConfiguration()
|
||||||
{
|
{
|
||||||
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
Configuration = new();
|
||||||
|
PopulateDefaultEditorPrograms(Configuration);
|
||||||
|
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
||||||
|
}
|
||||||
|
|
||||||
public static Dictionary<string, string> Configuration { get; }
|
private static void PopulateDefaultKeyBindings(Dictionary<string, string> configuration, List<CommandBindingConfiguration> commandBindingConfigs, string basePath)
|
||||||
|
{
|
||||||
static MainConfiguration()
|
for (var i = 0; i < commandBindingConfigs.Count; i++)
|
||||||
{
|
{
|
||||||
Configuration = new();
|
var baseKey = basePath + $":[{i}]:";
|
||||||
PopulateDefaultEditorPrograms(Configuration);
|
var commandBindingConfig = commandBindingConfigs[i];
|
||||||
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
configuration.Add(baseKey + nameof(CommandBindingConfiguration.Command), commandBindingConfig.Command.ToString());
|
||||||
}
|
|
||||||
|
|
||||||
private static void PopulateDefaultKeyBindings(Dictionary<string, string> configuration, List<CommandBindingConfiguration> commandBindingConfigs, string basePath)
|
for (var j = 0; j < commandBindingConfig.Keys.Count; j++)
|
||||||
{
|
|
||||||
for (var i = 0; i < commandBindingConfigs.Count; i++)
|
|
||||||
{
|
{
|
||||||
var baseKey = basePath + $":[{i}]:";
|
var key = commandBindingConfig.Keys[j];
|
||||||
var commandBindingConfig = commandBindingConfigs[i];
|
var keyBaseKey = baseKey + $"keys:[{j}]:";
|
||||||
configuration.Add(baseKey + nameof(CommandBindingConfiguration.Command), commandBindingConfig.Command.ToString());
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString());
|
||||||
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString());
|
||||||
for (var j = 0; j < commandBindingConfig.Keys.Count; j++)
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString());
|
||||||
{
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString());
|
||||||
var key = commandBindingConfig.Keys[j];
|
|
||||||
var keyBaseKey = baseKey + $"keys:[{j}]:";
|
|
||||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString());
|
|
||||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString());
|
|
||||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString());
|
|
||||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static List<CommandBindingConfiguration> InitDefaultKeyBindings()
|
private static List<CommandBindingConfiguration> InitDefaultKeyBindings()
|
||||||
|
{
|
||||||
|
return new List<CommandBindingConfiguration>()
|
||||||
{
|
{
|
||||||
return new List<CommandBindingConfiguration>()
|
new CommandBindingConfiguration(Commands.AutoRefresh, new KeyConfig(Key.R, shift: true)),
|
||||||
{
|
new CommandBindingConfiguration(Commands.ChangeTimelineMode, new[] { Key.T, Key.M }),
|
||||||
new CommandBindingConfiguration(Commands.AutoRefresh, new KeyConfig(Key.R, shift: true)),
|
new CommandBindingConfiguration(Commands.CloseTab, Key.Q),
|
||||||
new CommandBindingConfiguration(Commands.ChangeTimelineMode, new[] { Key.T, Key.M }),
|
new CommandBindingConfiguration(Commands.Compress, new[] { Key.Y, Key.C }),
|
||||||
new CommandBindingConfiguration(Commands.CloseTab, Key.Q),
|
new CommandBindingConfiguration(Commands.Copy, new[] { Key.Y, Key.Y }),
|
||||||
new CommandBindingConfiguration(Commands.Compress, new[] { Key.Y, Key.C }),
|
new CommandBindingConfiguration(Commands.CopyHash, new[] { Key.C, Key.H }),
|
||||||
new CommandBindingConfiguration(Commands.Copy, new[] { Key.Y, Key.Y }),
|
new CommandBindingConfiguration(Commands.CopyPath, new[] { Key.C, Key.P }),
|
||||||
new CommandBindingConfiguration(Commands.CopyHash, new[] { Key.C, Key.H }),
|
new CommandBindingConfiguration(Commands.CreateContainer, Key.F7),
|
||||||
new CommandBindingConfiguration(Commands.CopyPath, new[] { Key.C, Key.P }),
|
new CommandBindingConfiguration(Commands.CreateContainer, new[] { Key.C, Key.C }),
|
||||||
new CommandBindingConfiguration(Commands.CreateContainer, Key.F7),
|
new CommandBindingConfiguration(Commands.CreateElement, new[] { Key.C, Key.E }),
|
||||||
new CommandBindingConfiguration(Commands.CreateContainer, new[] { Key.C, Key.C }),
|
new CommandBindingConfiguration(Commands.Cut, new[] { Key.D, Key.D }),
|
||||||
new CommandBindingConfiguration(Commands.CreateElement, new[] { Key.C, Key.E }),
|
new CommandBindingConfiguration(Commands.Edit, new KeyConfig(Key.F4)),
|
||||||
new CommandBindingConfiguration(Commands.Cut, new[] { Key.D, Key.D }),
|
new CommandBindingConfiguration(Commands.EnterRapidTravel, new KeyConfig(Key.OemComma, shift: true)),
|
||||||
new CommandBindingConfiguration(Commands.Edit, new KeyConfig(Key.F4)),
|
new CommandBindingConfiguration(Commands.FindByName, new[] { Key.F, Key.N }),
|
||||||
new CommandBindingConfiguration(Commands.EnterRapidTravel, new KeyConfig(Key.OemComma, shift: true)),
|
new CommandBindingConfiguration(Commands.FindByNameRegex, new[] { Key.F, Key.R }),
|
||||||
new CommandBindingConfiguration(Commands.FindByName, new[] { Key.F, Key.N }),
|
new CommandBindingConfiguration(Commands.GoToHome, new[] { Key.G, Key.H }),
|
||||||
new CommandBindingConfiguration(Commands.FindByNameRegex, new[] { Key.F, Key.R }),
|
new CommandBindingConfiguration(Commands.GoToPath, new KeyConfig(Key.L, ctrl: true)),
|
||||||
new CommandBindingConfiguration(Commands.GoToHome, new[] { Key.G, Key.H }),
|
new CommandBindingConfiguration(Commands.GoToPath, new[] { Key.G, Key.P }),
|
||||||
new CommandBindingConfiguration(Commands.GoToPath, new KeyConfig(Key.L, ctrl: true)),
|
new CommandBindingConfiguration(Commands.GoToProvider, new[] { Key.G, Key.T }),
|
||||||
new CommandBindingConfiguration(Commands.GoToPath, new[] { Key.G, Key.P }),
|
new CommandBindingConfiguration(Commands.GoToRoot, new[] { Key.G, Key.R }),
|
||||||
new CommandBindingConfiguration(Commands.GoToProvider, new[] { Key.G, Key.T }),
|
new CommandBindingConfiguration(Commands.HardDelete, new[] { new KeyConfig(Key.D,shift: true), new KeyConfig(Key.D, shift: true) }),
|
||||||
new CommandBindingConfiguration(Commands.GoToRoot, new[] { Key.G, Key.R }),
|
new CommandBindingConfiguration(Commands.Mark, Key.Space),
|
||||||
new CommandBindingConfiguration(Commands.HardDelete, new[] { new KeyConfig(Key.D,shift: true), new KeyConfig(Key.D, shift: true) }),
|
new CommandBindingConfiguration(Commands.MoveToLast, new KeyConfig(Key.G, shift: true)),
|
||||||
new CommandBindingConfiguration(Commands.Mark, Key.Space),
|
new CommandBindingConfiguration(Commands.MoveToFirst, new[] { Key.G, Key.G }),
|
||||||
new CommandBindingConfiguration(Commands.MoveToLast, new KeyConfig(Key.G, shift: true)),
|
new CommandBindingConfiguration(Commands.NextTimelineBlock, Key.L ),
|
||||||
new CommandBindingConfiguration(Commands.MoveToFirst, new[] { Key.G, Key.G }),
|
new CommandBindingConfiguration(Commands.NextTimelineCommand, Key.J ),
|
||||||
new CommandBindingConfiguration(Commands.NextTimelineBlock, Key.L ),
|
new CommandBindingConfiguration(Commands.OpenInFileBrowser, new[] { Key.O, Key.E }),
|
||||||
new CommandBindingConfiguration(Commands.NextTimelineCommand, Key.J ),
|
new CommandBindingConfiguration(Commands.PasteMerge, new[] { Key.P, Key.P }),
|
||||||
new CommandBindingConfiguration(Commands.OpenInFileBrowser, new[] { Key.O, Key.E }),
|
new CommandBindingConfiguration(Commands.PasteOverwrite, new[] { Key.P, Key.O }),
|
||||||
new CommandBindingConfiguration(Commands.PasteMerge, new[] { Key.P, Key.P }),
|
new CommandBindingConfiguration(Commands.PasteSkip, new[] { Key.P, Key.S }),
|
||||||
new CommandBindingConfiguration(Commands.PasteOverwrite, new[] { Key.P, Key.O }),
|
new CommandBindingConfiguration(Commands.PinFavorite, new[] { Key.F, Key.P }),
|
||||||
new CommandBindingConfiguration(Commands.PasteSkip, new[] { Key.P, Key.S }),
|
new CommandBindingConfiguration(Commands.PreviousTimelineBlock, Key.H ),
|
||||||
new CommandBindingConfiguration(Commands.PinFavorite, new[] { Key.F, Key.P }),
|
new CommandBindingConfiguration(Commands.PreviousTimelineCommand, Key.K ),
|
||||||
new CommandBindingConfiguration(Commands.PreviousTimelineBlock, Key.H ),
|
new CommandBindingConfiguration(Commands.Refresh, Key.R),
|
||||||
new CommandBindingConfiguration(Commands.PreviousTimelineCommand, Key.K ),
|
new CommandBindingConfiguration(Commands.Rename, Key.F2),
|
||||||
new CommandBindingConfiguration(Commands.Refresh, Key.R),
|
new CommandBindingConfiguration(Commands.Rename, new[] { Key.C, Key.W }),
|
||||||
new CommandBindingConfiguration(Commands.Rename, Key.F2),
|
new CommandBindingConfiguration(Commands.RunCommand, new KeyConfig(Key.D4, shift: true)),
|
||||||
new CommandBindingConfiguration(Commands.Rename, new[] { Key.C, Key.W }),
|
new CommandBindingConfiguration(Commands.ScanContainerSize, new[] { Key.C, Key.S }),
|
||||||
new CommandBindingConfiguration(Commands.RunCommand, new KeyConfig(Key.D4, shift: true)),
|
new CommandBindingConfiguration(Commands.ShowAllShotcut, Key.F1),
|
||||||
new CommandBindingConfiguration(Commands.ScanContainerSize, new[] { Key.C, Key.S }),
|
new CommandBindingConfiguration(Commands.SoftDelete, new[] { new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true) }),
|
||||||
new CommandBindingConfiguration(Commands.ShowAllShotcut, Key.F1),
|
new CommandBindingConfiguration(Commands.SwitchToLastTab, Key.D9),
|
||||||
new CommandBindingConfiguration(Commands.SoftDelete, new[] { new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true) }),
|
new CommandBindingConfiguration(Commands.SwitchToTab1, Key.D1),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToLastTab, Key.D9),
|
new CommandBindingConfiguration(Commands.SwitchToTab2, Key.D2),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab1, Key.D1),
|
new CommandBindingConfiguration(Commands.SwitchToTab3, Key.D3),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab2, Key.D2),
|
new CommandBindingConfiguration(Commands.SwitchToTab4, Key.D4),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab3, Key.D3),
|
new CommandBindingConfiguration(Commands.SwitchToTab5, Key.D5),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab4, Key.D4),
|
new CommandBindingConfiguration(Commands.SwitchToTab6, Key.D6),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab5, Key.D5),
|
new CommandBindingConfiguration(Commands.SwitchToTab7, Key.D7),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab6, Key.D6),
|
new CommandBindingConfiguration(Commands.SwitchToTab8, Key.D8),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab7, Key.D7),
|
new CommandBindingConfiguration(Commands.TimelinePause, new[] { Key.T, Key.P }),
|
||||||
new CommandBindingConfiguration(Commands.SwitchToTab8, Key.D8),
|
new CommandBindingConfiguration(Commands.TimelineRefresh, new[] { Key.T, Key.R }),
|
||||||
new CommandBindingConfiguration(Commands.TimelinePause, new[] { Key.T, Key.P }),
|
new CommandBindingConfiguration(Commands.TimelineStart, new[] { Key.T, Key.S }),
|
||||||
new CommandBindingConfiguration(Commands.TimelineRefresh, new[] { Key.T, Key.R }),
|
new CommandBindingConfiguration(Commands.ToggleAdvancedIcons, new[] { Key.Z, Key.I }),
|
||||||
new CommandBindingConfiguration(Commands.TimelineStart, new[] { Key.T, Key.S }),
|
new CommandBindingConfiguration(Commands.GoUp, Key.Left),
|
||||||
new CommandBindingConfiguration(Commands.ToggleAdvancedIcons, new[] { Key.Z, Key.I }),
|
new CommandBindingConfiguration(Commands.Open, Key.Right),
|
||||||
new CommandBindingConfiguration(Commands.GoUp, Key.Left),
|
new CommandBindingConfiguration(Commands.OpenOrRun, Key.Enter),
|
||||||
new CommandBindingConfiguration(Commands.Open, Key.Right),
|
new CommandBindingConfiguration(Commands.MoveCursorUp, Key.Up),
|
||||||
new CommandBindingConfiguration(Commands.OpenOrRun, Key.Enter),
|
new CommandBindingConfiguration(Commands.MoveCursorDown, Key.Down),
|
||||||
new CommandBindingConfiguration(Commands.MoveCursorUp, Key.Up),
|
new CommandBindingConfiguration(Commands.MoveCursorUpPage, Key.PageUp),
|
||||||
new CommandBindingConfiguration(Commands.MoveCursorDown, Key.Down),
|
new CommandBindingConfiguration(Commands.MoveCursorDownPage, Key.PageDown),
|
||||||
new CommandBindingConfiguration(Commands.MoveCursorUpPage, Key.PageUp),
|
};
|
||||||
new CommandBindingConfiguration(Commands.MoveCursorDownPage, Key.PageDown),
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PopulateDefaultEditorPrograms(Dictionary<string, string> configuration)
|
private static void PopulateDefaultEditorPrograms(Dictionary<string, string> configuration)
|
||||||
|
{
|
||||||
|
var editorPrograms = new List<ProgramConfiguration>()
|
||||||
{
|
{
|
||||||
var editorPrograms = new List<ProgramConfiguration>()
|
new ProgramConfiguration(@"c:\Program Files\Notepad++\notepad++.exe"),
|
||||||
{
|
new ProgramConfiguration("notepad.exe"),
|
||||||
new ProgramConfiguration(@"c:\Program Files\Notepad++\notepad++.exe"),
|
};
|
||||||
new ProgramConfiguration("notepad.exe"),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var i = 0; i < editorPrograms.Count; i++)
|
for (var i = 0; i < editorPrograms.Count; i++)
|
||||||
{
|
{
|
||||||
if (editorPrograms[i].Path is not string path) continue;
|
if (editorPrograms[i].Path is not string path) continue;
|
||||||
configuration.Add($"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}", path);
|
configuration.Add($"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}", path);
|
||||||
|
|
||||||
if (editorPrograms[i].Arguments is string arguments)
|
if (editorPrograms[i].Arguments is string arguments)
|
||||||
{
|
{
|
||||||
configuration.Add($"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}", arguments);
|
configuration.Add($"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}", arguments);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public class ProgramConfiguration
|
||||||
{
|
{
|
||||||
public class ProgramConfiguration
|
public string? Path { get; set; }
|
||||||
|
public string? Arguments { get; set; }
|
||||||
|
|
||||||
|
public ProgramConfiguration() { }
|
||||||
|
|
||||||
|
public ProgramConfiguration(string? path, string? arguments = null)
|
||||||
{
|
{
|
||||||
public string? Path { get; set; }
|
Path = path;
|
||||||
public string? Arguments { get; set; }
|
Arguments = arguments;
|
||||||
|
|
||||||
public ProgramConfiguration() { }
|
|
||||||
|
|
||||||
public ProgramConfiguration(string? path, string? arguments = null)
|
|
||||||
{
|
|
||||||
Path = path;
|
|
||||||
Arguments = arguments;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public class ProgramsConfiguration
|
||||||
{
|
{
|
||||||
public class ProgramsConfiguration
|
public List<ProgramConfiguration> DefaultEditorPrograms { get; set; } = new();
|
||||||
{
|
public List<ProgramConfiguration> EditorPrograms { get; set; } = new();
|
||||||
public List<ProgramConfiguration> DefaultEditorPrograms { get; set; } = new();
|
|
||||||
public List<ProgramConfiguration> EditorPrograms { get; set; } = new();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace FileTime.GuiApp.Configuration
|
namespace FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
|
public static class SectionNames
|
||||||
{
|
{
|
||||||
public static class SectionNames
|
public const string KeybindingSectionName = "KeyBindings";
|
||||||
{
|
public const string ProgramsSectionName = "Programs";
|
||||||
public const string KeybindingSectionName = "KeyBindings";
|
|
||||||
public const string ProgramsSectionName = "Programs";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="0.10.13" />
|
<PackageReference Include="Avalonia" Version="0.10.13" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
namespace FileTime.GuiApp.Models
|
namespace FileTime.GuiApp.Models;
|
||||||
{
|
|
||||||
public record SpecialKeysStatus(bool IsAltPressed, bool IsShiftPressed, bool IsCtrlPressed);
|
public record SpecialKeysStatus(bool IsAltPressed, bool IsShiftPressed, bool IsCtrlPressed);
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
namespace FileTime.GuiApp.Services
|
namespace FileTime.GuiApp.Services;
|
||||||
{
|
|
||||||
public interface IDefaultModeKeyInputHandler : IKeyInputHandler { }
|
public interface IDefaultModeKeyInputHandler : IKeyInputHandler { }
|
||||||
}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using FileTime.GuiApp.Models;
|
using FileTime.GuiApp.Models;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Services
|
namespace FileTime.GuiApp.Services;
|
||||||
|
|
||||||
|
public interface IKeyInputHandler
|
||||||
{
|
{
|
||||||
public interface IKeyInputHandler
|
Task HandleInputKey(Key key, SpecialKeysStatus specialKeysStatus, Action<bool> setHandled);
|
||||||
{
|
|
||||||
Task HandleInputKey(Key key, SpecialKeysStatus specialKeysStatus, Action<bool> setHandled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Services
|
namespace FileTime.GuiApp.Services;
|
||||||
|
|
||||||
|
public interface IKeyInputHandlerService
|
||||||
{
|
{
|
||||||
public interface IKeyInputHandlerService
|
Task ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled);
|
||||||
{
|
|
||||||
Task ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
using FileTime.GuiApp.Configuration;
|
using FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Services
|
namespace FileTime.GuiApp.Services;
|
||||||
|
|
||||||
|
public interface IKeyboardConfigurationService
|
||||||
{
|
{
|
||||||
public interface IKeyboardConfigurationService
|
IReadOnlyList<CommandBindingConfiguration> CommandBindings { get; }
|
||||||
{
|
IReadOnlyList<CommandBindingConfiguration> UniversalCommandBindings { get; }
|
||||||
IReadOnlyList<CommandBindingConfiguration> CommandBindings { get; }
|
IReadOnlyList<CommandBindingConfiguration> AllShortcut { get; }
|
||||||
IReadOnlyList<CommandBindingConfiguration> UniversalCommandBindings { get; }
|
|
||||||
IReadOnlyList<CommandBindingConfiguration> AllShortcut { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
namespace FileTime.GuiApp.Services
|
namespace FileTime.GuiApp.Services;
|
||||||
{
|
|
||||||
public interface IRapidTravelModeKeyInputHandler : IKeyInputHandler { }
|
public interface IRapidTravelModeKeyInputHandler : IKeyInputHandler { }
|
||||||
}
|
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.GuiApp.Configuration;
|
using FileTime.GuiApp.Configuration;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.ViewModels
|
namespace FileTime.GuiApp.ViewModels;
|
||||||
|
|
||||||
|
public interface IGuiAppState : IAppState
|
||||||
{
|
{
|
||||||
public interface IGuiAppState : IAppState
|
List<KeyConfig> PreviousKeys { get; }
|
||||||
{
|
bool IsAllShortcutVisible { get; set; }
|
||||||
List<KeyConfig> PreviousKeys { get; }
|
bool NoCommandFound { get; set; }
|
||||||
bool IsAllShortcutVisible { get; set; }
|
string? MessageBoxText { get; set; }
|
||||||
bool NoCommandFound { get; set; }
|
List<CommandBindingConfiguration> PossibleCommands { get; set; }
|
||||||
string? MessageBoxText { get; set; }
|
|
||||||
List<CommandBindingConfiguration> PossibleCommands { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -7,40 +7,39 @@ using FileTime.GuiApp.Views;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.GuiApp
|
namespace FileTime.GuiApp;
|
||||||
|
|
||||||
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
public partial class App : Application
|
static App()
|
||||||
{
|
{
|
||||||
static App()
|
DI.ServiceProvider ??= DependencyInjection
|
||||||
{
|
.RegisterDefaultServices()
|
||||||
DI.ServiceProvider ??= DependencyInjection
|
.AddConfiguration()
|
||||||
.RegisterDefaultServices()
|
.RegisterLogging()
|
||||||
.AddConfiguration()
|
.RegisterServices()
|
||||||
.RegisterLogging()
|
.AddViewModels()
|
||||||
.RegisterServices()
|
.BuildServiceProvider()
|
||||||
.AddViewModels()
|
.InitSerilog();
|
||||||
.BuildServiceProvider()
|
|
||||||
.InitSerilog();
|
|
||||||
|
|
||||||
var logger = DI.ServiceProvider.GetRequiredService<ILogger<App>>();
|
var logger = DI.ServiceProvider.GetRequiredService<ILogger<App>>();
|
||||||
logger.LogInformation("App initialization completed");
|
logger.LogInformation("App initialization completed");
|
||||||
}
|
}
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
|
{
|
||||||
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
desktop.MainWindow = new MainWindow
|
||||||
{
|
{
|
||||||
desktop.MainWindow = new MainWindow
|
DataContext = new MainWindowLoadingViewModel(),
|
||||||
{
|
};
|
||||||
DataContext = new MainWindowLoadingViewModel(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.OnFrameworkInitializationCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,11 @@
|
|||||||
<ApplicationIcon>filetime.ico</ApplicationIcon>
|
<ApplicationIcon>filetime.ico</ApplicationIcon>
|
||||||
<Version>0.0.1</Version>
|
<Version>0.0.1</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="filetime.ico" />
|
<Content Include="filetime.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ using System.IO;
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace FileTime.GuiApp
|
namespace FileTime.GuiApp;
|
||||||
|
|
||||||
|
public static class Program
|
||||||
{
|
{
|
||||||
public static class Program
|
public static string AppDataRoot { get; }
|
||||||
|
public static string EnvironmentName { get; }
|
||||||
|
|
||||||
|
static Program()
|
||||||
{
|
{
|
||||||
public static string AppDataRoot { get; }
|
|
||||||
public static string EnvironmentName { get; }
|
|
||||||
|
|
||||||
static Program()
|
|
||||||
{
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
EnvironmentName = "Development";
|
EnvironmentName = "Development";
|
||||||
|
|
||||||
AppDataRoot = Path.Combine(Environment.CurrentDirectory, "appdata");
|
AppDataRoot = Path.Combine(Environment.CurrentDirectory, "appdata");
|
||||||
#else
|
#else
|
||||||
EnvironmentName = "Release";
|
EnvironmentName = "Release";
|
||||||
|
|
||||||
@@ -43,20 +43,19 @@ namespace FileTime.GuiApp
|
|||||||
if (appDataRoot == null) throw new UnauthorizedAccessException();
|
if (appDataRoot == null) throw new UnauthorizedAccessException();
|
||||||
AppDataRoot = appDataRoot;
|
AppDataRoot = appDataRoot;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
|
||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
|
||||||
// yet and stuff might break.
|
|
||||||
[STAThread]
|
|
||||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
|
||||||
.StartWithClassicDesktopLifetime(args);
|
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
|
||||||
=> AppBuilder.Configure<App>()
|
|
||||||
.UsePlatformDetect()
|
|
||||||
.UseReactiveUI()
|
|
||||||
.LogToTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||||
|
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||||
|
// yet and stuff might break.
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||||
|
.StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
|
=> AppBuilder.Configure<App>()
|
||||||
|
.UsePlatformDetect()
|
||||||
|
.UseReactiveUI()
|
||||||
|
.LogToTrace();
|
||||||
}
|
}
|
||||||
@@ -11,70 +11,69 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Configuration;
|
using Serilog.Configuration;
|
||||||
|
|
||||||
namespace FileTime.GuiApp
|
namespace FileTime.GuiApp;
|
||||||
|
|
||||||
|
public static class Startup
|
||||||
{
|
{
|
||||||
public static class Startup
|
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
|
return serviceCollection
|
||||||
{
|
.AddSingleton<MainWindowViewModel>()
|
||||||
return serviceCollection
|
.AddSingleton<GuiAppState>()
|
||||||
.AddSingleton<MainWindowViewModel>()
|
.AddSingleton<IAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
|
||||||
.AddSingleton<GuiAppState>()
|
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>());
|
||||||
.AddSingleton<IAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
|
}
|
||||||
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>());
|
internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection)
|
||||||
}
|
{
|
||||||
internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection)
|
return serviceCollection
|
||||||
{
|
.AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>()
|
||||||
return serviceCollection
|
.AddSingleton<IKeyInputHandlerService, KeyInputHandlerService>()
|
||||||
.AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>()
|
.AddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>()
|
||||||
.AddSingleton<IKeyInputHandlerService, KeyInputHandlerService>()
|
.AddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>()
|
||||||
.AddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>()
|
.AddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>();
|
||||||
.AddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>()
|
}
|
||||||
.AddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
return serviceCollection.AddLogging(loggingBuilder =>
|
return serviceCollection.AddLogging(loggingBuilder =>
|
||||||
loggingBuilder.AddSerilog(dispose: true)
|
loggingBuilder.AddSerilog(dispose: true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection AddConfiguration(this IServiceCollection serviceCollection)
|
internal static IServiceCollection AddConfiguration(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
var configuration = new ConfigurationBuilder()
|
var configuration = new ConfigurationBuilder()
|
||||||
.AddInMemoryCollection(MainConfiguration.Configuration)
|
.AddInMemoryCollection(MainConfiguration.Configuration)
|
||||||
.AddJsonFile("appsettings.json", optional: true)
|
.AddJsonFile("appsettings.json", optional: true)
|
||||||
.AddJsonFile($"appsettings.{Program.EnvironmentName}.json", true)
|
.AddJsonFile($"appsettings.{Program.EnvironmentName}.json", true)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.Configure<ProgramsConfiguration>(configuration.GetSection(SectionNames.ProgramsSectionName))
|
.Configure<ProgramsConfiguration>(configuration.GetSection(SectionNames.ProgramsSectionName))
|
||||||
.Configure<KeyBindingConfiguration>(configuration.GetSection(SectionNames.KeybindingSectionName))
|
.Configure<KeyBindingConfiguration>(configuration.GetSection(SectionNames.KeybindingSectionName))
|
||||||
.AddSingleton<IConfiguration>(configuration);
|
.AddSingleton<IConfiguration>(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceProvider InitSerilog(this IServiceProvider serviceProvider)
|
internal static IServiceProvider InitSerilog(this IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.ReadFrom.Configuration(serviceProvider.GetService<IConfiguration>())
|
.ReadFrom.Configuration(serviceProvider.GetService<IConfiguration>())
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.WriteTo.File(
|
.WriteTo.File(
|
||||||
Path.Combine(Program.AppDataRoot, "logs", "appLog.log"),
|
Path.Combine(Program.AppDataRoot, "logs", "appLog.log"),
|
||||||
fileSizeLimitBytes: 10 * 1024 * 1024,
|
fileSizeLimitBytes: 10 * 1024 * 1024,
|
||||||
rollOnFileSizeLimit: true,
|
rollOnFileSizeLimit: true,
|
||||||
rollingInterval: RollingInterval.Day)
|
rollingInterval: RollingInterval.Day)
|
||||||
.WriteTo.MessageBoxSink(serviceProvider)
|
.WriteTo.MessageBoxSink(serviceProvider)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
|
|
||||||
return serviceProvider;
|
return serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static LoggerConfiguration MessageBoxSink(
|
internal static LoggerConfiguration MessageBoxSink(
|
||||||
this LoggerSinkConfiguration loggerConfiguration,
|
this LoggerSinkConfiguration loggerConfiguration,
|
||||||
IServiceProvider serviceProvider)
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
return loggerConfiguration.Sink(serviceProvider.GetService<ToastMessageSink>());
|
return loggerConfiguration.Sink(serviceProvider.GetService<ToastMessageSink>());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.GuiApp.Abstractions\FileTime.GuiApp.Abstractions.csproj" />
|
<ProjectReference Include="..\FileTime.GuiApp.Abstractions\FileTime.GuiApp.Abstractions.csproj" />
|
||||||
|
|||||||
@@ -2,23 +2,22 @@ using FileTime.App.Core.ViewModels;
|
|||||||
using FileTime.GuiApp.Configuration;
|
using FileTime.GuiApp.Configuration;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.ViewModels
|
namespace FileTime.GuiApp.ViewModels;
|
||||||
|
|
||||||
|
[ViewModel]
|
||||||
|
public partial class GuiAppState : AppStateBase, IGuiAppState
|
||||||
{
|
{
|
||||||
[ViewModel]
|
[Property]
|
||||||
public partial class GuiAppState : AppStateBase, IGuiAppState
|
private bool _isAllShortcutVisible;
|
||||||
{
|
|
||||||
[Property]
|
|
||||||
private bool _isAllShortcutVisible;
|
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private bool _noCommandFound;
|
private bool _noCommandFound;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private string? _messageBoxText;
|
private string? _messageBoxText;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private List<CommandBindingConfiguration> _possibleCommands = new();
|
private List<CommandBindingConfiguration> _possibleCommands = new();
|
||||||
|
|
||||||
public List<KeyConfig> PreviousKeys { get; } = new();
|
public List<KeyConfig> PreviousKeys { get; } = new();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,54 +1,53 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public enum ComparisonCondition
|
||||||
{
|
{
|
||||||
public enum ComparisonCondition
|
Equal,
|
||||||
|
GreaterThan,
|
||||||
|
LessThan,
|
||||||
|
LessThanOrEqual,
|
||||||
|
NotEqual,
|
||||||
|
GreaterThanOrEqual
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CompareConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public ComparisonCondition ComparisonCondition { get; set; } = ComparisonCondition.Equal;
|
||||||
|
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
Equal,
|
return Compare(value, parameter);
|
||||||
GreaterThan,
|
|
||||||
LessThan,
|
|
||||||
LessThanOrEqual,
|
|
||||||
NotEqual,
|
|
||||||
GreaterThanOrEqual
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CompareConverter : IValueConverter
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public ComparisonCondition ComparisonCondition { get; set; } = ComparisonCondition.Equal;
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
private bool Compare(object? value, object? parameter)
|
||||||
|
{
|
||||||
|
if (ComparisonCondition == ComparisonCondition.GreaterThan)
|
||||||
{
|
{
|
||||||
return Compare(value, parameter);
|
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt > parameterInt;
|
||||||
|
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble > parameterDouble;
|
||||||
|
else throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
else if (ComparisonCondition == ComparisonCondition.NotEqual)
|
||||||
|
{
|
||||||
|
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt != parameterInt;
|
||||||
|
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble != parameterDouble;
|
||||||
|
return value != parameter;
|
||||||
|
}
|
||||||
|
else if (ComparisonCondition == ComparisonCondition.Equal)
|
||||||
|
{
|
||||||
|
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt == parameterInt;
|
||||||
|
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble == parameterDouble;
|
||||||
|
else if (value?.GetType().IsEnum ?? false && Enum.TryParse(value.GetType(), parameter?.ToString(), out var _)) return value.ToString() == parameter?.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
return value == parameter;
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Compare(object? value, object? parameter)
|
|
||||||
{
|
|
||||||
if (ComparisonCondition == ComparisonCondition.GreaterThan)
|
|
||||||
{
|
|
||||||
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt > parameterInt;
|
|
||||||
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble > parameterDouble;
|
|
||||||
else throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
else if (ComparisonCondition == ComparisonCondition.NotEqual)
|
|
||||||
{
|
|
||||||
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt != parameterInt;
|
|
||||||
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble != parameterDouble;
|
|
||||||
return value != parameter;
|
|
||||||
}
|
|
||||||
else if (ComparisonCondition == ComparisonCondition.Equal)
|
|
||||||
{
|
|
||||||
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt == parameterInt;
|
|
||||||
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble == parameterDouble;
|
|
||||||
else if (value?.GetType().IsEnum ?? false && Enum.TryParse(value.GetType(), parameter?.ToString(), out var _)) return value.ToString() == parameter?.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return value == parameter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
{
|
|
||||||
public class DateTimeConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) =>
|
|
||||||
value is DateTime dateTime && parameter is string parameterS
|
|
||||||
? dateTime.ToString(parameterS)
|
|
||||||
: value;
|
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public class DateTimeConverter : IValueConverter
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) =>
|
||||||
}
|
value is DateTime dateTime && parameter is string parameterS
|
||||||
|
? dateTime.ToString(parameterS)
|
||||||
|
: value;
|
||||||
|
|
||||||
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,45 +1,44 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class ExceptionToStringConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class ExceptionToStringConverter : IValueConverter
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
if (value is not Exception e) return value;
|
||||||
|
|
||||||
|
if (e is UnauthorizedAccessException)
|
||||||
{
|
{
|
||||||
if (value is not Exception e) return value;
|
return e.Message;
|
||||||
|
}
|
||||||
if (e is UnauthorizedAccessException)
|
else if (e.InnerException != null)
|
||||||
{
|
{
|
||||||
return e.Message;
|
return TraverseInnerException(e);
|
||||||
}
|
|
||||||
else if (e.InnerException != null)
|
|
||||||
{
|
|
||||||
return TraverseInnerException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FormatException(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string TraverseInnerException(Exception e)
|
return FormatException(e);
|
||||||
{
|
}
|
||||||
string s = "";
|
|
||||||
if (e.InnerException != null) s += TraverseInnerException(e.InnerException) + Environment.NewLine;
|
|
||||||
else return FormatException(e);
|
|
||||||
|
|
||||||
s += "In: " + FormatException(e);
|
private static string TraverseInnerException(Exception e)
|
||||||
|
{
|
||||||
|
string s = "";
|
||||||
|
if (e.InnerException != null) s += TraverseInnerException(e.InnerException) + Environment.NewLine;
|
||||||
|
else return FormatException(e);
|
||||||
|
|
||||||
return s;
|
s += "In: " + FormatException(e);
|
||||||
}
|
|
||||||
|
|
||||||
private static string FormatException(Exception e)
|
return s;
|
||||||
{
|
}
|
||||||
return $"{e.Message} ({e.GetType().FullName})";
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
private static string FormatException(Exception e)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return $"{e.Message} ({e.GetType().FullName})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,47 +1,46 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class FormatSizeConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class FormatSizeConverter : IValueConverter
|
private const long OneKiloByte = 1024;
|
||||||
|
private const long OneMegaByte = OneKiloByte * 1024;
|
||||||
|
private const long OneGigaByte = OneMegaByte * 1024;
|
||||||
|
private const long OneTerraByte = OneGigaByte * 1024;
|
||||||
|
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
private const long OneKiloByte = 1024;
|
return (value, int.TryParse(parameter?.ToString(), out var prec)) switch
|
||||||
private const long OneMegaByte = OneKiloByte * 1024;
|
|
||||||
private const long OneGigaByte = OneMegaByte * 1024;
|
|
||||||
private const long OneTerraByte = OneGigaByte * 1024;
|
|
||||||
|
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
||||||
{
|
{
|
||||||
return (value, int.TryParse(parameter?.ToString(), out var prec)) switch
|
(long size, true) => ToSizeString(size, prec),
|
||||||
{
|
(long size, false) => ToSizeString(size),
|
||||||
(long size, true) => ToSizeString(size, prec),
|
(null, _) => "...",
|
||||||
(long size, false) => ToSizeString(size),
|
_ => value
|
||||||
(null, _) => "...",
|
};
|
||||||
_ => value
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToSizeString(long fileSize, int precision = 1)
|
||||||
|
{
|
||||||
|
var fileSizeD = (decimal)fileSize;
|
||||||
|
var (size, suffix) = fileSize switch
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
> OneTerraByte => (fileSizeD / OneTerraByte, "T"),
|
||||||
}
|
> OneGigaByte => (fileSizeD / OneGigaByte, "G"),
|
||||||
|
> OneMegaByte => (fileSizeD / OneMegaByte, "M"),
|
||||||
|
> OneKiloByte => (fileSizeD / OneKiloByte, "K"),
|
||||||
|
_ => (fileSizeD, "B")
|
||||||
|
};
|
||||||
|
|
||||||
public static string ToSizeString(long fileSize, int precision = 1)
|
var result = string.Format("{0:N" + precision + "}", size).Replace(',', '.');
|
||||||
{
|
|
||||||
var fileSizeD = (decimal)fileSize;
|
|
||||||
var (size, suffix) = fileSize switch
|
|
||||||
{
|
|
||||||
> OneTerraByte => (fileSizeD / OneTerraByte, "T"),
|
|
||||||
> OneGigaByte => (fileSizeD / OneGigaByte, "G"),
|
|
||||||
> OneMegaByte => (fileSizeD / OneMegaByte, "M"),
|
|
||||||
> OneKiloByte => (fileSizeD / OneKiloByte, "K"),
|
|
||||||
_ => (fileSizeD, "B")
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = string.Format("{0:N" + precision + "}", size).Replace(',', '.');
|
if (result.Contains('.')) result = result.TrimEnd('0').TrimEnd('.');
|
||||||
|
return result + " " + suffix;
|
||||||
if (result.Contains('.')) result = result.TrimEnd('0').TrimEnd('.');
|
|
||||||
return result + " " + suffix;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,22 +3,21 @@ using Avalonia.Data.Converters;
|
|||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class GetFileExtensionConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class GetFileExtensionConverter : IValueConverter
|
private IItemNameConverterService? _itemNameConverterService;
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
private IItemNameConverterService? _itemNameConverterService;
|
if (value is not string fullName) return value;
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
_itemNameConverterService ??= DI.ServiceProvider.GetRequiredService<IItemNameConverterService>();
|
||||||
{
|
|
||||||
if (value is not string fullName) return value;
|
|
||||||
_itemNameConverterService ??= DI.ServiceProvider.GetRequiredService<IItemNameConverterService>();
|
|
||||||
|
|
||||||
return _itemNameConverterService.GetFileExtension(fullName);
|
return _itemNameConverterService.GetFileExtension(fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,39 +3,38 @@ using Avalonia.Data.Converters;
|
|||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using FileTime.App.Core.Models.Enums;
|
using FileTime.App.Core.Models.Enums;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class ItemViewModeToBrushConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class ItemViewModeToBrushConverter : IValueConverter
|
public Brush? DefaultBrush { get; set; }
|
||||||
|
public Brush? AlternativeBrush { get; set; }
|
||||||
|
public Brush? SelectedBrush { get; set; }
|
||||||
|
public Brush? MarkedBrush { get; set; }
|
||||||
|
public Brush? MarkedSelectedBrush { get; set; }
|
||||||
|
public Brush? MarkedAlternativeBrush { get; set; }
|
||||||
|
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public Brush? DefaultBrush { get; set; }
|
if (value is ItemViewMode viewMode)
|
||||||
public Brush? AlternativeBrush { get; set; }
|
|
||||||
public Brush? SelectedBrush { get; set; }
|
|
||||||
public Brush? MarkedBrush { get; set; }
|
|
||||||
public Brush? MarkedSelectedBrush { get; set; }
|
|
||||||
public Brush? MarkedAlternativeBrush { get; set; }
|
|
||||||
|
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
||||||
{
|
{
|
||||||
if (value is ItemViewMode viewMode)
|
return viewMode switch
|
||||||
{
|
{
|
||||||
return viewMode switch
|
ItemViewMode.Default => DefaultBrush,
|
||||||
{
|
ItemViewMode.Alternative => AlternativeBrush,
|
||||||
ItemViewMode.Default => DefaultBrush,
|
ItemViewMode.Selected => SelectedBrush,
|
||||||
ItemViewMode.Alternative => AlternativeBrush,
|
ItemViewMode.Marked => MarkedBrush,
|
||||||
ItemViewMode.Selected => SelectedBrush,
|
ItemViewMode.MarkedSelected => MarkedSelectedBrush,
|
||||||
ItemViewMode.Marked => MarkedBrush,
|
ItemViewMode.MarkedAlternative => MarkedAlternativeBrush,
|
||||||
ItemViewMode.MarkedSelected => MarkedSelectedBrush,
|
_ => throw new NotImplementedException()
|
||||||
ItemViewMode.MarkedAlternative => MarkedAlternativeBrush,
|
};
|
||||||
_ => throw new NotImplementedException()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
return value;
|
||||||
{
|
}
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,35 +3,34 @@ using Avalonia.Data.Converters;
|
|||||||
using FileTime.App.Core.Models.Enums;
|
using FileTime.App.Core.Models.Enums;
|
||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class ItemViewModelIsAttributeTypeConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class ItemViewModelIsAttributeTypeConverter : IValueConverter
|
public bool Invert { get; set; }
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public bool Invert { get; set; }
|
var attributeType = GetAttributeType(value);
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
if (parameter == null) return attributeType;
|
||||||
{
|
var result = parameter is ItemAttributeType targetAttribute && attributeType == targetAttribute;
|
||||||
var attributeType = GetAttributeType(value);
|
if (Invert && parameter is ItemAttributeType) result = !result;
|
||||||
if (parameter == null) return attributeType;
|
return result;
|
||||||
var result = parameter is ItemAttributeType targetAttribute && attributeType == targetAttribute;
|
}
|
||||||
if (Invert && parameter is ItemAttributeType) result = !result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ItemAttributeType? GetAttributeType(object? value)
|
private static ItemAttributeType? GetAttributeType(object? value)
|
||||||
|
{
|
||||||
|
return value switch
|
||||||
{
|
{
|
||||||
return value switch
|
IFileViewModel => ItemAttributeType.File,
|
||||||
{
|
IContainerSizeContainerViewModel => ItemAttributeType.SizeContainer,
|
||||||
IFileViewModel => ItemAttributeType.File,
|
IElementViewModel => ItemAttributeType.Element,
|
||||||
IContainerSizeContainerViewModel => ItemAttributeType.SizeContainer,
|
IContainerViewModel => ItemAttributeType.Container,
|
||||||
IElementViewModel => ItemAttributeType.Element,
|
_ => null
|
||||||
IContainerViewModel => ItemAttributeType.Container,
|
};
|
||||||
_ => null
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,112 +4,111 @@ using Avalonia.Media;
|
|||||||
using FileTime.App.Core.Models;
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.GuiApp.ViewModels;
|
using FileTime.GuiApp.ViewModels;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class NamePartShrinkerConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
public class NamePartShrinkerConverter : IMultiValueConverter
|
private const int PixelPerChar = 8;
|
||||||
|
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
private const int PixelPerChar = 8;
|
if (values.Count > 0 && values[0] is IList<ItemNamePart> nameParts)
|
||||||
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
|
|
||||||
{
|
{
|
||||||
if (values.Count > 0 && values[0] is IList<ItemNamePart> nameParts)
|
var attributeWidth = values[2] is bool b && b ? 340 : 0;
|
||||||
|
var newNameParts = nameParts;
|
||||||
|
if (values.Count > 1 && values[1] is double width && width > 0)
|
||||||
{
|
{
|
||||||
var attributeWidth = values[2] is bool b && b ? 340 : 0;
|
newNameParts = GetNamePartsForWidth(nameParts, width - attributeWidth);
|
||||||
var newNameParts = nameParts;
|
|
||||||
if (values.Count > 1 && values[1] is double width && width > 0)
|
|
||||||
{
|
|
||||||
newNameParts = GetNamePartsForWidth(nameParts, width - attributeWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newNameParts.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList();
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return newNameParts.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ItemNamePart> GetNamePartsForWidth(IList<ItemNamePart> nameParts, double maxWidth)
|
||||||
|
{
|
||||||
|
//Best case, we are in the range
|
||||||
|
var textLength = nameParts.Select(p => p.Text.Length).Sum();
|
||||||
|
if (textLength * PixelPerChar <= maxWidth)
|
||||||
|
{
|
||||||
|
return nameParts.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ItemNamePart> GetNamePartsForWidth(IList<ItemNamePart> nameParts, double maxWidth)
|
//Trying at least with the special parts
|
||||||
|
var newNameParts = new ItemNamePart?[nameParts.Count];
|
||||||
|
for (var i = 0; i < nameParts.Count; i++)
|
||||||
{
|
{
|
||||||
//Best case, we are in the range
|
if (nameParts[i].IsSpecial)
|
||||||
var textLength = nameParts.Select(p => p.Text.Length).Sum();
|
|
||||||
if (textLength * PixelPerChar <= maxWidth)
|
|
||||||
{
|
{
|
||||||
return nameParts.ToList();
|
newNameParts[i] = nameParts[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Trying at least with the special parts
|
|
||||||
var newNameParts = new ItemNamePart?[nameParts.Count];
|
|
||||||
for (var i = 0; i < nameParts.Count; i++)
|
|
||||||
{
|
|
||||||
if (nameParts[i].IsSpecial)
|
|
||||||
{
|
|
||||||
newNameParts[i] = nameParts[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetNamePartsForWidthOptimistic(nameParts, newNameParts, maxWidth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ItemNamePart> GetNamePartsForWidthOptimistic(IList<ItemNamePart> nameParts, ItemNamePart?[] newNameParts, double maxWidth)
|
return GetNamePartsForWidthOptimistic(nameParts, newNameParts, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ItemNamePart> GetNamePartsForWidthOptimistic(IList<ItemNamePart> nameParts, ItemNamePart?[] newNameParts, double maxWidth)
|
||||||
|
{
|
||||||
|
var trimmedIndexes = new List<int>();
|
||||||
|
for (var i = 0; i < newNameParts.Length; i++)
|
||||||
{
|
{
|
||||||
var trimmedIndexes = new List<int>();
|
if (newNameParts[i] == null)
|
||||||
for (var i = 0; i < newNameParts.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (newNameParts[i] == null)
|
trimmedIndexes.Add(i);
|
||||||
{
|
newNameParts[i] = new ItemNamePart("...");
|
||||||
trimmedIndexes.Add(i);
|
|
||||||
newNameParts[i] = new ItemNamePart("...");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var textLength = newNameParts.Select(p => p?.Text.Length ?? 0).Sum();
|
|
||||||
if (textLength * PixelPerChar > maxWidth)
|
|
||||||
{
|
|
||||||
return GetNamePartsForWidthPessimistic(nameParts, maxWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var trimmedIndex in trimmedIndexes)
|
|
||||||
{
|
|
||||||
var baseTextLength = newNameParts.Select((p, i) => i == trimmedIndex ? 0 : (p?.Text.Length ?? 0)).Sum();
|
|
||||||
var proposedText = nameParts[trimmedIndex].Text;
|
|
||||||
var trimmed = false;
|
|
||||||
while ((baseTextLength + proposedText.Length + (trimmed ? 3 : 0)) * PixelPerChar > maxWidth)
|
|
||||||
{
|
|
||||||
proposedText = proposedText[0..^1];
|
|
||||||
trimmed = true;
|
|
||||||
}
|
|
||||||
newNameParts[trimmedIndex] = new ItemNamePart(proposedText + (trimmed ? "..." : ""));
|
|
||||||
if (trimmed) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newNameParts.Where(f => f is not null).ToList()!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ItemNamePart> GetNamePartsForWidthPessimistic(IList<ItemNamePart> nameParts, double maxWidth)
|
var textLength = newNameParts.Select(p => p?.Text.Length ?? 0).Sum();
|
||||||
|
if (textLength * PixelPerChar > maxWidth)
|
||||||
{
|
{
|
||||||
var newNameParts = new List<ItemNamePart>(nameParts);
|
return GetNamePartsForWidthPessimistic(nameParts, maxWidth);
|
||||||
foreach (var namePart in nameParts)
|
|
||||||
{
|
|
||||||
var baseTextLength = newNameParts.Select(p => p.Text.Length).Sum();
|
|
||||||
var proposedText = namePart.Text;
|
|
||||||
var trimmed = false;
|
|
||||||
|
|
||||||
while ((baseTextLength + 3) * PixelPerChar > maxWidth && proposedText != "")
|
|
||||||
{
|
|
||||||
proposedText = proposedText[0..^1];
|
|
||||||
trimmed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(proposedText)) newNameParts.Add(new ItemNamePart(proposedText, namePart.IsSpecial));
|
|
||||||
if (trimmed) break;
|
|
||||||
}
|
|
||||||
if (newNameParts.Last().IsSpecial)
|
|
||||||
{
|
|
||||||
newNameParts.Add(new ItemNamePart("..."));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var last = newNameParts.Last();
|
|
||||||
last.Text += "...";
|
|
||||||
}
|
|
||||||
return newNameParts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var trimmedIndex in trimmedIndexes)
|
||||||
|
{
|
||||||
|
var baseTextLength = newNameParts.Select((p, i) => i == trimmedIndex ? 0 : (p?.Text.Length ?? 0)).Sum();
|
||||||
|
var proposedText = nameParts[trimmedIndex].Text;
|
||||||
|
var trimmed = false;
|
||||||
|
while ((baseTextLength + proposedText.Length + (trimmed ? 3 : 0)) * PixelPerChar > maxWidth)
|
||||||
|
{
|
||||||
|
proposedText = proposedText[0..^1];
|
||||||
|
trimmed = true;
|
||||||
|
}
|
||||||
|
newNameParts[trimmedIndex] = new ItemNamePart(proposedText + (trimmed ? "..." : ""));
|
||||||
|
if (trimmed) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newNameParts.Where(f => f is not null).ToList()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ItemNamePart> GetNamePartsForWidthPessimistic(IList<ItemNamePart> nameParts, double maxWidth)
|
||||||
|
{
|
||||||
|
var newNameParts = new List<ItemNamePart>(nameParts);
|
||||||
|
foreach (var namePart in nameParts)
|
||||||
|
{
|
||||||
|
var baseTextLength = newNameParts.Select(p => p.Text.Length).Sum();
|
||||||
|
var proposedText = namePart.Text;
|
||||||
|
var trimmed = false;
|
||||||
|
|
||||||
|
while ((baseTextLength + 3) * PixelPerChar > maxWidth && proposedText != "")
|
||||||
|
{
|
||||||
|
proposedText = proposedText[0..^1];
|
||||||
|
trimmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(proposedText)) newNameParts.Add(new ItemNamePart(proposedText, namePart.IsSpecial));
|
||||||
|
if (trimmed) break;
|
||||||
|
}
|
||||||
|
if (newNameParts.Last().IsSpecial)
|
||||||
|
{
|
||||||
|
newNameParts.Add(new ItemNamePart("..."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var last = newNameParts.Last();
|
||||||
|
last.Text += "...";
|
||||||
|
}
|
||||||
|
return newNameParts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,27 +1,26 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.Converters
|
namespace FileTime.GuiApp.Converters;
|
||||||
|
|
||||||
|
public class SplitStringConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class SplitStringConverter : IValueConverter
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
if (value is string path && parameter is string separator)
|
||||||
{
|
{
|
||||||
if (value is string path && parameter is string separator)
|
return path.Split(separator);
|
||||||
{
|
}
|
||||||
return path.Split(separator);
|
else if (value is string path2 && parameter is char separator2)
|
||||||
}
|
{
|
||||||
else if (value is string path2 && parameter is char separator2)
|
return path2.Split(separator2);
|
||||||
{
|
|
||||||
return path2.Split(separator2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
return value;
|
||||||
{
|
}
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user