From e0f37e1cd43a8bd1460b621ff69068fb2892a8b7 Mon Sep 17 00:00:00 2001 From: David Palmer Date: Sat, 3 Aug 2024 02:11:32 -0500 Subject: [PATCH] Added Open Project to Main Menu and implemented dialog interaction for opening an existing project. #27 #28 --- Horizon/View/Controls/MainMenu.xaml | 10 ++++++++ Horizon/View/Controls/MainMenu.xaml.cs | 6 +++++ Horizon/View/Windows/Workspace.xaml.cs | 32 ++++++++++++++++++++++++++ Horizon/ViewModel/CommandsViewModel.cs | 25 ++++++++++++++++++++ 4 files changed, 73 insertions(+) diff --git a/Horizon/View/Controls/MainMenu.xaml b/Horizon/View/Controls/MainMenu.xaml index 6736059..8842007 100644 --- a/Horizon/View/Controls/MainMenu.xaml +++ b/Horizon/View/Controls/MainMenu.xaml @@ -17,6 +17,16 @@ + + + + + + + + + + diff --git a/Horizon/View/Controls/MainMenu.xaml.cs b/Horizon/View/Controls/MainMenu.xaml.cs index 65e862a..d37b7cf 100644 --- a/Horizon/View/Controls/MainMenu.xaml.cs +++ b/Horizon/View/Controls/MainMenu.xaml.cs @@ -26,6 +26,12 @@ public MainMenu() .Select(x => new Unit()) .InvokeCommand(App.CommandsViewModel, x => x.NewProjectDialog) .DisposeWith(dispose); + + this.OpenProjectMenuItem.Events() + .Click + .Select(x => new Unit()) + .InvokeCommand(App.CommandsViewModel, x => x.OpenProjectDialog) + .DisposeWith(dispose); }); } } \ No newline at end of file diff --git a/Horizon/View/Windows/Workspace.xaml.cs b/Horizon/View/Windows/Workspace.xaml.cs index 1357455..a5bf6b1 100644 --- a/Horizon/View/Windows/Workspace.xaml.cs +++ b/Horizon/View/Windows/Workspace.xaml.cs @@ -1,5 +1,7 @@ using AvalonDock; using Horizon.Converters; +using Horizon.ObjectModel; +using Microsoft.WindowsAPICodePack.Dialogs; using ReactiveMarbles.ObservableEvents; using ReactiveUI; using System.Reactive; @@ -124,5 +126,35 @@ private void Interactions(CompositeDisposable dispose) }, RxApp.MainThreadScheduler); }) .DisposeWith(dispose); + + App.CommandsViewModel + .OpenProjectDialogInteraction + .RegisterHandler(interaction => + { + CommonOpenFileDialog fileDialog = new() { EnsureFileExists = true, Title = "Select a project file...", Multiselect = false }; + fileDialog.Filters.Add(new CommonFileDialogFilter("Project Files", "Project.horizon")); + + return Observable.StartAsync(async () => + { + if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok) + { + ProjectFile? project = await JsonFile.FromAbstractFile(fileDialog.FileName); + + if (project is not null) + { + interaction.SetOutput(project); + } + else + { + interaction.SetOutput(null); + } + } + else + { + interaction.SetOutput(null); + } + }, RxApp.MainThreadScheduler); + }) + .DisposeWith(dispose); } } \ No newline at end of file diff --git a/Horizon/ViewModel/CommandsViewModel.cs b/Horizon/ViewModel/CommandsViewModel.cs index 3f61f49..2e3b871 100644 --- a/Horizon/ViewModel/CommandsViewModel.cs +++ b/Horizon/ViewModel/CommandsViewModel.cs @@ -16,6 +16,7 @@ public sealed class CommandsViewModel : ReactiveObject public CommandsViewModel() { this.NewProjectDialog = ReactiveCommand.CreateFromTask(this.HandleNewProjectDialog); + this.OpenProjectDialog = ReactiveCommand.CreateFromTask(this.HandleOpenProjectDialog); } /// @@ -23,6 +24,16 @@ public CommandsViewModel() /// public ReactiveCommand NewProjectDialog { get; set; } + /// + /// Command that opens an "Open Project" file picker and waits for the interaction to complete. + /// + public ReactiveCommand OpenProjectDialog { get; set; } + + /// + /// Interaction that handles the "Open Project" dialog without blocking the UI. + /// + public Interaction OpenProjectDialogInteraction { get; } = new(); + /// /// Interaction that handles the "New Project" dialog without blocking the UI. /// @@ -74,6 +85,20 @@ private static async Task OpenProject(ProjectFile project) await LoadProject(project); } + /// + /// Handles the "Open Project" dialog and opens the selected project if the input is accepted. + /// + /// An awaitable . + private async Task HandleOpenProjectDialog() + { + ProjectFile? project = await this.OpenProjectDialogInteraction.Handle(Unit.Default); + + if (project is not null) + { + await OpenProject(project); + } + } + /// /// handles the "New Project" dialog and creates a new project if the input is accepted. ///