DesignPreview WIP

This commit is contained in:
2023-07-18 07:48:13 +02:00
parent cd31104f8d
commit db32c7aef3
13 changed files with 389 additions and 23 deletions

View File

@@ -15,7 +15,7 @@ namespace FileTime.GuiApp.App;
public class App : Application
{
static App()
private static void InitializeApp()
{
var configuration = Startup.CreateConfiguration();
DI.ServiceProvider = DependencyInjection
@@ -33,13 +33,14 @@ public class App : Application
var logger = DI.ServiceProvider.GetRequiredService<ILogger<App>>();
logger.LogInformation("App initialization completed");
}
public override void Initialize() => AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
desktop.MainWindow = new MainWindow(InitializeApp)
{
DataContext = new MainWindowLoadingViewModel(),
};

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
<ProjectReference Include="..\FileTime.GuiApp.Abstractions\FileTime.GuiApp.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,59 @@
using System.Collections.ObjectModel;
using System.Reactive.Subjects;
using FileTime.App.Core.Models.Enums;
using FileTime.App.Core.ViewModels;
using FileTime.App.Core.ViewModels.Timeline;
using FileTime.Core.Models;
using FileTime.GuiApp.Configuration;
using FileTime.GuiApp.Models;
using FileTime.GuiApp.ViewModels;
namespace FileTime.GuiApp.DesignPreview.Services;
public class GuiAppStatePreview : IGuiAppState
{
public GuiAppStatePreview()
{
var tab = new TabViewModelPreview(this);
SelectedTab = new BehaviorSubject<ITabViewModel>(tab);
CurrentSelectedTab = tab;
var tabs = new ObservableCollection<ITabViewModel>(new [] {tab});
Tabs = new ReadOnlyObservableCollection<ITabViewModel>(tabs);
SearchText = new BehaviorSubject<string?>(null);
ViewMode = new BehaviorSubject<ViewMode>(FileTime.App.Core.Models.Enums.ViewMode.Default);
PreviousKeys = new();
ActivePanel = new BehaviorSubject<GuiPanel>(GuiPanel.FileBrowser);
PopupTexts = new ObservableCollection<string>();
}
public ReadOnlyObservableCollection<ITabViewModel> Tabs { get; }
public IObservable<ITabViewModel> SelectedTab { get; }
public IObservable<string?> SearchText { get; }
public IObservable<ViewMode> ViewMode { get; }
public string RapidTravelText { get; set; }
public ITabViewModel? CurrentSelectedTab { get; }
public ITimelineViewModel TimelineViewModel { get; }
public void SetSearchText(string? searchText) => throw new NotImplementedException();
public void SetSelectedTab(ITabViewModel tabToSelect) => throw new NotImplementedException();
public void SwitchViewMode(ViewMode newViewMode) => throw new NotImplementedException();
public void RemoveTab(ITabViewModel tabViewModel) => throw new NotImplementedException();
public void AddTab(ITabViewModel tabViewModel) => throw new NotImplementedException();
public List<KeyConfig> PreviousKeys { get; }
public bool IsAllShortcutVisible { get; set; }
public bool NoCommandFound { get; set; }
public List<CommandBindingConfiguration> PossibleCommands { get; set; }
public BindedCollection<RootDriveInfo, string> RootDriveInfos { get; set; }
public IReadOnlyList<PlaceInfo> Places { get; set; }
public ObservableCollection<string> PopupTexts { get; }
public IObservable<GuiPanel> ActivePanel { get; }
public void SetActivePanel(GuiPanel newPanel) => throw new NotImplementedException();
}

View File

@@ -0,0 +1,64 @@
using DynamicData;
using FileTime.Core.Enums;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
namespace FileTime.GuiApp.DesignPreview.Services;
public class ItemPreview
{
public static IContainer CurrentContainer { get; }
static ItemPreview()
{
var exceptions = new SourceList<Exception>();
CurrentContainer = new Container(
"HomePreview",
"HomePreview",
new FullName("local/root/test/path/HomePreview"),
new NativePath("/root/test/path/HomePreview"),
new AbsolutePath(
null!,
PointInTime.Present,
new FullName("local/root/test/path"),
AbsolutePathType.Container
),
false,
true,
DateTime.Now,
SupportsDelete.True,
true,
"attr",
null!,
false,
PointInTime.Present,
exceptions.Connect(),
new ExtensionCollection().AsReadOnly(),
new SourceCache<AbsolutePath, string>(a => a.Path.Path).Connect()
);
}
public static IElement GenerateElement(string name, string parentPath = "local/root/test/path/HomePreview") =>
new Element(
name,
name,
new FullName(parentPath + "/" + name),
new NativePath("/root/test/path/HomePreview/" + name),
new AbsolutePath(
null!,
PointInTime.Present,
new FullName(parentPath),
AbsolutePathType.Container
),
false,
true,
DateTime.Now,
SupportsDelete.True,
true,
"attr",
null!,
PointInTime.Present,
new SourceList<Exception>().Connect(),
new ExtensionCollection().AsReadOnly()
);
}

View File

@@ -0,0 +1,49 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.Core.Models;
using FileTime.Core.Services;
namespace FileTime.GuiApp.DesignPreview.Services;
public class TabPreview : ITab
{
public TabPreview()
{
var currentLocation = new BehaviorSubject<IContainer?>(ItemPreview.CurrentContainer);
CurrentLocation = currentLocation.AsObservable();
var currentItems = new SourceCache<IItem, string>(i => i.Name);
var items = GenerateItems();
currentItems.AddOrUpdate(items);
CurrentSelectedItemPreview = items[0];
CurrentItems = new BehaviorSubject<IObservable<IChangeSet<IItem, string>>>(currentItems.Connect());
CurrentSelectedItem = new BehaviorSubject<AbsolutePath?>(new AbsolutePath(null!, CurrentSelectedItemPreview));
}
public IItem CurrentSelectedItemPreview { get; }
private static List<IItem> GenerateItems()
=> Enumerable.Range(1, 10).Select(i => (IItem)ItemPreview.GenerateElement("Element" + i)).ToList();
public IObservable<IContainer?> CurrentLocation { get; }
public IObservable<AbsolutePath?> CurrentSelectedItem { get; }
public IObservable<IObservable<IChangeSet<IItem, string>>?> CurrentItems { get; }
public FullName? LastDeepestSelectedPath { get; }
public void SetCurrentLocation(IContainer newLocation) => throw new NotImplementedException();
public void AddItemFilter(ItemFilter filter) => throw new NotImplementedException();
public void RemoveItemFilter(ItemFilter filter) => throw new NotImplementedException();
public void RemoveItemFilter(string name) => throw new NotImplementedException();
public void SetSelectedItem(AbsolutePath newSelectedItem) => throw new NotImplementedException();
public void ForceSetCurrentLocation(IContainer newLocation) => throw new NotImplementedException();
public void Init(IContainer obj1) => throw new NotImplementedException();
public void Dispose()
{
}
}

View File

@@ -0,0 +1,118 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.App.Core.Models.Enums;
using FileTime.App.Core.Services;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
using FileTime.Core.Services;
namespace FileTime.GuiApp.DesignPreview.Services;
public class TabViewModelPreview : ITabViewModel
{
private static readonly ItemNameConverterService _itemNameConverterService = new();
public TabViewModelPreview(IAppState appState)
{
var tab = new TabPreview();
Tab = tab;
TabNumber = 1;
IsSelected = new BehaviorSubject<bool>(true);
CurrentLocation = tab.CurrentLocation;
IItemViewModel currentSelectedItem = tab.CurrentSelectedItemPreview is IContainer
? CreateCurrentSelectedItemContainer()
: CreateCurrentSelectedItemElement();
CurrentSelectedItem = new BehaviorSubject<IItemViewModel>(currentSelectedItem);
CurrentItems = tab.CurrentItems
.Select<IObservable<IChangeSet<IItem, string>>?, IObservable<IChangeSet<IItemViewModel, string>>?>(
items =>
items!.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main)));
ContainerViewModel CreateCurrentSelectedItemContainer()
{
var vm = new ContainerViewModel(
_itemNameConverterService,
appState
);
vm.Init(
(IContainer) tab.CurrentSelectedItemPreview,
this,
ItemViewModelType.Main
);
return vm;
}
ElementViewModel CreateCurrentSelectedItemElement()
{
var vm = new ElementViewModel(
_itemNameConverterService,
appState
);
vm.Init(
(IElement) tab.CurrentSelectedItemPreview,
this,
ItemViewModelType.Main
);
return vm;
}
IItemViewModel MapItemToViewModel(IItem item, ItemViewModelType type)
{
if (item is IContainer container)
{
var containerViewModel = new ContainerViewModel(_itemNameConverterService, appState);
containerViewModel.Init(container, this, type);
return containerViewModel;
}
else if (item is IElement element)
{
var elementViewModel = new ElementViewModel(_itemNameConverterService, appState);
elementViewModel.Init(element, this, type);
return elementViewModel;
}
throw new Exception();
}
}
public ITab? Tab { get; }
public int TabNumber { get; }
public IObservable<bool> IsSelected { get; }
public IObservable<IContainer?> CurrentLocation { get; }
public IObservable<IItemViewModel?> CurrentSelectedItem { get; }
public IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> CurrentItems { get; }
public IObservable<IChangeSet<FullName>> MarkedItems { get; }
public IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> SelectedsChildren { get; }
public IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> ParentsChildren { get; }
public BindedCollection<IItemViewModel, string>? CurrentItemsCollection { get; }
public BindedCollection<IItemViewModel, string>? SelectedsChildrenCollection { get; }
public BindedCollection<IItemViewModel, string>? ParentsChildrenCollection { get; }
public IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; }
public IObservable<IReadOnlyCollection<IItemViewModel>?> ParentsChildrenCollectionObservable { get; }
public IObservable<IReadOnlyCollection<IItemViewModel>?> SelectedsChildrenCollectionObservable { get; }
public IContainer? CachedCurrentLocation { get; }
public void ClearMarkedItems() => throw new NotImplementedException();
public void RemoveMarkedItem(FullName fullName) => throw new NotImplementedException();
public void AddMarkedItem(FullName fullName) => throw new NotImplementedException();
public void ToggleMarkedItem(FullName fullName) => throw new NotImplementedException();
public void Init(ITab obj1, int obj2)
{
}
public void Dispose()
{
}
}

View File

@@ -43,6 +43,7 @@
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj" />
<ProjectReference Include="..\..\..\Providers\FileTime.Providers.Local.Abstractions\FileTime.Providers.Local.Abstractions.csproj" />
<ProjectReference Include="..\FileTime.GuiApp.Abstractions\FileTime.GuiApp.Abstractions.csproj" />
<ProjectReference Include="..\FileTime.GuiApp.DesignPreview\FileTime.GuiApp.DesignPreview.csproj" />
<ProjectReference Include="..\FileTime.GuiApp.Font.Abstractions\FileTime.GuiApp.Font.Abstractions.csproj" />
</ItemGroup>

View File

@@ -0,0 +1,16 @@
using FileTime.App.CommandPalette.Services;
using FileTime.App.Core.Services;
using FileTime.App.FrequencyNavigation.Services;
using FileTime.GuiApp.Services;
namespace FileTime.GuiApp.ViewModels;
public interface IMainWindowViewModel : IMainWindowViewModelBase
{
string Title { get; }
IGuiAppState AppState { get; }
IItemPreviewService ItemPreviewService { get; }
IDialogService DialogService { get; }
IFrequencyNavigationService FrequencyNavigationService { get; }
ICommandPaletteService CommandPaletteService { get; }
}

View File

@@ -0,0 +1,25 @@
using System.Reactive.Subjects;
using FileTime.App.CommandPalette.Services;
using FileTime.App.Core.Services;
using FileTime.App.FrequencyNavigation.Services;
using FileTime.GuiApp.DesignPreview.Services;
using FileTime.GuiApp.Services;
namespace FileTime.GuiApp.ViewModels;
public class MainWindowDesignViewModel : IMainWindowViewModel
{
public bool Loading => false;
public IObservable<string?> MainFont { get; } = new BehaviorSubject<string?>("");
public string Title => "FileTime Design Preview";
public IGuiAppState AppState { get; }
public IItemPreviewService ItemPreviewService { get; }
public IDialogService DialogService { get; }
public IFrequencyNavigationService FrequencyNavigationService { get; }
public ICommandPaletteService CommandPaletteService { get; }
public MainWindowDesignViewModel()
{
AppState = new GuiAppStatePreview();
}
}

View File

@@ -28,7 +28,7 @@ namespace FileTime.GuiApp.ViewModels;
[Inject(typeof(IFontService), "_fontService")]
[Inject(typeof(IFrequencyNavigationService), PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(ICommandPaletteService), PropertyAccessModifier = AccessModifier.Public)]
public partial class MainWindowViewModel : IMainWindowViewModelBase
public partial class MainWindowViewModel : IMainWindowViewModel
{
public bool Loading => false;
public IObservable<string?> MainFont => _fontService.MainFont.Select(x => x ?? "");

View File

@@ -5,8 +5,8 @@
FontFamily="{Binding MainFont^, Mode=OneWay}"
Icon="/Assets/filetime.ico"
KeyDown="OnKeyDown"
MinHeight="600"
MinWidth="800"
MinHeight="800"
MinWidth="1000"
Opened="OnWindowOpened"
RequestedThemeVariant="Dark"
Title="FileTime"
@@ -44,7 +44,7 @@
</Window.Styles>
<Grid Background="{DynamicResource AppBackgroundBrush}">
<Grid IsVisible="{Binding Loading, Converter={x:Static BoolConverters.Not}, FallbackValue=False}" x:DataType="vm:MainWindowViewModel">
<Grid IsVisible="{Binding Loading, Converter={x:Static BoolConverters.Not}, FallbackValue=False}" x:DataType="vm:IMainWindowViewModel">
<Grid ColumnDefinitions="250,*" RowDefinitions="Auto,*">

View File

@@ -17,8 +17,9 @@ namespace FileTime.GuiApp.Views;
public partial class MainWindow : Window, IUiAccessor
{
private readonly ILogger<MainWindow>? _logger;
private readonly IModalService _modalService;
private readonly Action? _initializer;
private ILogger<MainWindow>? _logger;
private IModalService? _modalService;
private IReadOnlyCollection<IModalViewModel>? _openModals;
private ReadInputsViewModel? _inputViewModel;
private IDisposable? _inputViewModelSubscription;
@@ -37,29 +38,40 @@ public partial class MainWindow : Window, IUiAccessor
public MainWindow()
{
_logger = DI.ServiceProvider.GetService<ILogger<MainWindow>>();
_logger?.LogInformation($"Starting {nameof(MainWindow)} initialization...");
_modalService = DI.ServiceProvider.GetRequiredService<IModalService>();
_modalService.OpenModals.ToCollection().Subscribe(m => _openModals = m);
DI.ServiceProvider.GetRequiredService<Services.SystemClipboardService>().UiAccessor = this;
InitializeComponent();
ReadInputContainer.PropertyChanged += ReadInputContainerOnPropertyChanged;
DataContextChanged += (sender, args) =>
if (Design.IsDesignMode)
{
if (DataContext is not MainWindowViewModel mainWindowViewModel) return;
DataContext = new MainWindowDesignViewModel();
}
}
_inputViewModelSubscription?.Dispose();
_inputViewModelSubscription = mainWindowViewModel.DialogService.ReadInput.Subscribe(
inputViewModel => _inputViewModel = inputViewModel
);
};
public MainWindow(Action initializer) : this()
{
_initializer = initializer;
}
private void OnWindowOpened(object sender, EventArgs e)
{
if (DataContext is not MainWindowViewModel)
if (DataContext is not MainWindowViewModel && !Design.IsDesignMode)
{
_initializer?.Invoke();
_logger = DI.ServiceProvider.GetService<ILogger<MainWindow>>();
_modalService = DI.ServiceProvider.GetRequiredService<IModalService>();
_modalService.OpenModals.ToCollection().Subscribe(m => _openModals = m);
DI.ServiceProvider.GetRequiredService<Services.SystemClipboardService>().UiAccessor = this;
ReadInputContainer.PropertyChanged += ReadInputContainerOnPropertyChanged;
DataContextChanged += (_, _) =>
{
if (DataContext is not MainWindowViewModel mainWindowViewModel) return;
_inputViewModelSubscription?.Dispose();
_inputViewModelSubscription = mainWindowViewModel.DialogService.ReadInput.Subscribe(
inputViewModel => _inputViewModel = inputViewModel
);
};
_logger?.LogInformation(
$"{nameof(MainWindow)} opened, starting {nameof(MainWindowViewModel)} initialization...");
ViewModel = DI.ServiceProvider.GetRequiredService<MainWindowViewModel>();