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