From 9b9136d13c93d16bcb46e0e90b50aaff71053df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Gr=C3=BCtzmacher?= Date: Tue, 31 Oct 2023 16:54:48 +0100 Subject: [PATCH 1/2] Update recent list immediately after loading and saving project --- .../Infrastructure/ProjectFileLoader.cs | 8 +---- src/SimpleAccounting/Model/ProjectData.cs | 2 ++ .../Presentation/MenuViewModel.cs | 31 +++++++++++-------- .../Properties/Settings.Extensions.cs | 23 ++++++++++++++ .../Presentation/MenuViewModelTests.cs | 15 ++++++++- .../Presentation/ShellViewModelTests.cs | 2 +- 6 files changed, 59 insertions(+), 22 deletions(-) create mode 100644 src/SimpleAccounting/Properties/Settings.Extensions.cs diff --git a/src/SimpleAccounting/Infrastructure/ProjectFileLoader.cs b/src/SimpleAccounting/Infrastructure/ProjectFileLoader.cs index d31760cc..57c35f58 100644 --- a/src/SimpleAccounting/Infrastructure/ProjectFileLoader.cs +++ b/src/SimpleAccounting/Infrastructure/ProjectFileLoader.cs @@ -16,7 +16,6 @@ namespace lg2de.SimpleAccounting.Infrastructure; internal class ProjectFileLoader { - private const int MaxRecentProjects = 10; private readonly IFileSystem fileSystem; private readonly IDialogs dialogs; @@ -170,11 +169,6 @@ private void UpdateSettings(string projectFileName) this.settings.SecuredDrives.Add(info.RootPath); } - this.settings.RecentProjects.Remove(projectFileName); - this.settings.RecentProjects.Insert(0, projectFileName); - while (this.settings.RecentProjects.Count > MaxRecentProjects) - { - this.settings.RecentProjects.RemoveAt(MaxRecentProjects); - } + this.settings.SetRecentProject(projectFileName); } } diff --git a/src/SimpleAccounting/Model/ProjectData.cs b/src/SimpleAccounting/Model/ProjectData.cs index 9798c98c..2412419f 100644 --- a/src/SimpleAccounting/Model/ProjectData.cs +++ b/src/SimpleAccounting/Model/ProjectData.cs @@ -167,6 +167,8 @@ public void SaveProject() { this.fileSystem.FileDelete(this.AutoSaveFileName); } + + this.Settings.SetRecentProject(this.FileName); } public async Task AutoSaveAsync(CancellationToken cancellationToken) diff --git a/src/SimpleAccounting/Presentation/MenuViewModel.cs b/src/SimpleAccounting/Presentation/MenuViewModel.cs index 171f5541..a00e829b 100644 --- a/src/SimpleAccounting/Presentation/MenuViewModel.cs +++ b/src/SimpleAccounting/Presentation/MenuViewModel.cs @@ -59,7 +59,7 @@ public MenuViewModel( _ => this.OnOpenProject()); public ICommand SaveProjectCommand => new RelayCommand( - _ => this.projectData.SaveProject(), + _ => this.OnSaveProject(), _ => this.projectData.IsModified); public ICommand ProjectOptionsCommand => new RelayCommand( @@ -148,6 +148,7 @@ public void BuildRecentProjectsMenu() return; } + this.RecentProjects.Clear(); foreach (var project in this.projectData.Settings.RecentProjects.Cast()) { var command = new AsyncCommand(this.busy, () => this.OnLoadRecentProjectAsync(project)); @@ -167,20 +168,14 @@ public void OnDataLoaded() private async Task OnLoadRecentProjectAsync(string project) { var loadResult = await this.projectData.LoadFromFileAsync(project); - if (loadResult != OperationResult.Failed) + if (loadResult == OperationResult.Failed) { - return; - } - - // failed to load, remove from menu - // keep in menu if aborted (e.g. SecureDrive not available) - var item = this.RecentProjects.FirstOrDefault(x => x.Header == project); - if (item != null) - { - this.RecentProjects.Remove(item); + // failed to load, remove from menu + // keep in menu if aborted (e.g. SecureDrive not available) + this.projectData.Settings.RecentProjects.Remove(project); } - this.projectData.Settings.RecentProjects.Remove(project); + this.BuildRecentProjectsMenu(); } private void OnOpenProject() @@ -197,10 +192,20 @@ private void OnOpenProject() async () => { await this.projectData.LoadFromFileAsync(fileName); - await Execute.OnUIThreadAsync(() => this.busy.IsBusy = false); + await Execute.OnUIThreadAsync(() => + { + this.busy.IsBusy = false; + this.BuildRecentProjectsMenu(); + }); }); } + private void OnSaveProject() + { + this.projectData.SaveProject(); + this.BuildRecentProjectsMenu(); + } + private void UpdateBookingYears() { this.BookingYears.Clear(); diff --git a/src/SimpleAccounting/Properties/Settings.Extensions.cs b/src/SimpleAccounting/Properties/Settings.Extensions.cs new file mode 100644 index 00000000..af71fd23 --- /dev/null +++ b/src/SimpleAccounting/Properties/Settings.Extensions.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Lukas Grützmacher. All rights reserved. +// + +namespace lg2de.SimpleAccounting.Properties; + +using System.Collections.Specialized; + +internal sealed partial class Settings +{ + private const int MaxRecentProjects = 10; + + public void SetRecentProject(string projectFileName) + { + this.RecentProjects ??= new StringCollection(); + this.RecentProjects.Remove(projectFileName); + this.RecentProjects.Insert(0, projectFileName); + while (this.RecentProjects.Count > MaxRecentProjects) + { + this.RecentProjects.RemoveAt(MaxRecentProjects); + } + } +} diff --git a/tests/SimpleAccounting.UnitTests/Presentation/MenuViewModelTests.cs b/tests/SimpleAccounting.UnitTests/Presentation/MenuViewModelTests.cs index daa6d019..20f677c8 100644 --- a/tests/SimpleAccounting.UnitTests/Presentation/MenuViewModelTests.cs +++ b/tests/SimpleAccounting.UnitTests/Presentation/MenuViewModelTests.cs @@ -81,6 +81,18 @@ public void SwitchCultureCommand_DummyLanguage_MessageBoxShownAndConfigurationUp sut.IsSystemCulture.Should().BeFalse(); } + [Fact] + public void RecentProjects_SaveNewFile_AddedToList() + { + var sut = CreateSut(out ProjectData projectData); + sut.NewProjectCommand.Execute(null); + projectData.FileName = "this-is-the-file-name"; + + sut.SaveProjectCommand.Execute(null); + + sut.RecentProjects.Should().BeEquivalentTo(new[] { new { Header = "this-is-the-file-name" } }); + } + [Fact] public void NewProjectCommand_ModifiedProjectNoDiscard_ProjectRemains() { @@ -376,7 +388,8 @@ private static MenuViewModel CreateSut(out ProjectData projectData, out IReportF return sut; } - private static MenuViewModel CreateSut(out ProjectData projectData, out IDialogs dialogs, out IReportFactory reportFactory) + private static MenuViewModel CreateSut( + out ProjectData projectData, out IDialogs dialogs, out IReportFactory reportFactory) { var windowManager = Substitute.For(); var fileSystem = Substitute.For(); diff --git a/tests/SimpleAccounting.UnitTests/Presentation/ShellViewModelTests.cs b/tests/SimpleAccounting.UnitTests/Presentation/ShellViewModelTests.cs index 8fe303dc..addc4075 100644 --- a/tests/SimpleAccounting.UnitTests/Presentation/ShellViewModelTests.cs +++ b/tests/SimpleAccounting.UnitTests/Presentation/ShellViewModelTests.cs @@ -279,7 +279,7 @@ public async Task RecentFileCommand_FileOnSecureDriveNotStarted_ProjectKept() ((IActivate)sut).Activate(); sut.Menu.RecentProjects.Select(x => x.Header).Should().Equal("K:\\file1", "file2"); - foreach (var viewModel in sut.Menu.RecentProjects) + foreach (var viewModel in sut.Menu.RecentProjects.ToList()) { await viewModel.Command.ExecuteAsync(null); } From 5686bcfd7b704b469dafe80001f017ce83e5e644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Gr=C3=BCtzmacher?= Date: Sat, 9 Dec 2023 17:25:47 +0100 Subject: [PATCH 2/2] fix SQ issue --- .../Properties/Settings.Extensions.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/SimpleAccounting/Properties/Settings.Extensions.cs b/src/SimpleAccounting/Properties/Settings.Extensions.cs index af71fd23..693d8936 100644 --- a/src/SimpleAccounting/Properties/Settings.Extensions.cs +++ b/src/SimpleAccounting/Properties/Settings.Extensions.cs @@ -4,15 +4,20 @@ namespace lg2de.SimpleAccounting.Properties; -using System.Collections.Specialized; - internal sealed partial class Settings { private const int MaxRecentProjects = 10; + /// + /// Sets the specified project file (path) as the most recent project. + /// + /// + /// The list of recent projects is updated automatically. + /// + /// The full path of the recent project. public void SetRecentProject(string projectFileName) { - this.RecentProjects ??= new StringCollection(); + this.RecentProjects ??= []; this.RecentProjects.Remove(projectFileName); this.RecentProjects.Insert(0, projectFileName); while (this.RecentProjects.Count > MaxRecentProjects)