Skip to content

improve functions#732

Merged
YukiMatsuzawa merged 4 commits into
masterfrom
improve/addfunction_delete
May 25, 2026
Merged

improve functions#732
YukiMatsuzawa merged 4 commits into
masterfrom
improve/addfunction_delete

Conversation

@YuuKamegai
Copy link
Copy Markdown
Collaborator

Add function to delete current project by right clicking.
Chande the save timing of loded projects.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds UI support for removing a recent project via right-click and changes how the “recent projects” list is represented and persisted in the app (moving to an observable collection and updating settings on save).

Changes:

  • Added DeletePreviousProjectCommand to MainWindowVM and wired it to a new Delete context-menu item for recent projects.
  • Changed PreviousProjects from a ReadOnlyCollection backed by a List to a ReadOnlyObservableCollection backed by an ObservableCollection.
  • Updated recent-project list update/persistence logic to occur during SaveAsync() (and during deletion).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/MSDIAL5/MsdialGuiApp/ViewModel/Core/MainWindowVM.cs Adds a delete command and switches exposed PreviousProjects type to observable.
src/MSDIAL5/MsdialGuiApp/View/Core/MainWindow.xaml Adds context menu for deleting a recent project and introduces a BindingProxy resource.
src/MSDIAL5/MsdialGuiApp/Model/Core/ProjectModel.cs Minor formatting-only change (extra blank lines).
src/MSDIAL5/MsdialGuiApp/Model/Core/MainWindowModel.cs Converts recent projects storage to ObservableCollection, updates dedupe logic, persists recents on save, and adds delete method.
Comments suppressed due to low confidence (2)

src/MSDIAL5/MsdialGuiApp/Model/Core/MainWindowModel.cs:147

  • In LoadAsync(), the code awaits ProjectModel.LoadAsync(...).ConfigureAwait(false) and then mutates CurrentProject and _previousProjects. With _previousProjects now being an ObservableCollection bound to the UI, these mutations can run on a thread-pool thread and cause cross-thread exceptions. Resume on the UI thread for the post-load state updates (e.g., remove ConfigureAwait(false) here or dispatch the state/collection updates via the Dispatcher).
                    var loadedProject = await ProjectModel.LoadAsync(projectPath, _broker).ConfigureAwait(false);
                    if (loadedProject is null) {
                        _broker.Publish(new ShortMessageRequest("Project loading has failed."));
                        return;
                    }
                    CurrentProject = loadedProject;
                    var currentCrumb = new ProjectCrumb(loadedProject.Storage.ProjectParameter);
                    if (_previousProjects.Any(currentCrumb.MaybeSame)) {
                        var resembleProjects = _previousProjects.Where(currentCrumb.MaybeSame).ToList();
                        foreach (var resembleProject in resembleProjects)

src/MSDIAL5/MsdialGuiApp/Model/Core/MainWindowModel.cs:97

  • SaveAsync() removes only the first matching entry (_previousProjects.First(currentCrumb.MaybeSame)) while other code paths (load/new project) remove all matching entries. Because ProjectCrumb.MaybeSame() compares only Title, this can leave duplicate recent entries when multiple crumbs share a title. Consider removing all matches consistently (same approach as in SetNewProject()/LoadAsync()).
                var currentCrumb = new ProjectCrumb(CurrentProject.Storage.ProjectParameter);
                if (_previousProjects.Any(currentCrumb.MaybeSame))
                {
                    _previousProjects.Remove(_previousProjects.First(currentCrumb.MaybeSame));
                }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 91 to +99
using (nowSaving.ProcessStart()) {
await CurrentProject.SaveAsync().ConfigureAwait(false);
await CurrentProject.SaveAsync().ConfigureAwait(true);
var currentCrumb = new ProjectCrumb(CurrentProject.Storage.ProjectParameter);
if (_previousProjects.Any(currentCrumb.MaybeSame))
{
_previousProjects.Remove(_previousProjects.First(currentCrumb.MaybeSame));
}
_previousProjects.Insert(0, currentCrumb);
if (_previousProjects.Count > 50)
Comment on lines +204 to +212
public async Task DeleteProjectAsync(ProjectCrumb projectCrumb){
using (nowLoading.ProcessStart()){
try
{
if (projectCrumb.FilePath is null || !File.Exists(projectCrumb.FilePath))
{
return;
}
var resembleProjects = _previousProjects.Where(projectCrumb.MaybeSame).ToList();
Comment on lines +168 to +173
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete"
Command="{Binding Data, Source={StaticResource delete}}"
CommandParameter="{Binding}"/>
</ContextMenu>
Comment thread src/MSDIAL5/MsdialGuiApp/Model/Core/ProjectModel.cs Outdated
YukiMatsuzawa and others added 2 commits May 21, 2026 17:56
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (2)

src/MSDIAL5/MsdialGuiApp/Model/Core/MainWindowModel.cs:193

  • _previousProjects is an ObservableCollection, but it is modified after await ProjectModel.LoadAsync(...).ConfigureAwait(true). Using ConfigureAwait(true) here is inconsistent with the codebase’s general ConfigureAwait(false) usage and still doesn’t guarantee the continuation is on the WPF dispatcher if this method is invoked from a non-UI context. Prefer ConfigureAwait(false) for the load and explicitly dispatch the _previousProjects mutations to the UI thread.
                    var loadedProject = await ProjectModel.LoadAsync(projectCrumb.FilePath, _broker).ConfigureAwait(true);
                    if (loadedProject is null) {
                        _broker.Publish(new ShortMessageRequest("Project loading has failed."));
                        return;
                    }
                    CurrentProject = loadedProject;
                    var currentCrumb = new ProjectCrumb(loadedProject.Storage.ProjectParameter);
                    if (_previousProjects.Any(currentCrumb.MaybeSame)) {
                        var resembleProjects = _previousProjects.Where(currentCrumb.MaybeSame).ToList();
                        foreach (var resembleProject in resembleProjects)
                        {
                            _previousProjects.Remove(resembleProject);
                        }
                    }
                    _previousProjects.Insert(0, currentCrumb);
                    if (_previousProjects.Count > 50) {
                        while (_previousProjects.Count > 50) {
                            _previousProjects.RemoveAt(_previousProjects.Count - 1);
                        }
                    }

src/MSDIAL5/MsdialGuiApp/Model/Core/MainWindowModel.cs:214

  • The method name DeleteProjectAsync suggests deleting a project (potentially on disk), but the UI text is "Remove from recent projects" and the implementation only removes entries from _previousProjects/settings. Renaming this method/command to something like RemoveRecentProjectAsync (and corresponding RemovePreviousProjectCommand) would avoid confusion and reduce the risk of future misuse.
        public async Task DeleteProjectAsync(ProjectCrumb projectCrumb){
            using (nowLoading.ProcessStart()){
                try
                {
                    var resembleProjects = _previousProjects.Where(projectCrumb.MaybeSame).ToList();
                    foreach (var resembleProject in resembleProjects)
                    {
                        _previousProjects.Remove(resembleProject);
                    }
                    _settings.PreviousProjects = PreviousProjects.ToList();
                    _settings.Save();

</Button.ToolTip>
</Button>
<Button.ContextMenu>
<ContextMenu>
Comment on lines +146 to +156
var resembleProjects = _previousProjects.Where(currentCrumb.MaybeSame).ToList();
foreach (var resembleProject in resembleProjects)
{
_previousProjects.Remove(resembleProject);
}
}
_previousProjects.Insert(0, currentCrumb);
if (_previousProjects.Count > 50) {
_previousProjects.RemoveRange(50, _previousProjects.Count - 50);
while (_previousProjects.Count > 50) {
_previousProjects.RemoveAt(_previousProjects.Count - 1);
}
Comment on lines +92 to 107
await CurrentProject.SaveAsync().ConfigureAwait(true);
var currentCrumb = new ProjectCrumb(CurrentProject.Storage.ProjectParameter);
if (_previousProjects.Any(currentCrumb.MaybeSame))
{
_previousProjects.Remove(_previousProjects.First(currentCrumb.MaybeSame));
}
_previousProjects.Insert(0, currentCrumb);
if (_previousProjects.Count > 50)
{
while (_previousProjects.Count > 50)
{
_previousProjects.RemoveAt(_previousProjects.Count - 1);
}
}
_settings.PreviousProjects = PreviousProjects.ToList();
_settings.Save();
Comment on lines +94 to +96
if (_previousProjects.Any(currentCrumb.MaybeSame))
{
_previousProjects.Remove(_previousProjects.First(currentCrumb.MaybeSame));
Comment on lines +205 to +223
using (nowLoading.ProcessStart()){
try
{
var resembleProjects = _previousProjects.Where(projectCrumb.MaybeSame).ToList();
foreach (var resembleProject in resembleProjects)
{
_previousProjects.Remove(resembleProject);
}
_settings.PreviousProjects = PreviousProjects.ToList();
_settings.Save();
}
catch
{
await Application.Current.Dispatcher.InvokeAsync(() => {
MessageBox.Show("Failed to delete project.\nPlease check your project.");
return Task.CompletedTask;
});
}
}
@YukiMatsuzawa YukiMatsuzawa merged commit 4b5a1ec into master May 25, 2026
13 checks passed
@YukiMatsuzawa YukiMatsuzawa deleted the improve/addfunction_delete branch May 25, 2026 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants