More project base

This commit is contained in:
2022-04-01 20:38:43 +02:00
parent d0edf85e98
commit 8e09bf41bb
76 changed files with 3589 additions and 78 deletions

View File

@@ -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,
}
}

View File

@@ -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>

View 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);
}
}

View File

@@ -0,0 +1,10 @@
namespace FileTime.App.Core.Models.Enums
{
public enum ItemAttributeType
{
File,
Element,
Container,
SizeContainer
}
}

View File

@@ -0,0 +1,12 @@
namespace FileTime.App.Core.Models.Enums
{
public enum ItemViewMode
{
Default,
Alternative,
Selected,
Marked,
MarkedSelected,
MarkedAlternative
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public interface IContainerSizeContainerViewModel : IItemViewModel
{
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public interface IContainerViewModel : IItemViewModel
{
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public interface IElementViewModel : IItemViewModel
{
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public interface IFileViewModel : IElementViewModel
{
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View 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);
}
}
}

View 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>

View File

@@ -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];
}
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public class ContainerSizeContainerViewModel : ItemViewModel, IContainerSizeContainerViewModel
{
}
}

View File

@@ -0,0 +1,6 @@
namespace FileTime.App.Core.ViewModels
{
public class ContainerViewModel : ItemViewModel, IContainerViewModel
{
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public class ElementViewModel : ItemViewModel, IElementViewModel
{
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.App.Core.ViewModels
{
public class FileViewModel : ElementViewModel, IFileViewModel
{
}
}

View 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;
}
}

View 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;
}
}
}