From 2aacec75b4c72608a1623fee2f3b9dac234b56db Mon Sep 17 00:00:00 2001 From: leo Date: Tue, 27 Feb 2024 18:26:05 +0800 Subject: [PATCH] optimize<*>: add a static method CreateMenuIcon to App. Restore working copy changes' selection state after refreshed --- src/App.axaml.cs | 9 ++ src/ViewModels/CommitDetail.cs | 31 ++---- src/ViewModels/Histories.cs | 70 ++++++------- src/ViewModels/Repository.cs | 88 ++++++++--------- src/ViewModels/WorkingCopy.cs | 173 +++++++++++++++++++++++---------- src/Views/WorkingCopy.axaml | 12 +-- src/Views/WorkingCopy.axaml.cs | 126 ------------------------ 7 files changed, 217 insertions(+), 292 deletions(-) diff --git a/src/App.axaml.cs b/src/App.axaml.cs index f11f9eaf..c8a8302b 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -120,6 +120,15 @@ namespace SourceGit { return string.Format(fmt, args); } + public static Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) { + var icon = new Avalonia.Controls.Shapes.Path(); + icon.Width = 12; + icon.Height = 12; + icon.Stretch = Stretch.Uniform; + icon.Data = Current.FindResource(key) as StreamGeometry; + return icon; + } + public static TopLevel GetTopLevel() { if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { return desktop.MainWindow; diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 85dcaa6a..4bdcdfca 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -1,6 +1,4 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; +using Avalonia.Controls; using Avalonia.Platform.Storage; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -151,7 +149,7 @@ namespace SourceGit.ViewModels { if (change.Index != Models.ChangeState.Deleted) { var history = new MenuItem(); history.Header = App.Text("FileHistory"); - history.Icon = CreateMenuIcon("Icons.Histories"); + history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, ev) => { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) }; window.Show(); @@ -160,7 +158,7 @@ namespace SourceGit.ViewModels { var blame = new MenuItem(); blame.Header = App.Text("Blame"); - blame.Icon = CreateMenuIcon("Icons.Blame"); + blame.Icon = App.CreateMenuIcon("Icons.Blame"); blame.Click += (o, ev) => { var window = new Views.Blame() { DataContext = new Blame(_repo, change.Path, _commit.SHA) }; window.Show(); @@ -170,7 +168,7 @@ namespace SourceGit.ViewModels { var full = Path.GetFullPath(Path.Combine(_repo, change.Path)); var explore = new MenuItem(); explore.Header = App.Text("RevealFile"); - explore.Icon = CreateMenuIcon("Icons.Folder.Open"); + explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.IsEnabled = File.Exists(full); explore.Click += (_, ev) => { Native.OS.OpenInFileManager(full, true); @@ -184,7 +182,7 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); - copyPath.Icon = CreateMenuIcon("Icons.Copy"); + copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); copyPath.Click += (_, ev) => { App.CopyText(change.Path); ev.Handled = true; @@ -197,7 +195,7 @@ namespace SourceGit.ViewModels { public ContextMenu CreateRevisionFileContextMenu(Models.Object file) { var history = new MenuItem(); history.Header = App.Text("FileHistory"); - history.Icon = CreateMenuIcon("Icons.Histories"); + history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, ev) => { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, file.Path) }; window.Show(); @@ -206,7 +204,7 @@ namespace SourceGit.ViewModels { var blame = new MenuItem(); blame.Header = App.Text("Blame"); - blame.Icon = CreateMenuIcon("Icons.Blame"); + blame.Icon = App.CreateMenuIcon("Icons.Blame"); blame.Click += (o, ev) => { var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) }; window.Show(); @@ -216,7 +214,7 @@ namespace SourceGit.ViewModels { var full = Path.GetFullPath(Path.Combine(_repo, file.Path)); var explore = new MenuItem(); explore.Header = App.Text("RevealFile"); - explore.Icon = CreateMenuIcon("Icons.Folder.Open"); + explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.Click += (_, ev) => { Native.OS.OpenInFileManager(full, file.Type == Models.ObjectType.Blob); ev.Handled = true; @@ -224,7 +222,7 @@ namespace SourceGit.ViewModels { var saveAs = new MenuItem(); saveAs.Header = App.Text("SaveAs"); - saveAs.Icon = CreateMenuIcon("Icons.Save"); + saveAs.Icon = App.CreateMenuIcon("Icons.Save"); saveAs.IsEnabled = file.Type == Models.ObjectType.Blob; saveAs.Click += async (_, ev) => { var topLevel = App.GetTopLevel(); @@ -242,7 +240,7 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); - copyPath.Icon = CreateMenuIcon("Icons.Copy"); + copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); copyPath.Click += (_, ev) => { App.CopyText(file.Path); ev.Handled = true; @@ -397,15 +395,6 @@ namespace SourceGit.ViewModels { } } - private Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) { - var icon = new Avalonia.Controls.Shapes.Path(); - icon.Width = 12; - icon.Height = 12; - icon.Stretch = Stretch.Uniform; - icon.Data = App.Current?.FindResource(key) as StreamGeometry; - return icon; - } - private string _repo = string.Empty; private int _activePageIndex = 0; private Models.Commit _commit = null; diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 6878f58b..74c59f0c 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -1,5 +1,4 @@ using Avalonia.Controls; -using Avalonia.Media; using Avalonia.Platform.Storage; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -148,7 +147,7 @@ namespace SourceGit.ViewModels { if (current.Head != commit.SHA) { var reset = new MenuItem(); reset.Header = CreateHighlightLabel("CommitCM.Reset", current.Name); - reset.Icon = CreateMenuIcon("Icons.Reset"); + reset.Icon = App.CreateMenuIcon("Icons.Reset"); reset.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Reset(_repo, current, commit)); e.Handled = true; @@ -157,7 +156,7 @@ namespace SourceGit.ViewModels { } else { var reword = new MenuItem(); reword.Header = App.Text("CommitCM.Reword"); - reword.Icon = CreateMenuIcon("Icons.Edit"); + reword.Icon = App.CreateMenuIcon("Icons.Edit"); reword.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Reword(_repo, commit)); e.Handled = true; @@ -166,7 +165,7 @@ namespace SourceGit.ViewModels { var squash = new MenuItem(); squash.Header = App.Text("CommitCM.Squash"); - squash.Icon = CreateMenuIcon("Icons.SquashIntoParent"); + squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent"); squash.IsEnabled = commit.Parents.Count == 1; squash.Click += (o, e) => { if (commit.Parents.Count == 1) { @@ -182,7 +181,7 @@ namespace SourceGit.ViewModels { if (!commit.IsMerged) { var rebase = new MenuItem(); rebase.Header = CreateHighlightLabel("CommitCM.Rebase", current.Name); - rebase.Icon = CreateMenuIcon("Icons.Rebase"); + rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(_repo, current, commit)); e.Handled = true; @@ -191,7 +190,7 @@ namespace SourceGit.ViewModels { var cherryPick = new MenuItem(); cherryPick.Header = App.Text("CommitCM.CherryPick"); - cherryPick.Icon = CreateMenuIcon("Icons.CherryPick"); + cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick"); cherryPick.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CherryPick(_repo, commit)); e.Handled = true; @@ -200,7 +199,7 @@ namespace SourceGit.ViewModels { } else { var revert = new MenuItem(); revert.Header = App.Text("CommitCM.Revert"); - revert.Icon = CreateMenuIcon("Icons.Undo"); + revert.Icon = App.CreateMenuIcon("Icons.Undo"); revert.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Revert(_repo, commit)); e.Handled = true; @@ -211,7 +210,7 @@ namespace SourceGit.ViewModels { menu.Items.Add(new MenuItem() { Header = "-" }); var createBranch = new MenuItem(); - createBranch.Icon = CreateMenuIcon("Icons.Branch.Add"); + createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); createBranch.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(_repo, commit)); @@ -220,7 +219,7 @@ namespace SourceGit.ViewModels { menu.Items.Add(createBranch); var createTag = new MenuItem(); - createTag.Icon = CreateMenuIcon("Icons.Tag.Add"); + createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Header = App.Text("CreateTag"); createTag.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(_repo, commit)); @@ -230,7 +229,7 @@ namespace SourceGit.ViewModels { menu.Items.Add(new MenuItem() { Header = "-" }); var saveToPatch = new MenuItem(); - saveToPatch.Icon = CreateMenuIcon("Icons.Diff"); + saveToPatch.Icon = App.CreateMenuIcon("Icons.Diff"); saveToPatch.Header = App.Text("CommitCM.SaveAsPatch"); saveToPatch.Click += async (_, e) => { var topLevel = App.GetTopLevel(); @@ -248,7 +247,7 @@ namespace SourceGit.ViewModels { menu.Items.Add(saveToPatch); var archive = new MenuItem(); - archive.Icon = CreateMenuIcon("Icons.Archive"); + archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); archive.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(_repo, commit)); @@ -259,7 +258,7 @@ namespace SourceGit.ViewModels { var copySHA = new MenuItem(); copySHA.Header = App.Text("CommitCM.CopySHA"); - copySHA.Icon = CreateMenuIcon("Icons.Copy"); + copySHA.Icon = App.CreateMenuIcon("Icons.Copy"); copySHA.Click += (o, e) => { App.CopyText(commit.SHA); e.Handled = true; @@ -270,7 +269,7 @@ namespace SourceGit.ViewModels { private void FillCurrentBranchMenu(ContextMenu menu, Models.Branch current) { var submenu = new MenuItem(); - submenu.Icon = CreateMenuIcon("Icons.Branch"); + submenu.Icon = App.CreateMenuIcon("Icons.Branch"); submenu.Header = current.Name; var dirty = !string.IsNullOrEmpty(current.UpstreamTrackStatus); @@ -279,7 +278,7 @@ namespace SourceGit.ViewModels { var fastForward = new MenuItem(); fastForward.Header = CreateHighlightLabel("BranchCM.FastForward", upstream); - fastForward.Icon = CreateMenuIcon("Icons.FastForward"); + fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.IsEnabled = dirty; fastForward.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Merge(_repo, upstream, current.Name)); @@ -289,7 +288,7 @@ namespace SourceGit.ViewModels { var pull = new MenuItem(); pull.Header = CreateHighlightLabel("BranchCM.Pull", upstream); - pull.Icon = CreateMenuIcon("Icons.Pull"); + pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.IsEnabled = dirty; pull.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(_repo, null)); @@ -300,7 +299,7 @@ namespace SourceGit.ViewModels { var push = new MenuItem(); push.Header = CreateHighlightLabel("BranchCM.Push", current.Name); - push.Icon = CreateMenuIcon("Icons.Push"); + push.Icon = App.CreateMenuIcon("Icons.Push"); push.IsEnabled = _repo.Remotes.Count > 0 && dirty; push.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Push(_repo, current)); @@ -313,7 +312,7 @@ namespace SourceGit.ViewModels { if (type != Models.GitFlowBranchType.None) { var finish = new MenuItem(); finish.Header = CreateHighlightLabel("BranchCM.Finish", current.Name); - finish.Icon = CreateMenuIcon("Icons.Flow"); + finish.Icon = App.CreateMenuIcon("Icons.Flow"); finish.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(_repo, current, type)); e.Handled = true; @@ -324,7 +323,7 @@ namespace SourceGit.ViewModels { var rename = new MenuItem(); rename.Header = CreateHighlightLabel("BranchCM.Rename", current.Name); - rename.Icon = CreateMenuIcon("Icons.Rename"); + rename.Icon = App.CreateMenuIcon("Icons.Rename"); rename.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(_repo, current)); e.Handled = true; @@ -336,12 +335,12 @@ namespace SourceGit.ViewModels { private void FillOtherLocalBranchMenu(ContextMenu menu, Models.Branch branch, Models.Branch current, bool merged) { var submenu = new MenuItem(); - submenu.Icon = CreateMenuIcon("Icons.Branch"); + submenu.Icon = App.CreateMenuIcon("Icons.Branch"); submenu.Header = branch.Name; var checkout = new MenuItem(); checkout.Header = CreateHighlightLabel("BranchCM.Checkout", branch.Name); - checkout.Icon = CreateMenuIcon("Icons.Check"); + checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(_repo, branch.Name)); e.Handled = true; @@ -350,7 +349,7 @@ namespace SourceGit.ViewModels { var merge = new MenuItem(); merge.Header = CreateHighlightLabel("BranchCM.Merge", branch.Name, current.Name); - merge.Icon = CreateMenuIcon("Icons.Merge"); + merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.IsEnabled = !merged; merge.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(_repo, branch.Name, current.Name)); @@ -363,7 +362,7 @@ namespace SourceGit.ViewModels { if (type != Models.GitFlowBranchType.None) { var finish = new MenuItem(); finish.Header = CreateHighlightLabel("BranchCM.Finish", branch.Name); - finish.Icon = CreateMenuIcon("Icons.Flow"); + finish.Icon = App.CreateMenuIcon("Icons.Flow"); finish.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, type)); e.Handled = true; @@ -374,7 +373,7 @@ namespace SourceGit.ViewModels { var rename = new MenuItem(); rename.Header = CreateHighlightLabel("BranchCM.Rename", branch.Name); - rename.Icon = CreateMenuIcon("Icons.Rename"); + rename.Icon = App.CreateMenuIcon("Icons.Rename"); rename.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(_repo, branch)); e.Handled = true; @@ -383,7 +382,7 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = CreateHighlightLabel("BranchCM.Delete", branch.Name); - delete.Icon = CreateMenuIcon("Icons.Clear"); + delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(_repo, branch)); e.Handled = true; @@ -397,12 +396,12 @@ namespace SourceGit.ViewModels { var name = $"{branch.Remote}/{branch.Name}"; var submenu = new MenuItem(); - submenu.Icon = CreateMenuIcon("Icons.Branch"); + submenu.Icon = App.CreateMenuIcon("Icons.Branch"); submenu.Header = name; var checkout = new MenuItem(); checkout.Header = CreateHighlightLabel("BranchCM.Checkout", name); - checkout.Icon = CreateMenuIcon("Icons.Check"); + checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Click += (o, e) => { foreach (var b in _repo.Branches) { if (b.IsLocal && b.Upstream == branch.FullName) { @@ -419,7 +418,7 @@ namespace SourceGit.ViewModels { var merge = new MenuItem(); merge.Header = CreateHighlightLabel("BranchCM.Merge", name, current.Name); - merge.Icon = CreateMenuIcon("Icons.Merge"); + merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.IsEnabled = !merged; merge.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(_repo, name, current.Name)); @@ -431,7 +430,7 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = CreateHighlightLabel("BranchCM.Delete", name); - delete.Icon = CreateMenuIcon("Icons.Clear"); + delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(_repo, branch)); e.Handled = true; @@ -444,12 +443,12 @@ namespace SourceGit.ViewModels { private void FillTagMenu(ContextMenu menu, Models.Tag tag) { var submenu = new MenuItem(); submenu.Header = tag.Name; - submenu.Icon = CreateMenuIcon("Icons.Tag"); + submenu.Icon = App.CreateMenuIcon("Icons.Tag"); submenu.MinWidth = 200; var push = new MenuItem(); push.Header = CreateHighlightLabel("TagCM.Push", tag.Name); - push.Icon = CreateMenuIcon("Icons.Push"); + push.Icon = App.CreateMenuIcon("Icons.Push"); push.IsEnabled = _repo.Remotes.Count > 0; push.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new PushTag(_repo, tag)); @@ -459,7 +458,7 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = CreateHighlightLabel("TagCM.Delete", tag.Name); - delete.Icon = CreateMenuIcon("Icons.Clear"); + delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteTag(_repo, tag)); e.Handled = true; @@ -476,15 +475,6 @@ namespace SourceGit.ViewModels { return label; } - private Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) { - var icon = new Avalonia.Controls.Shapes.Path(); - icon.Width = 12; - icon.Height = 12; - icon.Stretch = Stretch.Uniform; - icon.Data = App.Current?.FindResource(key) as StreamGeometry; - return icon; - } - private Repository _repo = null; private double _dataGridRowHeight = 28; private bool _isLoading = true; diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 54919af0..b4a5b581 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -1,6 +1,5 @@ using Avalonia.Collections; using Avalonia.Controls; -using Avalonia.Media; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using System; @@ -580,7 +579,7 @@ namespace SourceGit.ViewModels { var push = new MenuItem(); push.Header = CreateHighlightLabel("BranchCM.Push", branch.Name); - push.Icon = CreateMenuIcon("Icons.Push"); + push.Icon = App.CreateMenuIcon("Icons.Push"); push.IsEnabled = Remotes.Count > 0; push.Click += (_, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Push(this, branch)); @@ -590,7 +589,7 @@ namespace SourceGit.ViewModels { if (branch.IsCurrent) { var discard = new MenuItem(); discard.Header = App.Text("BranchCM.DiscardAll"); - discard.Icon = CreateMenuIcon("Icons.Undo"); + discard.Icon = App.CreateMenuIcon("Icons.Undo"); discard.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Discard(this)); e.Handled = true; @@ -603,7 +602,7 @@ namespace SourceGit.ViewModels { var upstream = branch.Upstream.Substring(13); var fastForward = new MenuItem(); fastForward.Header = CreateHighlightLabel("BranchCM.FastForward", upstream); - fastForward.Icon = CreateMenuIcon("Icons.FastForward"); + fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0; fastForward.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Merge(this, upstream, branch.Name)); @@ -612,7 +611,7 @@ namespace SourceGit.ViewModels { var pull = new MenuItem(); pull.Header = CreateHighlightLabel("BranchCM.Pull", upstream); - pull.Icon = CreateMenuIcon("Icons.Pull"); + pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus); pull.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(this, null)); @@ -629,7 +628,7 @@ namespace SourceGit.ViewModels { var checkout = new MenuItem(); checkout.Header = CreateHighlightLabel("BranchCM.Checkout", branch.Name); - checkout.Icon = CreateMenuIcon("Icons.Check"); + checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Checkout(this, branch.Name)); e.Handled = true; @@ -640,7 +639,7 @@ namespace SourceGit.ViewModels { if (upstream != null) { var fastForward = new MenuItem(); fastForward.Header = CreateHighlightLabel("BranchCM.FastForward", $"{upstream.Remote}/{upstream.Name}"); - fastForward.Icon = CreateMenuIcon("Icons.FastForward"); + fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0; fastForward.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new FastForwardWithoutCheckout(this, branch, upstream)); @@ -656,7 +655,7 @@ namespace SourceGit.ViewModels { var merge = new MenuItem(); merge.Header = CreateHighlightLabel("BranchCM.Merge", branch.Name, current.Name); - merge.Icon = CreateMenuIcon("Icons.Merge"); + merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(this, branch.Name, current.Name)); e.Handled = true; @@ -664,7 +663,7 @@ namespace SourceGit.ViewModels { var rebase = new MenuItem(); rebase.Header = CreateHighlightLabel("BranchCM.Rebase", current.Name, branch.Name); - rebase.Icon = CreateMenuIcon("Icons.Rebase"); + rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(this, current, branch)); e.Handled = true; @@ -678,7 +677,7 @@ namespace SourceGit.ViewModels { if (type != Models.GitFlowBranchType.None) { var finish = new MenuItem(); finish.Header = CreateHighlightLabel("BranchCM.Finish", branch.Name); - finish.Icon = CreateMenuIcon("Icons.Flow"); + finish.Icon = App.CreateMenuIcon("Icons.Flow"); finish.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new GitFlowFinish(this, branch, type)); e.Handled = true; @@ -689,7 +688,7 @@ namespace SourceGit.ViewModels { var rename = new MenuItem(); rename.Header = CreateHighlightLabel("BranchCM.Rename", branch.Name); - rename.Icon = CreateMenuIcon("Icons.Rename"); + rename.Icon = App.CreateMenuIcon("Icons.Rename"); rename.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new RenameBranch(this, branch)); e.Handled = true; @@ -697,7 +696,7 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = CreateHighlightLabel("BranchCM.Delete", branch.Name); - delete.Icon = CreateMenuIcon("Icons.Clear"); + delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.IsEnabled = !branch.IsCurrent; delete.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(this, branch)); @@ -705,7 +704,7 @@ namespace SourceGit.ViewModels { }; var createBranch = new MenuItem(); - createBranch.Icon = CreateMenuIcon("Icons.Branch.Add"); + createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); createBranch.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, branch)); @@ -713,7 +712,7 @@ namespace SourceGit.ViewModels { }; var createTag = new MenuItem(); - createTag.Icon = CreateMenuIcon("Icons.Tag.Add"); + createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Header = App.Text("CreateTag"); createTag.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(this, branch)); @@ -736,13 +735,13 @@ namespace SourceGit.ViewModels { if (remoteBranches.Count > 0) { var tracking = new MenuItem(); tracking.Header = App.Text("BranchCM.Tracking"); - tracking.Icon = CreateMenuIcon("Icons.Branch"); + tracking.Icon = App.CreateMenuIcon("Icons.Branch"); foreach (var b in remoteBranches) { var upstream = b.FullName.Replace("refs/remotes/", ""); var target = new MenuItem(); target.Header = upstream; - if (branch.Upstream == b.FullName) target.Icon = CreateMenuIcon("Icons.Check"); + if (branch.Upstream == b.FullName) target.Icon = App.CreateMenuIcon("Icons.Check"); target.Click += (o, e) => { if (Commands.Branch.SetUpstream(_fullpath, branch.Name, upstream)) { @@ -769,7 +768,7 @@ namespace SourceGit.ViewModels { } var archive = new MenuItem(); - archive.Icon = CreateMenuIcon("Icons.Archive"); + archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); archive.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(this, branch)); @@ -780,7 +779,7 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("BranchCM.CopyName"); - copy.Icon = CreateMenuIcon("Icons.Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Click += (o, e) => { App.CopyText(branch.Name); e.Handled = true; @@ -795,7 +794,7 @@ namespace SourceGit.ViewModels { var fetch = new MenuItem(); fetch.Header = App.Text("RemoteCM.Fetch"); - fetch.Icon = CreateMenuIcon("Icons.Fetch"); + fetch.Icon = App.CreateMenuIcon("Icons.Fetch"); fetch.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new Fetch(this, remote)); e.Handled = true; @@ -803,7 +802,7 @@ namespace SourceGit.ViewModels { var prune = new MenuItem(); prune.Header = App.Text("RemoteCM.Prune"); - prune.Icon = CreateMenuIcon("Icons.Clear2"); + prune.Icon = App.CreateMenuIcon("Icons.Clear2"); prune.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowAndStartPopup(new PruneRemote(this, remote)); e.Handled = true; @@ -811,7 +810,7 @@ namespace SourceGit.ViewModels { var edit = new MenuItem(); edit.Header = App.Text("RemoteCM.Edit"); - edit.Icon = CreateMenuIcon("Icons.Edit"); + edit.Icon = App.CreateMenuIcon("Icons.Edit"); edit.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new EditRemote(this, remote)); e.Handled = true; @@ -819,7 +818,7 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = App.Text("RemoteCM.Delete"); - delete.Icon = CreateMenuIcon("Icons.Clear"); + delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteRemote(this, remote)); e.Handled = true; @@ -827,7 +826,7 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("RemoteCM.CopyURL"); - copy.Icon = CreateMenuIcon("Icons.Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Click += (o, e) => { App.CopyText(remote.URL); e.Handled = true; @@ -849,7 +848,7 @@ namespace SourceGit.ViewModels { var checkout = new MenuItem(); checkout.Header = CreateHighlightLabel("BranchCM.Checkout", $"{branch.Remote}/{branch.Name}"); - checkout.Icon = CreateMenuIcon("Icons.Check"); + checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Click += (o, e) => { foreach (var b in Branches) { if (b.IsLocal && b.Upstream == branch.FullName) { @@ -868,7 +867,7 @@ namespace SourceGit.ViewModels { if (current != null) { var pull = new MenuItem(); pull.Header = CreateHighlightLabel("BranchCM.PullInto", $"{branch.Remote}/{branch.Name}", current.Name); - pull.Icon = CreateMenuIcon("Icons.Pull"); + pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Pull(this, branch)); e.Handled = true; @@ -876,7 +875,7 @@ namespace SourceGit.ViewModels { var merge = new MenuItem(); merge.Header = CreateHighlightLabel("BranchCM.Merge", $"{branch.Remote}/{branch.Name}", current.Name); - merge.Icon = CreateMenuIcon("Icons.Merge"); + merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Merge(this, $"{branch.Remote}/{branch.Name}", current.Name)); e.Handled = true; @@ -884,7 +883,7 @@ namespace SourceGit.ViewModels { var rebase = new MenuItem(); rebase.Header = CreateHighlightLabel("BranchCM.Rebase", current.Name, $"{branch.Remote}/{branch.Name}"); - rebase.Icon = CreateMenuIcon("Icons.Rebase"); + rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Rebase(this, current, branch)); e.Handled = true; @@ -898,14 +897,14 @@ namespace SourceGit.ViewModels { var delete = new MenuItem(); delete.Header = CreateHighlightLabel("BranchCM.Delete", $"{branch.Remote}/{branch.Name}"); - delete.Icon = CreateMenuIcon("Icons.Clear"); + delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteBranch(this, branch)); e.Handled = true; }; var createBranch = new MenuItem(); - createBranch.Icon = CreateMenuIcon("Icons.Branch.Add"); + createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); createBranch.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, branch)); @@ -913,7 +912,7 @@ namespace SourceGit.ViewModels { }; var createTag = new MenuItem(); - createTag.Icon = CreateMenuIcon("Icons.Tag.Add"); + createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Header = App.Text("CreateTag"); createTag.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateTag(this, branch)); @@ -921,7 +920,7 @@ namespace SourceGit.ViewModels { }; var archive = new MenuItem(); - archive.Icon = CreateMenuIcon("Icons.Archive"); + archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); archive.Click += (o, e) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(this, branch)); @@ -930,7 +929,7 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("BranchCM.CopyName"); - copy.Icon = CreateMenuIcon("Icons.Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Click += (o, e) => { App.CopyText(branch.Remote + "/" + branch.Name); e.Handled = true; @@ -949,7 +948,7 @@ namespace SourceGit.ViewModels { public ContextMenu CreateContextMenuForTag(Models.Tag tag) { var createBranch = new MenuItem(); - createBranch.Icon = CreateMenuIcon("Icons.Branch.Add"); + createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Header = App.Text("CreateBranch"); createBranch.Click += (o, ev) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new CreateBranch(this, tag)); @@ -958,7 +957,7 @@ namespace SourceGit.ViewModels { var pushTag = new MenuItem(); pushTag.Header = CreateHighlightLabel("TagCM.Push", tag.Name); - pushTag.Icon = CreateMenuIcon("Icons.Push"); + pushTag.Icon = App.CreateMenuIcon("Icons.Push"); pushTag.IsEnabled = Remotes.Count > 0; pushTag.Click += (o, ev) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new PushTag(this, tag)); @@ -967,14 +966,14 @@ namespace SourceGit.ViewModels { var deleteTag = new MenuItem(); deleteTag.Header = CreateHighlightLabel("TagCM.Delete", tag.Name); - deleteTag.Icon = CreateMenuIcon("Icons.Clear"); + deleteTag.Icon = App.CreateMenuIcon("Icons.Clear"); deleteTag.Click += (o, ev) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteTag(this, tag)); ev.Handled = true; }; var archive = new MenuItem(); - archive.Icon = CreateMenuIcon("Icons.Archive"); + archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Header = App.Text("Archive"); archive.Click += (o, ev) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new Archive(this, tag)); @@ -983,7 +982,7 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("TagCM.Copy"); - copy.Icon = CreateMenuIcon("Icons.Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Click += (o, ev) => { App.CopyText(tag.Name); ev.Handled = true; @@ -1004,7 +1003,7 @@ namespace SourceGit.ViewModels { public ContextMenu CreateContextMenuForSubmodule(string submodule) { var open = new MenuItem(); open.Header = App.Text("Submodule.Open"); - open.Icon = CreateMenuIcon("Icons.Folder.Open"); + open.Icon = App.CreateMenuIcon("Icons.Folder.Open"); open.Click += (o, ev) => { var root = Path.GetFullPath(Path.Combine(_fullpath, submodule)); var gitDir = new Commands.QueryGitDir(root).Result(); @@ -1026,7 +1025,7 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("Submodule.CopyPath"); - copy.Icon = CreateMenuIcon("Icons.Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Click += (o, ev) => { App.CopyText(submodule); ev.Handled = true; @@ -1034,7 +1033,7 @@ namespace SourceGit.ViewModels { var rm = new MenuItem(); rm.Header = App.Text("Submodule.Remove"); - rm.Icon = CreateMenuIcon("Icons.Clear"); + rm.Icon = App.CreateMenuIcon("Icons.Clear"); rm.Click += (o, ev) => { if (PopupHost.CanCreatePopup()) PopupHost.ShowPopup(new DeleteSubmodule(this, submodule)); ev.Handled = true; @@ -1054,15 +1053,6 @@ namespace SourceGit.ViewModels { return label; } - private Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) { - var icon = new Avalonia.Controls.Shapes.Path(); - icon.Width = 12; - icon.Height = 12; - icon.Stretch = Stretch.Uniform; - icon.Data = App.Current?.FindResource(key) as StreamGeometry; - return icon; - } - private string _fullpath = string.Empty; private string _gitDir = string.Empty; private Models.GitFlow _gitflow = new Models.GitFlow(); diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 50392174..4a741bbc 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -1,6 +1,4 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; +using Avalonia.Controls; using Avalonia.Platform.Storage; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -14,11 +12,6 @@ namespace SourceGit.ViewModels { public Models.Change Change { get; set; } } - public class ViewChangeDetailContext { - public string FilePath { get; set; } = string.Empty; - public bool IsUnstaged { get; set; } = false; - } - public class WorkingCopy : ObservableObject { public bool IsStaging { get => _isStaging; @@ -54,6 +47,28 @@ namespace SourceGit.ViewModels { get => _count; } + public Models.Change SelectedUnstagedChange { + get => _selectedUnstagedChange; + set { + if (SetProperty(ref _selectedUnstagedChange, value) && value != null) { + SelectedStagedChange = null; + SelectedStagedTreeNode = null; + SetDetail(value, true); + } + } + } + + public Models.Change SelectedStagedChange { + get => _selectedStagedChange; + set { + if (SetProperty(ref _selectedStagedChange, value) && value != null) { + SelectedUnstagedChange = null; + SelectedUnstagedTreeNode = null; + SetDetail(value, false); + } + } + } + public List UnstagedTree { get => _unstagedTree; private set => SetProperty(ref _unstagedTree, value); @@ -64,6 +79,44 @@ namespace SourceGit.ViewModels { private set => SetProperty(ref _stagedTree, value); } + public FileTreeNode SelectedUnstagedTreeNode { + get => _selectedUnstagedTreeNode; + set { + if (SetProperty(ref _selectedUnstagedTreeNode, value)) { + if (value == null) { + SelectedUnstagedChange = null; + } else { + SelectedUnstagedChange = value.Backend as Models.Change; + SelectedStagedTreeNode = null; + SelectedStagedChange = null; + + if (value.IsFolder) { + SetDetail(null, true); + } + } + } + } + } + + public FileTreeNode SelectedStagedTreeNode { + get => _selectedStagedTreeNode; + set { + if (SetProperty(ref _selectedStagedTreeNode, value)) { + if (value == null) { + SelectedStagedChange = null; + } else { + SelectedStagedChange = value.Backend as Models.Change; + SelectedUnstagedTreeNode = null; + SelectedUnstagedChange = null; + + if (value.IsFolder) { + SetDetail(null, false); + } + } + } + } + } + public object DetailContext { get => _detailContext; private set => SetProperty(ref _detailContext, value); @@ -84,7 +137,10 @@ namespace SourceGit.ViewModels { if (_staged != null) _staged.Clear(); if (_unstagedTree != null) _unstagedTree.Clear(); if (_stagedTree != null) _stagedTree.Clear(); - _lastViewChange = null; + _selectedUnstagedChange = null; + _selectedStagedChange = null; + _selectedUnstagedTreeNode = null; + _selectedStagedTreeNode = null; _detailContext = null; _commitMessage = string.Empty; } @@ -93,24 +149,34 @@ namespace SourceGit.ViewModels { var unstaged = new List(); var staged = new List(); - var viewFile = _lastViewChange == null ? string.Empty : _lastViewChange.FilePath; + var viewFile = string.Empty; + var lastSelectedIsUnstaged = false; + if (_selectedUnstagedChange != null) { + viewFile = _selectedUnstagedChange.Path; + lastSelectedIsUnstaged = true; + } else if (_selectedStagedChange != null) { + viewFile = _selectedStagedChange.Path; + } + var viewChange = null as Models.Change; var hasConflict = false; foreach (var c in changes) { - if (c.Path == viewFile) { - viewChange = c; - } - if (c.Index == Models.ChangeState.Modified || c.Index == Models.ChangeState.Added || c.Index == Models.ChangeState.Deleted || c.Index == Models.ChangeState.Renamed) { staged.Add(c); + if (!lastSelectedIsUnstaged && c.Path == viewFile) { + viewChange = c; + } } if (c.WorkTree != Models.ChangeState.None) { unstaged.Add(c); hasConflict |= c.IsConflit; + if (lastSelectedIsUnstaged && c.Path == viewFile) { + viewChange = c; + } } } @@ -125,7 +191,23 @@ namespace SourceGit.ViewModels { UnstagedTree = unstagedTree; StagedTree = stagedTree; _isLoadingData = false; - SetDetail(viewChange, _lastViewChange == null || _lastViewChange.IsUnstaged); + + // Restore last selection states. + if (viewChange != null) { + if (lastSelectedIsUnstaged) { + SelectedUnstagedChange = viewChange; + SelectedUnstagedTreeNode = FileTreeNode.SelectByPath(_unstagedTree, viewFile); + } else { + SelectedStagedChange = viewChange; + SelectedStagedTreeNode = FileTreeNode.SelectByPath(_stagedTree, viewFile); + } + } else { + SelectedUnstagedChange = null; + SelectedUnstagedTreeNode = null; + SelectedStagedChange = null; + SelectedStagedTreeNode = null; + SetDetail(null, false); + } }); return hasConflict; @@ -135,13 +217,10 @@ namespace SourceGit.ViewModels { if (_isLoadingData) return; if (change == null) { - _lastViewChange = null; DetailContext = null; } else if (change.IsConflit) { - _lastViewChange = new ViewChangeDetailContext() { FilePath = change.Path, IsUnstaged = isUnstaged }; DetailContext = new ConflictContext() { Change = change }; } else { - _lastViewChange = new ViewChangeDetailContext() { FilePath = change.Path, IsUnstaged = isUnstaged }; DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged)); } } @@ -284,7 +363,7 @@ namespace SourceGit.ViewModels { var explore = new MenuItem(); explore.Header = App.Text("RevealFile"); - explore.Icon = CreateMenuIcon("Icons.Folder.Open"); + explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.IsEnabled = File.Exists(path) || Directory.Exists(path); explore.Click += (_, e) => { Native.OS.OpenInFileManager(path, true); @@ -293,7 +372,7 @@ namespace SourceGit.ViewModels { var openWith = new MenuItem(); openWith.Header = App.Text("OpenWith"); - openWith.Icon = CreateMenuIcon("Icons.OpenWith"); + openWith.Icon = App.CreateMenuIcon("Icons.OpenWith"); openWith.IsEnabled = File.Exists(path); openWith.Click += (_, e) => { Native.OS.OpenWithDefaultEditor(path); @@ -302,7 +381,7 @@ namespace SourceGit.ViewModels { var stage = new MenuItem(); stage.Header = App.Text("FileCM.Stage"); - stage.Icon = CreateMenuIcon("Icons.File.Add"); + stage.Icon = App.CreateMenuIcon("Icons.File.Add"); stage.Click += (_, e) => { StageChanges(changes); e.Handled = true; @@ -310,7 +389,7 @@ namespace SourceGit.ViewModels { var discard = new MenuItem(); discard.Header = App.Text("FileCM.Discard"); - discard.Icon = CreateMenuIcon("Icons.Undo"); + discard.Icon = App.CreateMenuIcon("Icons.Undo"); discard.Click += (_, e) => { Discard(changes); e.Handled = true; @@ -318,7 +397,7 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.Stash"); - stash.Icon = CreateMenuIcon("Icons.Stashes"); + stash.Icon = App.CreateMenuIcon("Icons.Stashes"); stash.Click += (_, e) => { if (PopupHost.CanCreatePopup()) { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); @@ -328,7 +407,7 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); - patch.Icon = CreateMenuIcon("Icons.Diff"); + patch.Icon = App.CreateMenuIcon("Icons.Diff"); patch.Click += async (_, e) => { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -349,7 +428,7 @@ namespace SourceGit.ViewModels { var history = new MenuItem(); history.Header = App.Text("FileHistory"); - history.Icon = CreateMenuIcon("Icons.Histories"); + history.Icon = App.CreateMenuIcon("Icons.Histories"); history.Click += (_, e) => { var window = new Views.FileHistories() { DataContext = new FileHistories(_repo.FullPath, change.Path) }; window.Show(); @@ -358,7 +437,7 @@ namespace SourceGit.ViewModels { var assumeUnchanged = new MenuItem(); assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged"); - assumeUnchanged.Icon = CreateMenuIcon("Icons.File.Ignore"); + assumeUnchanged.Icon = App.CreateMenuIcon("Icons.File.Ignore"); assumeUnchanged.IsEnabled = change.WorkTree != Models.ChangeState.Untracked; assumeUnchanged.Click += (_, e) => { new Commands.AssumeUnchanged(_repo.FullPath).Add(change.Path); @@ -367,7 +446,7 @@ namespace SourceGit.ViewModels { var copy = new MenuItem(); copy.Header = App.Text("CopyPath"); - copy.Icon = CreateMenuIcon("Icons.Copy"); + copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Click += (_, e) => { App.CopyText(change.Path); e.Handled = true; @@ -388,7 +467,7 @@ namespace SourceGit.ViewModels { } else { var stage = new MenuItem(); stage.Header = App.Text("FileCM.StageMulti", changes.Count); - stage.Icon = CreateMenuIcon("Icons.File.Add"); + stage.Icon = App.CreateMenuIcon("Icons.File.Add"); stage.Click += (_, e) => { StageChanges(changes); e.Handled = true; @@ -396,7 +475,7 @@ namespace SourceGit.ViewModels { var discard = new MenuItem(); discard.Header = App.Text("FileCM.DiscardMulti", changes.Count); - discard.Icon = CreateMenuIcon("Icons.Undo"); + discard.Icon = App.CreateMenuIcon("Icons.Undo"); discard.Click += (_, e) => { Discard(changes); e.Handled = true; @@ -404,7 +483,7 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.StashMulti", changes.Count); - stash.Icon = CreateMenuIcon("Icons.Stashes"); + stash.Icon = App.CreateMenuIcon("Icons.Stashes"); stash.Click += (_, e) => { if (PopupHost.CanCreatePopup()) { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); @@ -414,7 +493,7 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); - patch.Icon = CreateMenuIcon("Icons.Diff"); + patch.Icon = App.CreateMenuIcon("Icons.Diff"); patch.Click += async (o, e) => { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -453,7 +532,7 @@ namespace SourceGit.ViewModels { var explore = new MenuItem(); explore.IsEnabled = File.Exists(path) || Directory.Exists(path); explore.Header = App.Text("RevealFile"); - explore.Icon = CreateMenuIcon("Icons.Folder.Open"); + explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.Click += (o, e) => { Native.OS.OpenInFileManager(path, true); e.Handled = true; @@ -461,7 +540,7 @@ namespace SourceGit.ViewModels { var openWith = new MenuItem(); openWith.Header = App.Text("OpenWith"); - openWith.Icon = CreateMenuIcon("Icons.OpenWith"); + openWith.Icon = App.CreateMenuIcon("Icons.OpenWith"); openWith.IsEnabled = File.Exists(path); openWith.Click += (_, e) => { Native.OS.OpenWithDefaultEditor(path); @@ -470,7 +549,7 @@ namespace SourceGit.ViewModels { var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.Unstage"); - unstage.Icon = CreateMenuIcon("Icons.File.Remove"); + unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); unstage.Click += (o, e) => { UnstageChanges(changes); e.Handled = true; @@ -478,7 +557,7 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.Stash"); - stash.Icon = CreateMenuIcon("Icons.Stashes"); + stash.Icon = App.CreateMenuIcon("Icons.Stashes"); stash.Click += (_, e) => { if (PopupHost.CanCreatePopup()) { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); @@ -488,7 +567,7 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); - patch.Icon = CreateMenuIcon("Icons.Diff"); + patch.Icon = App.CreateMenuIcon("Icons.Diff"); patch.Click += async (o, e) => { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -509,7 +588,7 @@ namespace SourceGit.ViewModels { var copyPath = new MenuItem(); copyPath.Header = App.Text("CopyPath"); - copyPath.Icon = CreateMenuIcon("Icons.Copy"); + copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); copyPath.Click += (o, e) => { App.CopyText(change.Path); e.Handled = true; @@ -526,7 +605,7 @@ namespace SourceGit.ViewModels { } else { var unstage = new MenuItem(); unstage.Header = App.Text("FileCM.UnstageMulti", changes.Count); - unstage.Icon = CreateMenuIcon("Icons.File.Remove"); + unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); unstage.Click += (o, e) => { UnstageChanges(changes); e.Handled = true; @@ -534,7 +613,7 @@ namespace SourceGit.ViewModels { var stash = new MenuItem(); stash.Header = App.Text("FileCM.StashMulti", changes.Count); - stash.Icon = CreateMenuIcon("Icons.Stashes"); + stash.Icon = App.CreateMenuIcon("Icons.Stashes"); stash.Click += (_, e) => { if (PopupHost.CanCreatePopup()) { PopupHost.ShowPopup(new StashChanges(_repo, changes, false)); @@ -544,7 +623,7 @@ namespace SourceGit.ViewModels { var patch = new MenuItem(); patch.Header = App.Text("FileCM.SaveAsPatch"); - patch.Icon = CreateMenuIcon("Icons.Diff"); + patch.Icon = App.CreateMenuIcon("Icons.Diff"); patch.Click += async (_, e) => { var topLevel = App.GetTopLevel(); if (topLevel == null) return; @@ -603,15 +682,6 @@ namespace SourceGit.ViewModels { return menu; } - private Avalonia.Controls.Shapes.Path CreateMenuIcon(string key) { - var icon = new Avalonia.Controls.Shapes.Path(); - icon.Width = 12; - icon.Height = 12; - icon.Stretch = Stretch.Uniform; - icon.Data = App.Current?.FindResource(key) as StreamGeometry; - return icon; - } - private void PushCommitMessage() { var existIdx = _repo.CommitMessages.IndexOf(CommitMessage); if (existIdx == 0) { @@ -636,10 +706,13 @@ namespace SourceGit.ViewModels { private bool _useAmend = false; private List _unstaged = null; private List _staged = null; + private Models.Change _selectedUnstagedChange = null; + private Models.Change _selectedStagedChange = null; private int _count = 0; private List _unstagedTree = null; private List _stagedTree = null; - private ViewChangeDetailContext _lastViewChange = null; + private FileTreeNode _selectedUnstagedTreeNode = null; + private FileTreeNode _selectedStagedTreeNode = null; private object _detailContext = null; private string _commitMessage = string.Empty; } diff --git a/src/Views/WorkingCopy.axaml b/src/Views/WorkingCopy.axaml index 68a577e3..c17c7914 100644 --- a/src/Views/WorkingCopy.axaml +++ b/src/Views/WorkingCopy.axaml @@ -60,6 +60,7 @@ @@ -96,6 +96,7 @@ @@ -139,11 +139,11 @@ @@ -185,6 +185,7 @@ @@ -221,6 +221,7 @@ @@ -264,11 +264,11 @@ diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs index dc58ee91..3b6293c1 100644 --- a/src/Views/WorkingCopy.axaml.cs +++ b/src/Views/WorkingCopy.axaml.cs @@ -19,132 +19,6 @@ namespace SourceGit.Views { GC.Collect(); } - private void OnUnstagedListSelectionChanged(object sender, SelectionChangedEventArgs e) { - var vm = DataContext as ViewModels.WorkingCopy; - if (vm == null) return; - - var datagrid = sender as DataGrid; - if (datagrid.SelectedItems.Count == 0) { - if (stagedList.SelectedItem == null && - stagedGrid.SelectedItem == null && - stagedTree.SelectedItem == null) { - vm.SetDetail(null, true); - } - - e.Handled = true; - return; - } - - stagedList.SelectedItems.Clear(); - stagedGrid.SelectedItems.Clear(); - stagedTree.SelectedItems.Clear(); - - if (datagrid.SelectedItems.Count == 1) { - vm.SetDetail(datagrid.SelectedItem as Models.Change, true); - } else { - vm.SetDetail(null, true); - } - - e.Handled = true; - } - - private void OnUnstagedTreeViewSelectionChanged(object sender, SelectionChangedEventArgs e) { - var vm = DataContext as ViewModels.WorkingCopy; - if (vm == null) return; - - var tree = sender as TreeView; - if (tree.SelectedItems.Count == 0) { - if (stagedList.SelectedItem == null && - stagedGrid.SelectedItem == null && - stagedTree.SelectedItem == null) { - vm.SetDetail(null, true); - } - - e.Handled = true; - return; - } - - stagedList.SelectedItems.Clear(); - stagedGrid.SelectedItems.Clear(); - stagedTree.SelectedItems.Clear(); - - if (tree.SelectedItems.Count == 1) { - var node = tree.SelectedItem as ViewModels.FileTreeNode; - if (node != null && !node.IsFolder) { - vm.SetDetail(node.Backend as Models.Change, true); - } else { - vm.SetDetail(null, true); - } - } else { - vm.SetDetail(null, true); - } - - e.Handled = true; - } - - private void OnStagedListSelectionChanged(object sender, SelectionChangedEventArgs e) { - var vm = DataContext as ViewModels.WorkingCopy; - if (vm == null) return; - - var datagrid = sender as DataGrid; - if (datagrid.SelectedItems.Count == 0) { - if (unstagedList.SelectedItem == null && - unstagedGrid.SelectedItem == null && - unstagedTree.SelectedItem == null) { - vm.SetDetail(null, false); - } - - e.Handled = true; - return; - } - - unstagedList.SelectedItems.Clear(); - unstagedGrid.SelectedItems.Clear(); - unstagedTree.SelectedItems.Clear(); - - if (datagrid.SelectedItems.Count == 1) { - vm.SetDetail(datagrid.SelectedItem as Models.Change, false); - } else { - vm.SetDetail(null, false); - } - - e.Handled = true; - } - - private void OnStagedTreeViewSelectionChanged(object sender, SelectionChangedEventArgs e) { - var vm = DataContext as ViewModels.WorkingCopy; - if (vm == null) return; - - var tree = sender as TreeView; - if (tree.SelectedItems.Count == 0) { - if (unstagedList.SelectedItem == null && - unstagedGrid.SelectedItem == null && - unstagedTree.SelectedItem == null) { - vm.SetDetail(null, false); - } - - e.Handled = true; - return; - } - - unstagedList.SelectedItems.Clear(); - unstagedGrid.SelectedItems.Clear(); - unstagedTree.SelectedItems.Clear(); - - if (tree.SelectedItems.Count == 1) { - var node = tree.SelectedItem as ViewModels.FileTreeNode; - if (node != null && !node.IsFolder) { - vm.SetDetail(node.Backend as Models.Change, false); - } else { - vm.SetDetail(null, false); - } - } else { - vm.SetDetail(null, false); - } - - e.Handled = true; - } - private void ViewAssumeUnchanged(object sender, RoutedEventArgs e) { var repoPage = this.FindAncestorOfType(); if (repoPage != null) {