More project base
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
namespace FileTime.App.Core.Command
|
||||
{
|
||||
public enum Commands
|
||||
{
|
||||
None,
|
||||
|
||||
AutoRefresh,
|
||||
ChangeTimelineMode,
|
||||
CloseTab,
|
||||
Compress,
|
||||
Copy,
|
||||
CopyHash,
|
||||
CopyPath,
|
||||
CreateContainer,
|
||||
CreateElement,
|
||||
Cut,
|
||||
Edit,
|
||||
EnterRapidTravel,
|
||||
FindByName,
|
||||
FindByNameRegex,
|
||||
GoToHome,
|
||||
GoToPath,
|
||||
GoToProvider,
|
||||
GoToRoot,
|
||||
GoUp,
|
||||
HardDelete,
|
||||
Mark,
|
||||
MoveCursorDown,
|
||||
MoveCursorDownPage,
|
||||
MoveCursorUp,
|
||||
MoveCursorUpPage,
|
||||
MoveToFirst,
|
||||
MoveToLast,
|
||||
NextTimelineBlock,
|
||||
NextTimelineCommand,
|
||||
Open,
|
||||
OpenInFileBrowser,
|
||||
OpenOrRun,
|
||||
PasteMerge,
|
||||
PasteOverwrite,
|
||||
PasteSkip,
|
||||
PinFavorite,
|
||||
PreviousTimelineBlock,
|
||||
PreviousTimelineCommand,
|
||||
Refresh,
|
||||
Rename,
|
||||
RunCommand,
|
||||
ScanContainerSize,
|
||||
ShowAllShotcut,
|
||||
SoftDelete,
|
||||
SwitchToLastTab,
|
||||
SwitchToTab1,
|
||||
SwitchToTab2,
|
||||
SwitchToTab3,
|
||||
SwitchToTab4,
|
||||
SwitchToTab5,
|
||||
SwitchToTab6,
|
||||
SwitchToTab7,
|
||||
SwitchToTab8,
|
||||
TimelinePause,
|
||||
TimelineRefresh,
|
||||
TimelineStart,
|
||||
ToggleAdvancedIcons,
|
||||
ToggleHidden,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
src/AppCommon/FileTime.App.Core.Abstraction/IAppState.cs
Normal file
16
src/AppCommon/FileTime.App.Core.Abstraction/IAppState.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
|
||||
namespace FileTime.App.Core
|
||||
{
|
||||
public interface IAppState
|
||||
{
|
||||
ObservableCollection<ITabViewModel> Tabs { get; }
|
||||
ITabViewModel? SelectedTab { get; }
|
||||
IObservable<string?> SearchText { get; }
|
||||
|
||||
void AddTab(ITabViewModel tabViewModel);
|
||||
void RemoveTab(ITabViewModel tabViewModel);
|
||||
void SetSearchText(string? searchText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace FileTime.App.Core.Models.Enums
|
||||
{
|
||||
public enum ItemAttributeType
|
||||
{
|
||||
File,
|
||||
Element,
|
||||
Container,
|
||||
SizeContainer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace FileTime.App.Core.Models.Enums
|
||||
{
|
||||
public enum ItemViewMode
|
||||
{
|
||||
Default,
|
||||
Alternative,
|
||||
Selected,
|
||||
Marked,
|
||||
MarkedSelected,
|
||||
MarkedAlternative
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
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)
|
||||
{
|
||||
Text = text;
|
||||
IsSpecial = isSpecial;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Services
|
||||
{
|
||||
public interface IItemNameConverterService
|
||||
{
|
||||
List<ItemNamePart> GetDisplayName(string name, string? searchText);
|
||||
string GetFileExtension(string fullName);
|
||||
string GetFileName(string fullName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public interface IContainerSizeContainerViewModel : IItemViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public interface IContainerViewModel : IItemViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public interface IElementViewModel : IItemViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public interface IFileViewModel : IElementViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Models.Enums;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public interface IItemViewModel
|
||||
{
|
||||
IItem? Item { get; set; }
|
||||
IObservable<IReadOnlyList<ItemNamePart>>? DisplayName { get; set; }
|
||||
IObservable<bool>? IsSelected { get; set; }
|
||||
IObservable<bool>? IsMarked { get; set; }
|
||||
ItemViewMode ViewMode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Services;
|
||||
using InitableService;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public interface ITabViewModel : IInitable<ITab>
|
||||
{
|
||||
IObservable<IContainer?>? CurrentLocation { get; }
|
||||
IObservable<IItemViewModel?>? CurrentSelectedItem { get; }
|
||||
IObservable<IReadOnlyList<IItemViewModel>>? CurrentItems { get; }
|
||||
IObservable<IReadOnlyList<FullName>> MarkedItems { get; }
|
||||
ITab? Tab { get; }
|
||||
}
|
||||
}
|
||||
49
src/AppCommon/FileTime.App.Core/AppStateBase.cs
Normal file
49
src/AppCommon/FileTime.App.Core/AppStateBase.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using MvvmGen;
|
||||
|
||||
namespace FileTime.App.Core
|
||||
{
|
||||
[ViewModel]
|
||||
public abstract partial class AppStateBase : IAppState
|
||||
{
|
||||
private readonly BehaviorSubject<string?> _searchText = new(null);
|
||||
public ObservableCollection<ITabViewModel> Tabs { get; } = new();
|
||||
public IObservable<string?> SearchText { get; private set; }
|
||||
|
||||
[Property]
|
||||
private ITabViewModel? _selectedTab;
|
||||
|
||||
partial void OnInitialize()
|
||||
{
|
||||
SearchText = _searchText.AsObservable();
|
||||
}
|
||||
|
||||
public void AddTab(ITabViewModel tabViewModel)
|
||||
{
|
||||
Tabs.Add(tabViewModel);
|
||||
if (_selectedTab == null)
|
||||
{
|
||||
SelectedTab = Tabs.First();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveTab(ITabViewModel tabViewModel)
|
||||
{
|
||||
if (!Tabs.Contains(tabViewModel)) return;
|
||||
|
||||
Tabs.Remove(tabViewModel);
|
||||
if (_selectedTab == tabViewModel)
|
||||
{
|
||||
SelectedTab = Tabs.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSearchText(string? searchText)
|
||||
{
|
||||
_searchText.OnNext(searchText);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj
Normal file
19
src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MvvmGen" Version="1.1.5" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,56 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Services
|
||||
{
|
||||
public class ItemNameConverterService : IItemNameConverterService
|
||||
{
|
||||
public List<ItemNamePart> GetDisplayName(string name, string? searchText)
|
||||
{
|
||||
var nameParts = new List<ItemNamePart>();
|
||||
searchText = searchText?.ToLower();
|
||||
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
var nameLeft = name;
|
||||
|
||||
while (nameLeft.ToLower().IndexOf(searchText, StringComparison.Ordinal) is int rapidTextStart && rapidTextStart != -1)
|
||||
{
|
||||
var before = rapidTextStart > 0 ? nameLeft.Substring(0, rapidTextStart) : null;
|
||||
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(nameLeft));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nameParts.Add(new ItemNamePart(name));
|
||||
}
|
||||
return nameParts;
|
||||
}
|
||||
|
||||
public string GetFileName(string fullName)
|
||||
{
|
||||
var parts = fullName.Split('.');
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public class ContainerSizeContainerViewModel : ItemViewModel, IContainerSizeContainerViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public class ContainerViewModel : ItemViewModel, IContainerViewModel
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public class ElementViewModel : ItemViewModel, IElementViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public class FileViewModel : ElementViewModel, IFileViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
26
src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs
Normal file
26
src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Models.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using MvvmGen;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
[ViewModel]
|
||||
public abstract partial class ItemViewModel : IItemViewModel
|
||||
{
|
||||
[Property]
|
||||
private IItem? _item;
|
||||
|
||||
[Property]
|
||||
private IObservable<IReadOnlyList<ItemNamePart>>? _displayName;
|
||||
|
||||
[Property]
|
||||
private IObservable<bool>? _isSelected;
|
||||
|
||||
[Property]
|
||||
private IObservable<bool>? _isMarked;
|
||||
|
||||
[Property]
|
||||
private ItemViewMode _viewMode;
|
||||
}
|
||||
}
|
||||
105
src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs
Normal file
105
src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels
|
||||
{
|
||||
public class TabViewModel : ITabViewModel, IDisposable
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IItemNameConverterService _itemNameConverterService;
|
||||
private readonly IAppState _appState;
|
||||
private readonly BehaviorSubject<IEnumerable<FullName>> _markedItems = new(Enumerable.Empty<FullName>());
|
||||
private readonly List<IDisposable> _disposables = new();
|
||||
private bool disposed;
|
||||
|
||||
public IObservable<IContainer?>? CurrentLocation { get; private set; }
|
||||
public IObservable<IItemViewModel?>? CurrentSelectedItem { get; private set; }
|
||||
public IObservable<IReadOnlyList<IItemViewModel>>? CurrentItems { get; private set; }
|
||||
public IObservable<IReadOnlyList<FullName>> MarkedItems { get; }
|
||||
|
||||
public ITab? Tab { get; private set; }
|
||||
|
||||
public TabViewModel(
|
||||
IServiceProvider serviceProvider,
|
||||
IItemNameConverterService itemNameConverterService,
|
||||
IAppState appState)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_itemNameConverterService = itemNameConverterService;
|
||||
_appState = appState;
|
||||
|
||||
MarkedItems = _markedItems.Select(e => e.ToList()).AsObservable();
|
||||
}
|
||||
|
||||
public void Init(ITab tab)
|
||||
{
|
||||
CurrentLocation = tab.CurrentLocation.AsObservable();
|
||||
CurrentItems = tab.CurrentItems.Select(items => items.Select(MapItemToViewModel).ToList());
|
||||
CurrentSelectedItem = CurrentItems.CombineLatest(
|
||||
tab.CurrentSelectedItem,
|
||||
(currentItems, currentSelectedItemPath) => currentItems.FirstOrDefault(i => i.Item?.FullName == currentSelectedItemPath?.Path));
|
||||
tab.CurrentLocation.Subscribe((_) => _markedItems.OnNext(Enumerable.Empty<FullName>()));
|
||||
|
||||
Tab = tab;
|
||||
}
|
||||
|
||||
private IItemViewModel MapItemToViewModel(IItem item)
|
||||
{
|
||||
if (item is IContainer container)
|
||||
{
|
||||
var containerViewModel = _serviceProvider.GetRequiredService<IContainerViewModel>();
|
||||
InitIItemViewModel(containerViewModel, item);
|
||||
|
||||
return containerViewModel;
|
||||
}
|
||||
else if (item is IElement element)
|
||||
{
|
||||
var elementViewModel = _serviceProvider.GetRequiredService<IElementViewModel>();
|
||||
InitIItemViewModel(elementViewModel, item);
|
||||
|
||||
return elementViewModel;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"{nameof(item)} is not {nameof(IContainer)} neighter {nameof(IElement)}");
|
||||
|
||||
void InitIItemViewModel(IItemViewModel itemViewModel, IItem item)
|
||||
{
|
||||
itemViewModel.Item = item;
|
||||
itemViewModel.DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s));
|
||||
itemViewModel.IsMarked = MarkedItems.Select(m => m.Contains(item.FullName));
|
||||
itemViewModel.IsSelected = MarkedItems.Select(m => m.Contains(item.FullName));
|
||||
}
|
||||
}
|
||||
|
||||
~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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user