refactor: move context menu creation from ViewModels to Views (PART 9)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo
2025-07-23 16:15:30 +08:00
parent fa44d9c378
commit c08f15827f
3 changed files with 149 additions and 149 deletions

View File

@@ -844,10 +844,6 @@
<v:NameHighlightedTextBlock Text="{Binding}" VerticalAlignment="Center"/>
</DataTemplate>
<DataTemplate DataType="vm:CommitMessageRecord">
<TextBlock Text="{Binding Subject}" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"/>
</DataTemplate>
<DataTemplate DataType="vm:FilterModeInGraph">
<v:FilterModeInGraph/>
</DataTemplate>

View File

@@ -11,13 +11,13 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public record CommitMessageRecord(string subject)
{
public string Subject { get; set; } = subject;
}
public class WorkingCopy : ObservableObject, IDisposable
{
public Repository Repository
{
get => _repo;
}
public bool IncludeUntracked
{
get => _repo.IncludeUntracked;
@@ -564,6 +564,11 @@ namespace SourceGit.ViewModels
}
}
public void ApplyCommitMessageTemplate(Models.CommitTemplate tmpl)
{
CommitMessage = tmpl.Apply(_repo.CurrentBranch, _staged);
}
public void Commit()
{
DoCommit(false, false);
@@ -1602,137 +1607,6 @@ namespace SourceGit.ViewModels
return menu;
}
public ContextMenu CreateContextMenuForCommitMessages()
{
var menu = new ContextMenu();
var gitTemplate = new Commands.Config(_repo.FullPath).GetAsync("commit.template").Result;
var templateCount = _repo.Settings.CommitTemplates.Count;
if (templateCount == 0 && string.IsNullOrEmpty(gitTemplate))
{
menu.Items.Add(new MenuItem()
{
Header = App.Text("WorkingCopy.NoCommitTemplates"),
Icon = App.CreateMenuIcon("Icons.Code"),
IsEnabled = false
});
}
else
{
for (int i = 0; i < templateCount; i++)
{
var template = _repo.Settings.CommitTemplates[i];
var item = new MenuItem();
item.Header = App.Text("WorkingCopy.UseCommitTemplate", template.Name);
item.Icon = App.CreateMenuIcon("Icons.Code");
item.Click += (_, e) =>
{
CommitMessage = template.Apply(_repo.CurrentBranch, _staged);
e.Handled = true;
};
menu.Items.Add(item);
}
if (!string.IsNullOrEmpty(gitTemplate))
{
if (!Path.IsPathRooted(gitTemplate))
gitTemplate = Native.OS.GetAbsPath(_repo.FullPath, gitTemplate);
var friendlyName = gitTemplate;
if (!OperatingSystem.IsWindows())
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (gitTemplate.StartsWith(home, StringComparison.Ordinal))
friendlyName = $"~{gitTemplate.AsSpan(prefixLen)}";
}
var gitTemplateItem = new MenuItem();
gitTemplateItem.Header = App.Text("WorkingCopy.UseCommitTemplate", friendlyName);
gitTemplateItem.Icon = App.CreateMenuIcon("Icons.Code");
gitTemplateItem.Click += (_, e) =>
{
if (File.Exists(gitTemplate))
CommitMessage = File.ReadAllText(gitTemplate);
e.Handled = true;
};
menu.Items.Add(gitTemplateItem);
}
}
menu.Items.Add(new MenuItem() { Header = "-" });
var historiesCount = _repo.Settings.CommitMessages.Count;
if (historiesCount == 0)
{
menu.Items.Add(new MenuItem()
{
Header = App.Text("WorkingCopy.NoCommitHistories"),
Icon = App.CreateMenuIcon("Icons.Histories"),
IsEnabled = false
});
}
else
{
for (int i = 0; i < historiesCount; i++)
{
var dup = _repo.Settings.CommitMessages[i].Trim();
var message = dup.ReplaceLineEndings(" ");
var item = new MenuItem();
item.Header = new CommitMessageRecord(message);
item.Icon = App.CreateMenuIcon("Icons.Histories");
item.Click += (_, e) =>
{
CommitMessage = dup;
e.Handled = true;
};
menu.Items.Add(item);
}
}
return menu;
}
public ContextMenu CreateContextForOpenAI()
{
if (_staged == null || _staged.Count == 0)
{
App.RaiseException(_repo.FullPath, "No files added to commit!");
return null;
}
var services = _repo.GetPreferredOpenAIServices();
if (services.Count == 0)
{
App.RaiseException(_repo.FullPath, "Bad configuration for OpenAI");
return null;
}
if (services.Count == 1)
{
_ = App.ShowDialog(new AIAssistant(_repo, services[0], _staged, t => CommitMessage = t));
return null;
}
var menu = new ContextMenu() { Placement = PlacementMode.TopEdgeAlignedLeft };
foreach (var service in services)
{
var dup = service;
var item = new MenuItem();
item.Header = service.Name;
item.Click += async (_, e) =>
{
await App.ShowDialog(new AIAssistant(_repo, dup, _staged, t => CommitMessage = t));
e.Handled = true;
};
menu.Items.Add(item);
}
return menu;
}
private List<Models.Change> GetVisibleChanges(List<Models.Change> changes)
{
if (string.IsNullOrEmpty(_filter))

View File

@@ -1,9 +1,12 @@
using System;
using System.IO;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
namespace SourceGit.Views
{
@@ -170,11 +173,104 @@ namespace SourceGit.Views
}
}
private void OnOpenCommitMessagePicker(object sender, RoutedEventArgs e)
private async void OnOpenCommitMessagePicker(object sender, RoutedEventArgs e)
{
if (sender is Button button && DataContext is ViewModels.WorkingCopy vm)
if (sender is Button button && DataContext is ViewModels.WorkingCopy vm && ShowAdvancedOptions)
{
var menu = vm.CreateContextMenuForCommitMessages();
var repo = vm.Repository;
var menu = new ContextMenu();
var gitTemplate = await new Commands.Config(repo.FullPath).GetAsync("commit.template");
var templateCount = repo.Settings.CommitTemplates.Count;
if (templateCount == 0 && string.IsNullOrEmpty(gitTemplate))
{
menu.Items.Add(new MenuItem()
{
Header = App.Text("WorkingCopy.NoCommitTemplates"),
Icon = App.CreateMenuIcon("Icons.Code"),
IsEnabled = false
});
}
else
{
for (int i = 0; i < templateCount; i++)
{
var template = repo.Settings.CommitTemplates[i];
var item = new MenuItem();
item.Header = App.Text("WorkingCopy.UseCommitTemplate", template.Name);
item.Icon = App.CreateMenuIcon("Icons.Code");
item.Click += (_, e) =>
{
vm.ApplyCommitMessageTemplate(template);
e.Handled = true;
};
menu.Items.Add(item);
}
if (!string.IsNullOrEmpty(gitTemplate))
{
if (!Path.IsPathRooted(gitTemplate))
gitTemplate = Native.OS.GetAbsPath(repo.FullPath, gitTemplate);
var friendlyName = gitTemplate;
if (!OperatingSystem.IsWindows())
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
if (gitTemplate.StartsWith(home, StringComparison.Ordinal))
friendlyName = $"~{gitTemplate.AsSpan(prefixLen)}";
}
var gitTemplateItem = new MenuItem();
gitTemplateItem.Header = App.Text("WorkingCopy.UseCommitTemplate", friendlyName);
gitTemplateItem.Icon = App.CreateMenuIcon("Icons.Code");
gitTemplateItem.Click += (_, e) =>
{
if (File.Exists(gitTemplate))
vm.CommitMessage = File.ReadAllText(gitTemplate);
e.Handled = true;
};
menu.Items.Add(gitTemplateItem);
}
}
menu.Items.Add(new MenuItem() { Header = "-" });
var historiesCount = repo.Settings.CommitMessages.Count;
if (historiesCount == 0)
{
menu.Items.Add(new MenuItem()
{
Header = App.Text("WorkingCopy.NoCommitHistories"),
Icon = App.CreateMenuIcon("Icons.Histories"),
IsEnabled = false
});
}
else
{
for (int i = 0; i < historiesCount; i++)
{
var dup = repo.Settings.CommitMessages[i].Trim();
var header = new TextBlock()
{
Text = dup.ReplaceLineEndings(" "),
VerticalAlignment = VerticalAlignment.Center,
TextTrimming = TextTrimming.CharacterEllipsis
};
var item = new MenuItem();
item.Header = header;
item.Icon = App.CreateMenuIcon("Icons.Histories");
item.Click += (_, e) =>
{
vm.CommitMessage = dup;
e.Handled = true;
};
menu.Items.Add(item);
}
}
menu.Placement = PlacementMode.TopEdgeAlignedLeft;
menu.Open(button);
}
@@ -182,25 +278,59 @@ namespace SourceGit.Views
e.Handled = true;
}
private void OnOpenOpenAIHelper(object sender, RoutedEventArgs e)
private async void OnOpenOpenAIHelper(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.WorkingCopy vm && sender is Control control)
if (DataContext is ViewModels.WorkingCopy vm && sender is Control control && ShowAdvancedOptions)
{
var menu = vm.CreateContextForOpenAI();
menu?.Open(control);
var repo = vm.Repository;
if (vm.Staged == null || vm.Staged.Count == 0)
{
App.RaiseException(repo.FullPath, "No files added to commit!");
return;
}
var services = repo.GetPreferredOpenAIServices();
if (services.Count == 0)
{
App.RaiseException(repo.FullPath, "Bad configuration for OpenAI");
return;
}
if (services.Count == 1)
{
await App.ShowDialog(new ViewModels.AIAssistant(repo, services[0], vm.Staged, t => vm.CommitMessage = t));
return;
}
var menu = new ContextMenu() { Placement = PlacementMode.TopEdgeAlignedLeft };
foreach (var service in services)
{
var dup = service;
var item = new MenuItem();
item.Header = service.Name;
item.Click += async (_, e) =>
{
await App.ShowDialog(new ViewModels.AIAssistant(repo, dup, vm.Staged, t => vm.CommitMessage = t));
e.Handled = true;
};
menu.Items.Add(item);
}
menu.Open(control);
}
e.Handled = true;
}
private void OnOpenConventionalCommitHelper(object _, RoutedEventArgs e)
private async void OnOpenConventionalCommitHelper(object _, RoutedEventArgs e)
{
var toplevel = TopLevel.GetTopLevel(this);
if (toplevel is Window owner)
{
var vm = new ViewModels.ConventionalCommitMessageBuilder(text => Text = text);
var builder = new ConventionalCommitMessageBuilder() { DataContext = vm };
builder.ShowDialog(owner);
await builder.ShowDialog(owner);
}
e.Handled = true;