mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-23 20:47:25 -08:00
Merge branch 'release/v8.17'
This commit is contained in:
commit
5a1827fdcb
73 changed files with 2069 additions and 1544 deletions
45
README.md
45
README.md
|
@ -9,6 +9,7 @@ Opensource Git GUI client.
|
|||
* Fast
|
||||
* English/简体中文/繁體中文
|
||||
* Built-in light/dark themes
|
||||
* Customize theme
|
||||
* Visual commit graph
|
||||
* Supports SSH access with each remote
|
||||
* GIT commands with GUI
|
||||
|
@ -24,6 +25,8 @@ Opensource Git GUI client.
|
|||
* File histories
|
||||
* Blame
|
||||
* Revision Diffs
|
||||
* Branch Diff
|
||||
* Image Diff
|
||||
* GitFlow support
|
||||
|
||||
> **Linux** only tested on **Ubuntu 22.04** on **X11**.
|
||||
|
@ -87,6 +90,48 @@ This app supports open repository in external tools listed in the table below.
|
|||
|
||||
![Theme Light](./screenshots/theme_light.png)
|
||||
|
||||
## How to Customize Theme
|
||||
|
||||
1. Create a new json file, and provide your favorite colors with follow keys:
|
||||
|
||||
| Key | Description |
|
||||
| --- | --- |
|
||||
| Color.Window | Window background color |
|
||||
| Color.WindowBorder | Window border color. Only used on Linux. |
|
||||
| Color.TitleBar | Title bar background color |
|
||||
| Color.ToolBar | Tool bar background color |
|
||||
| Color.Popup | Popup panel background color |
|
||||
| Color.Contents | Background color used in inputs, data grids, file content viewer, change lists, text diff viewer, etc. |
|
||||
| Color.Badage | Badage background color |
|
||||
| Color.Conflict | Conflict panel background color |
|
||||
| Color.ConflictForeground | Conflict panel foreground color |
|
||||
| Color.Border0 | Border color used in some controls, like Window, Tab, Toolbar, etc. |
|
||||
| Color.Border1 | Border color used in inputs, like TextBox, ComboBox, etc. |
|
||||
| Color.Border2 | Border color used in visual lines, like seperators, Rectange, etc. |
|
||||
| Color.FlatButton.Background | Flat button background color, like `Cancel`, `Commit & Push` button |
|
||||
| Color.FlatButton.BackgroundHovered | Flat button background color when hovered, like `Cancel` button |
|
||||
| Color.FlatButton.PrimaryBackground | Primary flat button background color, like `Ok`, `Commit` button |
|
||||
| Color.FlatButton.PrimaryBackgroundHovered | Primary flat button background color when hovered, like `Ok`, `Commit` button |
|
||||
| Color.FG1 | Primary foreground color for all text elements |
|
||||
| Color.FG2 | Secondary foreground color for all text elements |
|
||||
| Color.Diff.EmptyBG | Background color used in empty lines in diff viewer |
|
||||
| Color.Diff.AddedBG | Background color used in added lines in diff viewer |
|
||||
| Color.Diff.DeletedBG | Background color used in deleted lines in diff viewer |
|
||||
| Color.Diff.AddedHighlight | Background color used for changed words in added lines in diff viewer |
|
||||
| Color.Diff.DeletedHighlight | Background color used for changed words in deleted lines in diff viewer |
|
||||
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"Color.Window": "#FFFF6059"
|
||||
}
|
||||
```
|
||||
|
||||
2. Open `Preference` -> `Appearance`, choose the json file you just created in `Custom Color Schema`.
|
||||
|
||||
> **NOTE**: The `Custom Color Schema` will override the colors with same keys in current active theme.
|
||||
|
||||
## Contributing
|
||||
|
||||
Thanks to all the people who contribute.
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
8.16
|
||||
8.17
|
|
@ -6,6 +6,16 @@ if (Test-Path SourceGit) {
|
|||
|
||||
Remove-Item *.zip -Force
|
||||
|
||||
dotnet publish ..\src\SourceGit.csproj -c Release -r win-arm64 -o SourceGit -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
|
||||
|
||||
Remove-Item SourceGit\*.pdb -Force
|
||||
|
||||
Compress-Archive -Path SourceGit -DestinationPath "sourcegit_$version.win-arm64.zip"
|
||||
|
||||
if (Test-Path SourceGit) {
|
||||
Remove-Item SourceGit -Recurse -Force
|
||||
}
|
||||
|
||||
dotnet publish ..\src\SourceGit.csproj -c Release -r win-x64 -o SourceGit -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link --self-contained
|
||||
|
||||
Remove-Item SourceGit\*.pdb -Force
|
||||
|
|
|
@ -1,90 +1,164 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public class GitFlow : Command
|
||||
public static class GitFlow
|
||||
{
|
||||
public GitFlow(string repo)
|
||||
public class BranchDetectResult
|
||||
{
|
||||
WorkingDirectory = repo;
|
||||
Context = repo;
|
||||
public bool IsGitFlowBranch { get; set; } = false;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string Prefix { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public bool Init(List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
|
||||
public static bool IsEnabled(string repo, List<Models.Branch> branches)
|
||||
{
|
||||
var localBrancheNames = new HashSet<string>();
|
||||
foreach (var branch in branches)
|
||||
{
|
||||
if (branch.IsLocal)
|
||||
localBrancheNames.Add(branch.Name);
|
||||
}
|
||||
|
||||
var config = new Config(repo).ListAll();
|
||||
if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master))
|
||||
return false;
|
||||
|
||||
if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop))
|
||||
return false;
|
||||
|
||||
return config.ContainsKey("gitflow.prefix.feature") &&
|
||||
config.ContainsKey("gitflow.prefix.release") &&
|
||||
config.ContainsKey("gitflow.prefix.hotfix");
|
||||
}
|
||||
|
||||
public static bool Init(string repo, List<Models.Branch> branches, string master, string develop, string feature, string release, string hotfix, string version)
|
||||
{
|
||||
var current = branches.Find(x => x.IsCurrent);
|
||||
|
||||
var masterBranch = branches.Find(x => x.Name == master);
|
||||
if (masterBranch == null && current != null)
|
||||
Branch.Create(WorkingDirectory, master, current.Head);
|
||||
Branch.Create(repo, master, current.Head);
|
||||
|
||||
var devBranch = branches.Find(x => x.Name == develop);
|
||||
if (devBranch == null && current != null)
|
||||
Branch.Create(WorkingDirectory, develop, current.Head);
|
||||
Branch.Create(repo, develop, current.Head);
|
||||
|
||||
var cmd = new Config(WorkingDirectory);
|
||||
cmd.Set("gitflow.branch.master", master);
|
||||
cmd.Set("gitflow.branch.develop", develop);
|
||||
cmd.Set("gitflow.prefix.feature", feature);
|
||||
cmd.Set("gitflow.prefix.bugfix", "bugfix/");
|
||||
cmd.Set("gitflow.prefix.release", release);
|
||||
cmd.Set("gitflow.prefix.hotfix", hotfix);
|
||||
cmd.Set("gitflow.prefix.support", "support/");
|
||||
cmd.Set("gitflow.prefix.versiontag", version, true);
|
||||
var config = new Config(repo);
|
||||
config.Set("gitflow.branch.master", master);
|
||||
config.Set("gitflow.branch.develop", develop);
|
||||
config.Set("gitflow.prefix.feature", feature);
|
||||
config.Set("gitflow.prefix.bugfix", "bugfix/");
|
||||
config.Set("gitflow.prefix.release", release);
|
||||
config.Set("gitflow.prefix.hotfix", hotfix);
|
||||
config.Set("gitflow.prefix.support", "support/");
|
||||
config.Set("gitflow.prefix.versiontag", version, true);
|
||||
|
||||
Args = "flow init -d";
|
||||
return Exec();
|
||||
var init = new Command();
|
||||
init.WorkingDirectory = repo;
|
||||
init.Context = repo;
|
||||
init.Args = "flow init -d";
|
||||
return init.Exec();
|
||||
}
|
||||
|
||||
public bool Start(Models.GitFlowBranchType type, string name)
|
||||
public static string Prefix(string repo, string type)
|
||||
{
|
||||
switch (type)
|
||||
return new Config(repo).Get($"gitflow.prefix.{type}");
|
||||
}
|
||||
|
||||
public static BranchDetectResult DetectType(string repo, List<Models.Branch> branches, string branch)
|
||||
{
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
Args = $"flow feature start {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
Args = $"flow release start {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Hotfix:
|
||||
Args = $"flow hotfix start {name}";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
var rs = new BranchDetectResult();
|
||||
var localBrancheNames = new HashSet<string>();
|
||||
foreach (var b in branches)
|
||||
{
|
||||
App.RaiseException(Context, "Bad branch type!!!");
|
||||
if (b.IsLocal)
|
||||
localBrancheNames.Add(b.Name);
|
||||
}
|
||||
|
||||
var config = new Config(repo).ListAll();
|
||||
if (!config.TryGetValue("gitflow.branch.master", out string master) || !localBrancheNames.Contains(master))
|
||||
return rs;
|
||||
|
||||
if (!config.TryGetValue("gitflow.branch.develop", out string develop) || !localBrancheNames.Contains(develop))
|
||||
return rs;
|
||||
|
||||
if (!config.TryGetValue("gitflow.prefix.feature", out var feature) ||
|
||||
!config.TryGetValue("gitflow.prefix.release", out var release) ||
|
||||
!config.TryGetValue("gitflow.prefix.hotfix", out var hotfix))
|
||||
return rs;
|
||||
|
||||
if (branch.StartsWith(feature, StringComparison.Ordinal))
|
||||
{
|
||||
rs.IsGitFlowBranch = true;
|
||||
rs.Type = "feature";
|
||||
rs.Prefix = feature;
|
||||
}
|
||||
else if (branch.StartsWith(release, StringComparison.Ordinal))
|
||||
{
|
||||
rs.IsGitFlowBranch = true;
|
||||
rs.Type = "release";
|
||||
rs.Prefix = release;
|
||||
}
|
||||
else if (branch.StartsWith(hotfix, StringComparison.Ordinal))
|
||||
{
|
||||
rs.IsGitFlowBranch = true;
|
||||
rs.Type = "hotfix";
|
||||
rs.Prefix = hotfix;
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
public static bool Start(string repo, string type, string name)
|
||||
{
|
||||
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Bad branch type!!!");
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return Exec();
|
||||
var start = new Command();
|
||||
start.WorkingDirectory = repo;
|
||||
start.Context = repo;
|
||||
start.Args = $"flow {type} start {name}";
|
||||
return start.Exec();
|
||||
}
|
||||
|
||||
public bool Finish(Models.GitFlowBranchType type, string name, bool keepBranch)
|
||||
public static bool Finish(string repo, string type, string name, bool keepBranch)
|
||||
{
|
||||
if (!SUPPORTED_BRANCH_TYPES.Contains(type))
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
App.RaiseException(repo, "Bad branch type!!!");
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var option = keepBranch ? "-k" : string.Empty;
|
||||
switch (type)
|
||||
{
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
Args = $"flow feature finish {option} {name}";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
Args = $"flow release finish {option} {name} -m \"RELEASE_DONE\"";
|
||||
break;
|
||||
case Models.GitFlowBranchType.Hotfix:
|
||||
Args = $"flow hotfix finish {option} {name} -m \"HOTFIX_DONE\"";
|
||||
break;
|
||||
default:
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
App.RaiseException(Context, "Bad branch type!!!");
|
||||
});
|
||||
return false;
|
||||
var finish = new Command();
|
||||
finish.WorkingDirectory = repo;
|
||||
finish.Context = repo;
|
||||
finish.Args = $"flow {type} finish {option} {name}";
|
||||
return finish.Exec();
|
||||
}
|
||||
|
||||
return Exec();
|
||||
}
|
||||
private static readonly List<string> SUPPORTED_BRANCH_TYPES = new List<string>()
|
||||
{
|
||||
"feature",
|
||||
"release",
|
||||
"bugfix",
|
||||
"hotfix",
|
||||
"support",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
16
src/Commands/GitIgnore.cs
Normal file
16
src/Commands/GitIgnore.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.IO;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
public static class GitIgnore
|
||||
{
|
||||
public static void Add(string repo, string pattern)
|
||||
{
|
||||
var file = Path.Combine(repo, ".gitignore");
|
||||
if (!File.Exists(file))
|
||||
File.WriteAllLines(file, [ pattern ]);
|
||||
else
|
||||
File.AppendAllLines(file, [ pattern ]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,8 @@ namespace SourceGit.Commands
|
|||
public string Result()
|
||||
{
|
||||
var rs = ReadToEnd();
|
||||
if (rs.IsSuccess) return rs.StdOut.TrimEnd();
|
||||
if (rs.IsSuccess)
|
||||
return rs.StdOut.TrimEnd();
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ namespace SourceGit.Commands
|
|||
end = rs.StdOut.IndexOf('\n', start);
|
||||
}
|
||||
|
||||
if (start < rs.StdOut.Length)
|
||||
_current.Subject = rs.StdOut.Substring(start);
|
||||
|
||||
if (_findFirstMerged && !_isHeadFounded && _commits.Count > 0)
|
||||
MarkFirstMerged();
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SourceGit.Commands
|
||||
{
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
namespace SourceGit.Converters
|
||||
{
|
||||
public static class WindowStateConverters
|
||||
{
|
||||
public static readonly FuncValueConverter<WindowState, Thickness> ToContentMargin =
|
||||
new FuncValueConverter<WindowState, Thickness>(state =>
|
||||
{
|
||||
if (OperatingSystem.IsWindows() && state == WindowState.Maximized)
|
||||
return new Thickness(6);
|
||||
else if (OperatingSystem.IsLinux() && state != WindowState.Maximized)
|
||||
return new Thickness(6);
|
||||
else
|
||||
return new Thickness(0);
|
||||
});
|
||||
|
||||
public static readonly FuncValueConverter<WindowState, GridLength> ToTitleBarHeight =
|
||||
new FuncValueConverter<WindowState, GridLength>(state =>
|
||||
{
|
||||
if (state == WindowState.Maximized)
|
||||
return new GridLength(OperatingSystem.IsMacOS() ? 34 : 30);
|
||||
else
|
||||
return new GridLength(38);
|
||||
});
|
||||
|
||||
public static readonly FuncValueConverter<WindowState, bool> IsNormal =
|
||||
new FuncValueConverter<WindowState, bool>(state => state == WindowState.Normal);
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
namespace SourceGit.Models
|
||||
{
|
||||
public enum GitFlowBranchType
|
||||
{
|
||||
None,
|
||||
Feature,
|
||||
Release,
|
||||
Hotfix,
|
||||
}
|
||||
|
||||
public class GitFlow
|
||||
{
|
||||
public string Feature { get; set; }
|
||||
public string Release { get; set; }
|
||||
public string Hotfix { get; set; }
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrEmpty(Feature)
|
||||
&& !string.IsNullOrEmpty(Release)
|
||||
&& !string.IsNullOrEmpty(Hotfix);
|
||||
}
|
||||
}
|
||||
|
||||
public GitFlowBranchType GetBranchType(string name)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
return GitFlowBranchType.None;
|
||||
if (name.StartsWith(Feature))
|
||||
return GitFlowBranchType.Feature;
|
||||
if (name.StartsWith(Release))
|
||||
return GitFlowBranchType.Release;
|
||||
if (name.StartsWith(Hotfix))
|
||||
return GitFlowBranchType.Hotfix;
|
||||
return GitFlowBranchType.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -98,4 +98,6 @@
|
|||
<StreamGeometry x:Key="Icons.Lines.Decr">M408 232C408 210 426 192 448 192h416a40 40 0 110 80H448a40 40 0 01-40-40zM408 512c0-22 18-40 40-40h416a40 40 0 110 80H448A40 40 0 01408 512zM448 752A40 40 0 00448 832h416a40 40 0 100-80H448zM32 480l328 0 0 64-328 0Z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Compare">M645 448l64 64 220-221L704 64l-64 64 115 115H128v90h628zM375 576l-64-64-220 224L314 960l64-64-116-115H896v-90H262z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.WordWrap">M248 221a77 77 0 00-30-21c-18-7-40-10-68-5a224 224 0 00-45 13c-5 2-10 5-15 8l-3 2v68l11-9c10-8 21-14 34-19 13-5 26-7 39-7 12 0 21 3 28 10 6 6 9 16 9 29l-62 9c-14 2-26 6-36 11a80 80 0 00-25 20c-7 8-12 17-15 27-6 21-6 44 1 65a70 70 0 0041 43c10 4 21 6 34 6a80 80 0 0063-28v22h64V298c0-16-2-31-6-44a91 91 0 00-18-33zm-41 121v15c0 8-1 15-4 22a48 48 0 01-24 29 44 44 0 01-33 2 29 29 0 01-10-6 25 25 0 01-6-9 30 30 0 01-2-12c0-5 1-9 2-14a21 21 0 015-9 28 28 0 0110-7 83 83 0 0120-5l42-6zm323-68a144 144 0 00-16-42 87 87 0 00-28-29 75 75 0 00-41-11 73 73 0 00-44 14c-6 5-12 11-17 17V64H326v398h59v-18c8 10 18 17 30 21 6 2 13 3 21 3 16 0 31-4 43-11 12-7 23-18 31-31a147 147 0 0019-46 248 248 0 006-57c0-17-2-33-5-49zm-55 49c0 15-1 28-4 39-2 11-6 20-10 27a41 41 0 01-15 15 37 37 0 01-36 1 44 44 0 01-13-12 59 59 0 01-9-18A76 76 0 01384 352v-33c0-10 1-20 4-29 2-8 6-15 10-22a43 43 0 0115-13 37 37 0 0119-5 35 35 0 0132 18c4 6 7 14 9 23 2 9 3 20 3 31zM154 634a58 58 0 0120-15c14-6 35-7 49-1 7 3 13 6 20 12l21 17V572l-6-4a124 124 0 00-58-14c-20 0-38 4-54 11-16 7-30 17-41 30-12 13-20 29-26 46-6 17-9 36-9 57 0 18 3 36 8 52 6 16 14 30 24 42 10 12 23 21 38 28 15 7 32 10 50 10 15 0 28-2 39-5 11-3 21-8 30-14l5-4v-57l-13 6a26 26 0 01-5 2c-3 1-6 2-8 3-2 1-15 6-15 6-4 2-9 3-14 4a63 63 0 01-38-4 53 53 0 01-20-14 70 70 0 01-13-24 111 111 0 01-5-34c0-13 2-26 5-36 3-10 8-19 14-26zM896 384h-256V320h288c21 1 32 12 32 32v384c0 18-12 32-32 32H504l132 133-45 45-185-185c-16-21-16-25 0-45l185-185L637 576l-128 128H896V384z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.Detached">M128 183C128 154 154 128 183 128h521c30 0 55 26 55 55v38c0 17-17 34-34 34s-34-17-34-34v-26H196v495h26c17 0 34 17 34 34s-17 34-34 34h-38c-30 0-55-26-55-55V183zM380 896h-34c-26 0-47-21-47-47v-90h68V828h64V896H380c4 0 0 0 0 0zM759 828V896h90c26 0 47-21 47-47v-90h-68V828h-68zM828 435H896V346c0-26-21-47-47-47h-90v68H828v68zM435 299v68H367V439H299V346C299 320 320 299 346 299h90zM367 649H299v-107h68v107zM546 367V299h107v68h-107zM828 546H896v107h-68v-107zM649 828V896h-107v-68h107zM730 508v188c0 17-17 34-34 34h-188c-17 0-34-17-34-34s17-34 34-34h102l-124-124c-13-13-13-34 0-47 13-13 34-13 47 0l124 124V512c0-17 17-34 34-34 21-4 38 9 38 30z</StreamGeometry>
|
||||
<StreamGeometry x:Key="Icons.GitIgnore">M590 74 859 342V876c0 38-31 68-68 68H233c-38 0-68-31-68-68V142c0-38 31-68 68-68h357zm-12 28H233a40 40 0 00-40 38L193 142v734a40 40 0 0038 40L233 916h558a40 40 0 0040-38L831 876V354L578 102zM855 371h-215c-46 0-83-36-84-82l0-2V74h28v213c0 30 24 54 54 55l2 0h215v28zM57 489m28 0 853 0q28 0 28 28l0 284q0 28-28 28l-853 0q-28 0-28-28l0-284q0-28 28-28ZM157 717c15 0 29-6 37-13v-51h-41v22h17v18c-2 2-6 3-10 3-21 0-30-13-30-34 0-21 12-34 28-34 9 0 15 4 20 9l14-17C184 610 172 603 156 603c-29 0-54 21-54 57 0 37 24 56 54 56zM245 711v-108h-34v108h34zm69 0v-86H341V603H262v22h28V711h24zM393 711v-108h-34v108h34zm66 6c15 0 29-6 37-13v-51h-41v22h17v18c-2 2-6 3-10 3-21 0-30-13-30-34 0-21 12-34 28-34 9 0 15 4 20 9l14-17C485 610 474 603 458 603c-29 0-54 21-54 57 0 37 24 56 54 56zm88-6v-36c0-13-2-28-3-40h1l10 24 25 52H603v-108h-23v36c0 13 2 28 3 40h-1l-10-24L548 603H523v108h23zM677 717c30 0 51-22 51-57 0-36-21-56-51-56-30 0-51 20-51 56 0 36 21 57 51 57zm3-23c-16 0-26-12-26-32 0-19 10-31 26-31 16 0 26 11 26 31S696 694 680 694zm93 17v-38h13l21 38H836l-25-43c12-5 19-15 19-31 0-26-20-34-44-34H745v108h27zm16-51H774v-34h15c16 0 25 4 25 16s-9 18-25 18zM922 711v-22h-43v-23h35v-22h-35V625h41V603H853v108h68z</StreamGeometry>
|
||||
</ResourceDictionary>
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
<x:String x:Key="Text.Blame" xml:space="preserve">Blame</x:String>
|
||||
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">BLAME ON THIS FILE IS NOT SUPPORTED!!!</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">Checkout${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">Compare with Branch</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">Compare with HEAD</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">Compare with Worktree</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CopyName" xml:space="preserve">Copy Branch Name</x:String>
|
||||
|
@ -49,6 +50,7 @@
|
|||
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">Rename${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">Tracking ...</x:String>
|
||||
<x:String x:Key="Text.BranchCM.UnsetUpstream" xml:space="preserve">Unset Upstream</x:String>
|
||||
<x:String x:Key="Text.BranchCompare" xml:space="preserve">Branch Compare</x:String>
|
||||
<x:String x:Key="Text.Bytes" xml:space="preserve">Bytes</x:String>
|
||||
<x:String x:Key="Text.Cancel" xml:space="preserve">CANCEL</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">CHANGE DISPLAY MODE</x:String>
|
||||
|
@ -241,6 +243,8 @@
|
|||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">Create new page</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreference" xml:space="preserve">Open preference dialog</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">REPOSITORY</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">Commit staged changes</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">Commit and push staged changes</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">Force to reload this repository</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">Stage/Unstage selected changes</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Open commit search</x:String>
|
||||
|
@ -473,6 +477,11 @@
|
|||
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">Search Repositories ...</x:String>
|
||||
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">Sort</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">Changes</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore" xml:space="preserve">Add To .gitignore ...</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.Extension" xml:space="preserve">Ignore all *{0} files</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">Ignore *{0} files in the same folder</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">Ignore files in the same folder</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">Ignore this file only</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">Amend</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">You can stage this file now.</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">COMMIT</x:String>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<x:String x:Key="Text.Blame" xml:space="preserve">逐行追溯(blame)</x:String>
|
||||
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">选中文件不支持该操作!!!</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">检出(checkout)${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">与其他分支对比</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">与当前HEAD比较</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">与本地工作树比较</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CopyName" xml:space="preserve">复制分支名</x:String>
|
||||
|
@ -52,6 +53,7 @@
|
|||
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">重命名${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">切换上游分支...</x:String>
|
||||
<x:String x:Key="Text.BranchCM.UnsetUpstream" xml:space="preserve">取消追踪</x:String>
|
||||
<x:String x:Key="Text.BranchCompare" xml:space="preserve">分支比较</x:String>
|
||||
<x:String x:Key="Text.Bytes" xml:space="preserve">字节</x:String>
|
||||
<x:String x:Key="Text.Cancel" xml:space="preserve">取 消</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">切换变更显示模式</x:String>
|
||||
|
@ -244,6 +246,8 @@
|
|||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">新建页面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreference" xml:space="preserve">打开偏好设置面板</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">仓库页面快捷键</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">提交暂存区更改</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">提交暂存区更改并推送</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">重新加载仓库状态</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">将选中的变更暂存或从暂存列表中移除</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">打开历史搜索</x:String>
|
||||
|
@ -476,6 +480,11 @@
|
|||
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">快速查找仓库...</x:String>
|
||||
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">排序</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">本地更改</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore" xml:space="preserve">添加至 .gitignore 忽略列表 ...</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.Extension" xml:space="preserve">忽略所有 *{0} 文件</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">忽略同目录下所有 *{0} 文件</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">忽略同目录下所有文件</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">忽略本文件</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">修补(--amend)</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">现在您已可将其加入暂存区中</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">提交</x:String>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<x:String x:Key="Text.Blame" xml:space="preserve">逐行追溯(blame)</x:String>
|
||||
<x:String x:Key="Text.BlameTypeNotSupported" xml:space="preserve">選中檔案不支援該操作!!!</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Checkout" xml:space="preserve">檢出(checkout)${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithBranch" xml:space="preserve">與其他分支比較</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithHead" xml:space="preserve">與當前HEAD比較</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CompareWithWorktree" xml:space="preserve">與本地工作樹比較</x:String>
|
||||
<x:String x:Key="Text.BranchCM.CopyName" xml:space="preserve">複製分支名</x:String>
|
||||
|
@ -52,6 +53,7 @@
|
|||
<x:String x:Key="Text.BranchCM.Rename" xml:space="preserve">重新命名${0}$</x:String>
|
||||
<x:String x:Key="Text.BranchCM.Tracking" xml:space="preserve">切換上游分支...</x:String>
|
||||
<x:String x:Key="Text.BranchCM.UnsetUpstream" xml:space="preserve">取消追蹤</x:String>
|
||||
<x:String x:Key="Text.BranchCompare" xml:space="preserve">分支比較</x:String>
|
||||
<x:String x:Key="Text.Bytes" xml:space="preserve">位元組</x:String>
|
||||
<x:String x:Key="Text.Cancel" xml:space="preserve">取 消</x:String>
|
||||
<x:String x:Key="Text.ChangeDisplayMode" xml:space="preserve">切換變更顯示模式</x:String>
|
||||
|
@ -244,6 +246,8 @@
|
|||
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">新建頁面</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Global.OpenPreference" xml:space="preserve">開啟偏好設定面板</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">倉庫頁面快捷鍵</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">提交暫存區變更</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">提交暫存區變更併推送</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.Refresh" xml:space="preserve">重新載入倉庫狀態</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.StageOrUnstageSelected" xml:space="preserve">將選中的變更暫存或從暫存列表中移除</x:String>
|
||||
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">開啟歷史搜尋</x:String>
|
||||
|
@ -476,6 +480,11 @@
|
|||
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">快速查詢倉庫...</x:String>
|
||||
<x:String x:Key="Text.Welcome.Sort" xml:space="preserve">排序</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy" xml:space="preserve">本地更改</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore" xml:space="preserve">添加至 .gitignore 忽略清單 ...</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.Extension" xml:space="preserve">忽略所有 *{0} 檔案</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.ExtensionInSameFolder" xml:space="preserve">忽略同路徑下所有 *{0} 檔案</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.InSameFolder" xml:space="preserve">忽略同路徑下所有檔案</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.AddToGitIgnore.SingleFile" xml:space="preserve">忽略本檔案</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.Amend" xml:space="preserve">修補(--amend)</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.CanStageTip" xml:space="preserve">現在您已可將其加入暫存區中</x:String>
|
||||
<x:String x:Key="Text.WorkingCopy.Commit" xml:space="preserve">提交</x:String>
|
||||
|
|
|
@ -18,6 +18,143 @@
|
|||
<Setter Property="HideDelay" Value="0:0:0.2"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window">
|
||||
<Setter Property="Background" Value="{DynamicResource Brush.Window}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border0}"/>
|
||||
<Setter Property="ExtendClientAreaChromeHints" Value="NoChrome"/>
|
||||
<Setter Property="ExtendClientAreaToDecorationsHint" Value="True"/>
|
||||
<Setter Property="SystemDecorations" Value="Full"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
|
||||
<Style.Resources>
|
||||
<SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="Red"/>
|
||||
<SolidColorBrush x:Key="SystemErrorTextColor" Color="Red"/>
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window[WindowState=Maximized]">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window[WindowState=Maximized].fix_maximized_padding">
|
||||
<Setter Property="Padding" Value="6"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window.custom_window_frame">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="SystemDecorations" Value="None"/>
|
||||
<Setter Property="Padding" Value="12"/>
|
||||
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<Border x:Name="PART_BorderTopLeft"
|
||||
Classes="resize_border"
|
||||
Width="12" Height="12"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"/>
|
||||
|
||||
<Border x:Name="PART_BorderTop"
|
||||
Classes="resize_border"
|
||||
Height="12" Margin="12,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"/>
|
||||
|
||||
<Border x:Name="PART_BorderTopRight"
|
||||
Classes="resize_border"
|
||||
Width="12" Height="12"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"/>
|
||||
|
||||
<Border x:Name="PART_BorderLeft"
|
||||
Classes="resize_border"
|
||||
Width="12" Margin="0,12"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"/>
|
||||
|
||||
<Border x:Name="PART_BorderRight"
|
||||
Classes="resize_border"
|
||||
Width="12" Margin="0,12"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"/>
|
||||
|
||||
<Border x:Name="PART_BorderBottomLeft"
|
||||
Classes="resize_border"
|
||||
Width="12" Height="12"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"/>
|
||||
|
||||
<Border x:Name="PART_BorderBottom"
|
||||
Classes="resize_border"
|
||||
Height="12" Margin="12,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"/>
|
||||
|
||||
<Border x:Name="PART_BorderBottomRight"
|
||||
Classes="resize_border"
|
||||
Width="12" Height="12"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"/>
|
||||
|
||||
<Grid Margin="{TemplateBinding Padding}" Effect="drop-shadow(0 0 12 #A0000000)">
|
||||
<Border x:Name="PART_ContentRoot"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
BorderBrush="{DynamicResource Brush.WindowBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<VisualLayerManager>
|
||||
<Border CornerRadius="8" ClipToBounds="True">
|
||||
<ContentPresenter Name="PART_ContentPresenter"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
Content="{TemplateBinding Content}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Border>
|
||||
</VisualLayerManager>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window.custom_window_frame[WindowState=Maximized]">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window.custom_window_frame[WindowState=Maximized] /template/ Border#PART_ContentRoot">
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window.custom_window_frame[WindowState=Maximized] /template/ Border.resize_border">
|
||||
<Setter Property="IsVisible" Value="False"/>
|
||||
<Setter Property="IsHitTestVisible" Value="False"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Window.custom_window_frame[CanResize=False] /template/ Border.resize_border">
|
||||
<Setter Property="IsVisible" Value="False"/>
|
||||
<Setter Property="IsHitTestVisible" Value="False"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="ContentPresenter">
|
||||
<Setter Property="FontFamily" Value="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFont}"/>
|
||||
<Setter Property="FontSize" Value="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize}"/>
|
||||
|
@ -1163,4 +1300,22 @@
|
|||
<Style Selector="TreeDataGridExpanderCell[IsExpanded=False] Path.folder_icon">
|
||||
<Setter Property="Data" Value="{StaticResource Icons.Folder.Fill}"/>
|
||||
</Style>
|
||||
|
||||
<Style Selector="NumericUpDown">
|
||||
<Style Selector="^ /template/ ButtonSpinner#PART_Spinner">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
</Style>
|
||||
<Style Selector="^ /template/ TextBox#PART_TextBox">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style Selector="^:focus-within /template/ ButtonSpinner#PART_Spinner">
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Accent}"/>
|
||||
</Style>
|
||||
<Style Selector="^ /template/ TextBox#PART_TextBox /template/ Border#PART_BorderElement">
|
||||
<Setter Property="IsVisible" Value="False"/>
|
||||
</Style>
|
||||
</Style>
|
||||
</Styles>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<Color x:Key="Color.MacOS.Minimize">#FFFFBE2F</Color>
|
||||
<Color x:Key="Color.MacOS.Maximize">#FF29c941</Color>
|
||||
<Color x:Key="Color.Window">#FFF0F5F9</Color>
|
||||
<Color x:Key="Color.WindowBorder">#FFAFAFAF</Color>
|
||||
<Color x:Key="Color.TitleBar">#FFCFDEEA</Color>
|
||||
<Color x:Key="Color.ToolBar">#FFF0F5F9</Color>
|
||||
<Color x:Key="Color.Popup">#FFF8F8F8</Color>
|
||||
|
@ -14,22 +15,21 @@
|
|||
<Color x:Key="Color.Decorator">#FF6F6F6F</Color>
|
||||
<Color x:Key="Color.DecoratorIcon">#FFF8F8F8</Color>
|
||||
<Color x:Key="Color.Conflict">#FF836C2E</Color>
|
||||
<Color x:Key="Color.ConflictForeground">#FFFFFFFF</Color>
|
||||
<Color x:Key="Color.Border0">#FFCFCFCF</Color>
|
||||
<Color x:Key="Color.Border1">#FF898989</Color>
|
||||
<Color x:Key="Color.Border2">#FFCFCFCF</Color>
|
||||
<Color x:Key="Color.Border3">#FFEFEFEF</Color>
|
||||
<Color x:Key="Color.FlatButton.Background">#FFF8F8F8</Color>
|
||||
<Color x:Key="Color.FlatButton.BackgroundHovered">White</Color>
|
||||
<Color x:Key="Color.FlatButton.PrimaryBackground">#FF4295FF</Color>
|
||||
<Color x:Key="Color.FlatButton.PrimaryBackgroundHovered">#FF529DFB</Color>
|
||||
<Color x:Key="Color.FG1">#FF1F1F1F</Color>
|
||||
<Color x:Key="Color.FG2">#FF6F6F6F</Color>
|
||||
<Color x:Key="Color.FG3">#FFFFFFFF</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG1.EMPTY">#3C000000</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG1.ADD">#3C00FF00</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG1.DELETED">#3CFF0000</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG2.ADD">#5A00FF00</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG2.DELETED">#50FF0000</Color>
|
||||
<Color x:Key="Color.Diff.EmptyBG">#3C000000</Color>
|
||||
<Color x:Key="Color.Diff.AddedBG">#3C00FF00</Color>
|
||||
<Color x:Key="Color.Diff.DeletedBG">#3CFF0000</Color>
|
||||
<Color x:Key="Color.Diff.AddedHighlight">#5A00FF00</Color>
|
||||
<Color x:Key="Color.Diff.DeletedHighlight">#50FF0000</Color>
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
|
@ -37,6 +37,7 @@
|
|||
<Color x:Key="Color.MacOS.Minimize">#FFFCBB2D</Color>
|
||||
<Color x:Key="Color.MacOS.Maximize">#FF25C53C</Color>
|
||||
<Color x:Key="Color.Window">#FF252525</Color>
|
||||
<Color x:Key="Color.WindowBorder">#FF444444</Color>
|
||||
<Color x:Key="Color.TitleBar">#FF1F1F1F</Color>
|
||||
<Color x:Key="Color.ToolBar">#FF2C2C2C</Color>
|
||||
<Color x:Key="Color.Popup">#FF2B2B2B</Color>
|
||||
|
@ -45,22 +46,21 @@
|
|||
<Color x:Key="Color.Decorator">#FF505050</Color>
|
||||
<Color x:Key="Color.DecoratorIcon">#FFF8F8F8</Color>
|
||||
<Color x:Key="Color.Conflict">#FFFAFAD2</Color>
|
||||
<Color x:Key="Color.ConflictForeground">#FF252525</Color>
|
||||
<Color x:Key="Color.Border0">#FF181818</Color>
|
||||
<Color x:Key="Color.Border1">#FF7C7C7C</Color>
|
||||
<Color x:Key="Color.Border2">#FF404040</Color>
|
||||
<Color x:Key="Color.Border3">#FF252525</Color>
|
||||
<Color x:Key="Color.FlatButton.Background">#FF303030</Color>
|
||||
<Color x:Key="Color.FlatButton.BackgroundHovered">#FF333333</Color>
|
||||
<Color x:Key="Color.FlatButton.PrimaryBackground">#FF3A3A3A</Color>
|
||||
<Color x:Key="Color.FlatButton.PrimaryBackgroundHovered">#FF404040</Color>
|
||||
<Color x:Key="Color.FG1">#FFDDDDDD</Color>
|
||||
<Color x:Key="Color.FG2">#40F1F1F1</Color>
|
||||
<Color x:Key="Color.FG3">#FF252525</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG1.EMPTY">#3C000000</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG1.ADD">#3C00FF00</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG1.DELETED">#3CFF0000</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG2.ADD">#5A00FF00</Color>
|
||||
<Color x:Key="Color.TextDiffView.LineBG2.DELETED">#50FF0000</Color>
|
||||
<Color x:Key="Color.Diff.EmptyBG">#3C000000</Color>
|
||||
<Color x:Key="Color.Diff.AddedBG">#3C00FF00</Color>
|
||||
<Color x:Key="Color.Diff.DeletedBG">#3CFF0000</Color>
|
||||
<Color x:Key="Color.Diff.AddedHighlight">#5A00FF00</Color>
|
||||
<Color x:Key="Color.Diff.DeletedHighlight">#50FF0000</Color>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
|||
<SolidColorBrush x:Key="Brush.MacOS.Minimize" Color="{DynamicResource Color.MacOS.Minimize}"/>
|
||||
<SolidColorBrush x:Key="Brush.MacOS.Maximize" Color="{DynamicResource Color.MacOS.Maximize}"/>
|
||||
<SolidColorBrush x:Key="Brush.Window" Color="{DynamicResource Color.Window}"/>
|
||||
<SolidColorBrush x:Key="Brush.WindowBorder" Color="{DynamicResource Color.WindowBorder}"/>
|
||||
<SolidColorBrush x:Key="Brush.TitleBar" Color="{DynamicResource Color.TitleBar}"/>
|
||||
<SolidColorBrush x:Key="Brush.ToolBar" Color="{DynamicResource Color.ToolBar}"/>
|
||||
<SolidColorBrush x:Key="Brush.Popup" Color="{DynamicResource Color.Popup}"/>
|
||||
|
@ -76,22 +77,21 @@
|
|||
<SolidColorBrush x:Key="Brush.Decorator" Color="{DynamicResource Color.Decorator}"/>
|
||||
<SolidColorBrush x:Key="Brush.DecoratorIcon" Color="{DynamicResource Color.DecoratorIcon}"/>
|
||||
<SolidColorBrush x:Key="Brush.Conflict" Color="{DynamicResource Color.Conflict}"/>
|
||||
<SolidColorBrush x:Key="Brush.ConflictForeground" Color="{DynamicResource Color.ConflictForeground}"/>
|
||||
<SolidColorBrush x:Key="Brush.Border0" Color="{DynamicResource Color.Border0}"/>
|
||||
<SolidColorBrush x:Key="Brush.Border1" Color="{DynamicResource Color.Border1}"/>
|
||||
<SolidColorBrush x:Key="Brush.Border2" Color="{DynamicResource Color.Border2}"/>
|
||||
<SolidColorBrush x:Key="Brush.Border3" Color="{DynamicResource Color.Border3}"/>
|
||||
<SolidColorBrush x:Key="Brush.FlatButton.Background" Color="{DynamicResource Color.FlatButton.Background}"/>
|
||||
<SolidColorBrush x:Key="Brush.FlatButton.BackgroundHovered" Color="{DynamicResource Color.FlatButton.BackgroundHovered}"/>
|
||||
<SolidColorBrush x:Key="Brush.FlatButton.PrimaryBackground" Color="{DynamicResource Color.FlatButton.PrimaryBackground}"/>
|
||||
<SolidColorBrush x:Key="Brush.FlatButton.PrimaryBackgroundHovered" Color="{DynamicResource Color.FlatButton.PrimaryBackgroundHovered}"/>
|
||||
<SolidColorBrush x:Key="Brush.FG1" Color="{DynamicResource Color.FG1}"/>
|
||||
<SolidColorBrush x:Key="Brush.FG2" Color="{DynamicResource Color.FG2}"/>
|
||||
<SolidColorBrush x:Key="Brush.FG3" Color="{DynamicResource Color.FG3}"/>
|
||||
<SolidColorBrush x:Key="Brush.Accent" Color="{DynamicResource SystemAccentColor}"/>
|
||||
<SolidColorBrush x:Key="Brush.AccentHovered" Color="{DynamicResource SystemListLowColor}"/>
|
||||
<SolidColorBrush x:Key="Brush.TextDiffView.LineBG1.EMPTY" Color="{DynamicResource Color.TextDiffView.LineBG1.EMPTY}"/>
|
||||
<SolidColorBrush x:Key="Brush.TextDiffView.LineBG1.ADD" Color="{DynamicResource Color.TextDiffView.LineBG1.ADD}"/>
|
||||
<SolidColorBrush x:Key="Brush.TextDiffView.LineBG1.DELETED" Color="{DynamicResource Color.TextDiffView.LineBG1.DELETED}"/>
|
||||
<SolidColorBrush x:Key="Brush.TextDiffView.LineBG2.ADD" Color="{DynamicResource Color.TextDiffView.LineBG2.ADD}"/>
|
||||
<SolidColorBrush x:Key="Brush.TextDiffView.LineBG2.DELETED" Color="{DynamicResource Color.TextDiffView.LineBG2.DELETED}"/>
|
||||
<SolidColorBrush x:Key="Brush.Diff.EmptyBG" Color="{DynamicResource Color.Diff.EmptyBG}"/>
|
||||
<SolidColorBrush x:Key="Brush.Diff.AddedBG" Color="{DynamicResource Color.Diff.AddedBG}"/>
|
||||
<SolidColorBrush x:Key="Brush.Diff.DeletedBG" Color="{DynamicResource Color.Diff.DeletedBG}"/>
|
||||
<SolidColorBrush x:Key="Brush.Diff.AddedHighlight" Color="{DynamicResource Color.Diff.AddedHighlight}"/>
|
||||
<SolidColorBrush x:Key="Brush.Diff.DeletedHighlight" Color="{DynamicResource Color.Diff.DeletedHighlight}"/>
|
||||
</ResourceDictionary>
|
||||
|
|
222
src/ViewModels/BranchCompare.cs
Normal file
222
src/ViewModels/BranchCompare.cs
Normal file
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public class BranchCompare : ObservableObject
|
||||
{
|
||||
public Models.Branch Base
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Models.Branch To
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Models.Commit BaseHead
|
||||
{
|
||||
get => _baseHead;
|
||||
private set => SetProperty(ref _baseHead, value);
|
||||
}
|
||||
|
||||
public Models.Commit ToHead
|
||||
{
|
||||
get => _toHead;
|
||||
private set => SetProperty(ref _toHead, value);
|
||||
}
|
||||
|
||||
public List<Models.Change> VisibleChanges
|
||||
{
|
||||
get => _visibleChanges;
|
||||
private set => SetProperty(ref _visibleChanges, value);
|
||||
}
|
||||
|
||||
public List<Models.Change> SelectedChanges
|
||||
{
|
||||
get => _selectedChanges;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedChanges, value))
|
||||
{
|
||||
if (value != null && value.Count == 1)
|
||||
DiffContext = new DiffContext(_repo, new Models.DiffOption(Base.Head, To.Head, value[0]), _diffContext);
|
||||
else
|
||||
DiffContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string SearchFilter
|
||||
{
|
||||
get => _searchFilter;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchFilter, value))
|
||||
{
|
||||
RefreshVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DiffContext DiffContext
|
||||
{
|
||||
get => _diffContext;
|
||||
private set => SetProperty(ref _diffContext, value);
|
||||
}
|
||||
|
||||
public BranchCompare(string repo, Models.Branch baseBranch, Models.Branch toBranch)
|
||||
{
|
||||
_repo = repo;
|
||||
|
||||
Base = baseBranch;
|
||||
To = toBranch;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
var baseHead = new Commands.QuerySingleCommit(_repo, Base.Head).Result();
|
||||
var toHead = new Commands.QuerySingleCommit(_repo, To.Head).Result();
|
||||
_changes = new Commands.CompareRevisions(_repo, Base.Head, To.Head).Result();
|
||||
|
||||
var visible = _changes;
|
||||
if (!string.IsNullOrWhiteSpace(_searchFilter))
|
||||
{
|
||||
visible = new List<Models.Change>();
|
||||
foreach (var c in _changes)
|
||||
{
|
||||
if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
|
||||
visible.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
BaseHead = baseHead;
|
||||
ToHead = toHead;
|
||||
VisibleChanges = visible;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void NavigateTo(string commitSHA)
|
||||
{
|
||||
var repo = Preference.FindRepository(_repo);
|
||||
if (repo != null)
|
||||
repo.NavigateToCommit(commitSHA);
|
||||
}
|
||||
|
||||
public void ClearSearchFilter()
|
||||
{
|
||||
SearchFilter = string.Empty;
|
||||
}
|
||||
|
||||
public ContextMenu CreateChangeContextMenu()
|
||||
{
|
||||
if (_selectedChanges == null || _selectedChanges.Count != 1)
|
||||
return null;
|
||||
|
||||
var change = _selectedChanges[0];
|
||||
var menu = new ContextMenu();
|
||||
|
||||
var diffWithMerger = new MenuItem();
|
||||
diffWithMerger.Header = App.Text("DiffWithMerger");
|
||||
diffWithMerger.Icon = App.CreateMenuIcon("Icons.Diff");
|
||||
diffWithMerger.Click += (_, ev) =>
|
||||
{
|
||||
var opt = new Models.DiffOption(Base.Head, To.Head, change);
|
||||
var type = Preference.Instance.ExternalMergeToolType;
|
||||
var exec = Preference.Instance.ExternalMergeToolPath;
|
||||
|
||||
var tool = Models.ExternalMerger.Supported.Find(x => x.Type == type);
|
||||
if (tool == null || !File.Exists(exec))
|
||||
{
|
||||
App.RaiseException(_repo, "Invalid merge tool in preference setting!");
|
||||
return;
|
||||
}
|
||||
|
||||
var args = tool.Type != 0 ? tool.DiffCmd : Preference.Instance.ExternalMergeToolDiffCmd;
|
||||
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo, exec, args, opt));
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(diffWithMerger);
|
||||
|
||||
if (change.Index != Models.ChangeState.Deleted)
|
||||
{
|
||||
var full = Path.GetFullPath(Path.Combine(_repo, change.Path));
|
||||
var explore = new MenuItem();
|
||||
explore.Header = App.Text("RevealFile");
|
||||
explore.Icon = App.CreateMenuIcon("Icons.Folder.Open");
|
||||
explore.IsEnabled = File.Exists(full);
|
||||
explore.Click += (_, ev) =>
|
||||
{
|
||||
Native.OS.OpenInFileManager(full, true);
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(explore);
|
||||
}
|
||||
|
||||
var copyPath = new MenuItem();
|
||||
copyPath.Header = App.Text("CopyPath");
|
||||
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||
copyPath.Click += (_, ev) =>
|
||||
{
|
||||
App.CopyText(change.Path);
|
||||
ev.Handled = true;
|
||||
};
|
||||
menu.Items.Add(copyPath);
|
||||
|
||||
var copyFileName = new MenuItem();
|
||||
copyFileName.Header = App.Text("CopyFileName");
|
||||
copyFileName.Icon = App.CreateMenuIcon("Icons.Copy");
|
||||
copyFileName.Click += (_, e) =>
|
||||
{
|
||||
App.CopyText(Path.GetFileName(change.Path));
|
||||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(copyFileName);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private void RefreshVisible()
|
||||
{
|
||||
if (_changes == null)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(_searchFilter))
|
||||
{
|
||||
VisibleChanges = _changes;
|
||||
}
|
||||
else
|
||||
{
|
||||
var visible = new List<Models.Change>();
|
||||
foreach (var c in _changes)
|
||||
{
|
||||
if (c.Path.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))
|
||||
visible.Add(c);
|
||||
}
|
||||
|
||||
VisibleChanges = visible;
|
||||
}
|
||||
}
|
||||
|
||||
private string _repo = string.Empty;
|
||||
private Models.Commit _baseHead = null;
|
||||
private Models.Commit _toHead = null;
|
||||
private List<Models.Change> _changes = null;
|
||||
private List<Models.Change> _visibleChanges = null;
|
||||
private List<Models.Change> _selectedChanges = null;
|
||||
private string _searchFilter = string.Empty;
|
||||
private DiffContext _diffContext = null;
|
||||
}
|
||||
}
|
|
@ -385,6 +385,7 @@ namespace SourceGit.ViewModels
|
|||
FullMessage = string.Empty;
|
||||
VisibleChanges = null;
|
||||
SelectedChanges = null;
|
||||
ViewRevisionFileContent = null;
|
||||
|
||||
if (_commit == null)
|
||||
return;
|
||||
|
|
|
@ -4,10 +4,15 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
public class GitFlowFinish : Popup
|
||||
{
|
||||
public Models.Branch Branch => _branch;
|
||||
public bool IsFeature => _type == Models.GitFlowBranchType.Feature;
|
||||
public bool IsRelease => _type == Models.GitFlowBranchType.Release;
|
||||
public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix;
|
||||
public Models.Branch Branch
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = null;
|
||||
|
||||
public bool IsFeature => _type == "feature";
|
||||
public bool IsRelease => _type == "release";
|
||||
public bool IsHotfix => _type == "hotfix";
|
||||
|
||||
public bool KeepBranch
|
||||
{
|
||||
|
@ -15,11 +20,13 @@ namespace SourceGit.ViewModels
|
|||
set;
|
||||
} = false;
|
||||
|
||||
public GitFlowFinish(Repository repo, Models.Branch branch, Models.GitFlowBranchType type)
|
||||
public GitFlowFinish(Repository repo, Models.Branch branch, string type, string prefix)
|
||||
{
|
||||
_repo = repo;
|
||||
_branch = branch;
|
||||
_type = type;
|
||||
_prefix = prefix;
|
||||
|
||||
Branch = branch;
|
||||
View = new Views.GitFlowFinish() { DataContext = this };
|
||||
}
|
||||
|
||||
|
@ -28,29 +35,16 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var branch = _branch.Name;
|
||||
switch (_type)
|
||||
{
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
branch = branch.Substring(_repo.GitFlow.Feature.Length);
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
branch = branch.Substring(_repo.GitFlow.Release.Length);
|
||||
break;
|
||||
default:
|
||||
branch = branch.Substring(_repo.GitFlow.Hotfix.Length);
|
||||
break;
|
||||
}
|
||||
|
||||
SetProgressDescription($"Git Flow - finishing {_branch.Name} ...");
|
||||
var succ = new Commands.GitFlow(_repo.FullPath).Finish(_type, branch, KeepBranch);
|
||||
var name = Branch.Name.StartsWith(_prefix) ? Branch.Name.Substring(_prefix.Length) : Branch.Name;
|
||||
SetProgressDescription($"Git Flow - finishing {_type} {name} ...");
|
||||
var succ = Commands.GitFlow.Finish(_repo.FullPath, _type, name, KeepBranch);
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Repository _repo = null;
|
||||
private readonly Models.Branch _branch = null;
|
||||
private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.None;
|
||||
private readonly string _type = "feature";
|
||||
private readonly string _prefix = string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,27 +19,15 @@ namespace SourceGit.ViewModels
|
|||
get => _prefix;
|
||||
}
|
||||
|
||||
public bool IsFeature => _type == Models.GitFlowBranchType.Feature;
|
||||
public bool IsRelease => _type == Models.GitFlowBranchType.Release;
|
||||
public bool IsHotfix => _type == Models.GitFlowBranchType.Hotfix;
|
||||
public bool IsFeature => _type == "feature";
|
||||
public bool IsRelease => _type == "release";
|
||||
public bool IsHotfix => _type == "hotfix";
|
||||
|
||||
public GitFlowStart(Repository repo, Models.GitFlowBranchType type)
|
||||
public GitFlowStart(Repository repo, string type)
|
||||
{
|
||||
_repo = repo;
|
||||
_type = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Models.GitFlowBranchType.Feature:
|
||||
_prefix = repo.GitFlow.Feature;
|
||||
break;
|
||||
case Models.GitFlowBranchType.Release:
|
||||
_prefix = repo.GitFlow.Release;
|
||||
break;
|
||||
default:
|
||||
_prefix = repo.GitFlow.Hotfix;
|
||||
break;
|
||||
}
|
||||
_prefix = Commands.GitFlow.Prefix(repo.FullPath, type);
|
||||
|
||||
View = new Views.GitFlowStart() { DataContext = this };
|
||||
}
|
||||
|
@ -65,15 +53,15 @@ namespace SourceGit.ViewModels
|
|||
_repo.SetWatcherEnabled(false);
|
||||
return Task.Run(() =>
|
||||
{
|
||||
SetProgressDescription($"Git Flow - starting {_prefix}{_name} ...");
|
||||
var succ = new Commands.GitFlow(_repo.FullPath).Start(_type, _name);
|
||||
SetProgressDescription($"Git Flow - starting {_type} {_name} ...");
|
||||
var succ = Commands.GitFlow.Start(_repo.FullPath, _type, _name);
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Repository _repo = null;
|
||||
private readonly Models.GitFlowBranchType _type = Models.GitFlowBranchType.Feature;
|
||||
private readonly string _type = "feature";
|
||||
private readonly string _prefix = string.Empty;
|
||||
private string _name = null;
|
||||
}
|
||||
|
|
|
@ -209,17 +209,6 @@ namespace SourceGit.ViewModels
|
|||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(reset);
|
||||
|
||||
var checkoutCommit = new MenuItem();
|
||||
checkoutCommit.Header = App.Text("CommitCM.Checkout");
|
||||
checkoutCommit.Icon = App.CreateMenuIcon("Icons.Check");
|
||||
checkoutCommit.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new CheckoutCommit(_repo, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(checkoutCommit);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -290,6 +279,20 @@ namespace SourceGit.ViewModels
|
|||
menu.Items.Add(revert);
|
||||
}
|
||||
|
||||
if (current.Head != commit.SHA)
|
||||
{
|
||||
var checkoutCommit = new MenuItem();
|
||||
checkoutCommit.Header = App.Text("CommitCM.Checkout");
|
||||
checkoutCommit.Icon = App.CreateMenuIcon("Icons.Detached");
|
||||
checkoutCommit.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new CheckoutCommit(_repo, commit));
|
||||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(checkoutCommit);
|
||||
}
|
||||
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
||||
if (current.Head != commit.SHA)
|
||||
|
@ -448,8 +451,8 @@ namespace SourceGit.ViewModels
|
|||
submenu.Items.Add(push);
|
||||
submenu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
||||
var type = _repo.GitFlow.GetBranchType(current.Name);
|
||||
if (type != Models.GitFlowBranchType.None)
|
||||
var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name);
|
||||
if (detect.IsGitFlowBranch)
|
||||
{
|
||||
var finish = new MenuItem();
|
||||
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name);
|
||||
|
@ -457,7 +460,7 @@ namespace SourceGit.ViewModels
|
|||
finish.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new GitFlowFinish(_repo, current, type));
|
||||
PopupHost.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix));
|
||||
e.Handled = true;
|
||||
};
|
||||
submenu.Items.Add(finish);
|
||||
|
@ -507,8 +510,8 @@ namespace SourceGit.ViewModels
|
|||
submenu.Items.Add(merge);
|
||||
submenu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
||||
var type = _repo.GitFlow.GetBranchType(branch.Name);
|
||||
if (type != Models.GitFlowBranchType.None)
|
||||
var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name);
|
||||
if (detect.IsGitFlowBranch)
|
||||
{
|
||||
var finish = new MenuItem();
|
||||
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
|
||||
|
@ -516,7 +519,7 @@ namespace SourceGit.ViewModels
|
|||
finish.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, type));
|
||||
PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix));
|
||||
e.Handled = true;
|
||||
};
|
||||
submenu.Items.Add(finish);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -6,7 +7,6 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
public partial class InitGitFlow : Popup
|
||||
{
|
||||
|
||||
[GeneratedRegex(@"^[\w\-/\.]+$")]
|
||||
private static partial Regex TAG_PREFIX();
|
||||
|
||||
|
@ -62,6 +62,23 @@ namespace SourceGit.ViewModels
|
|||
public InitGitFlow(Repository repo)
|
||||
{
|
||||
_repo = repo;
|
||||
|
||||
var localBranches = new List<string>();
|
||||
foreach (var branch in repo.Branches)
|
||||
{
|
||||
if (branch.IsLocal)
|
||||
localBranches.Add(branch.Name);
|
||||
}
|
||||
|
||||
if (localBranches.Contains("master"))
|
||||
_master = "master";
|
||||
else if (localBranches.Contains("main"))
|
||||
_master = "main";
|
||||
else if (localBranches.Count > 0)
|
||||
_master = localBranches[0];
|
||||
else
|
||||
_master = "master";
|
||||
|
||||
View = new Views.InitGitFlow() { DataContext = this };
|
||||
}
|
||||
|
||||
|
@ -79,9 +96,7 @@ namespace SourceGit.ViewModels
|
|||
public static ValidationResult ValidateTagPrefix(string tagPrefix, ValidationContext ctx)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(tagPrefix) && !TAG_PREFIX().IsMatch(tagPrefix))
|
||||
{
|
||||
return new ValidationResult("Bad tag prefix format!");
|
||||
}
|
||||
|
||||
return ValidationResult.Success;
|
||||
}
|
||||
|
@ -93,14 +108,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var succ = new Commands.GitFlow(_repo.FullPath).Init(_repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix);
|
||||
if (succ)
|
||||
{
|
||||
_repo.GitFlow.Feature = _featurePrefix;
|
||||
_repo.GitFlow.Release = _releasePrefix;
|
||||
_repo.GitFlow.Hotfix = _hotfixPrefix;
|
||||
}
|
||||
|
||||
var succ = Commands.GitFlow.Init(_repo.FullPath, _repo.Branches, _master, _develop, _featurePrefix, _releasePrefix, _hotfixPrefix, _tagPrefix);
|
||||
CallUIThread(() => _repo.SetWatcherEnabled(true));
|
||||
return succ;
|
||||
});
|
||||
|
|
|
@ -136,6 +136,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
last.Node = new RepositoryNode() { Id = Guid.NewGuid().ToString() };
|
||||
last.Data = Welcome.Instance;
|
||||
last.Popup = null;
|
||||
|
||||
GC.Collect();
|
||||
}
|
||||
|
@ -188,6 +189,7 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
|
||||
Pages = new AvaloniaList<LauncherPage> { ActivePage };
|
||||
OnPropertyChanged(nameof(Pages));
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
|
|
86
src/ViewModels/LayoutInfo.cs
Normal file
86
src/ViewModels/LayoutInfo.cs
Normal file
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using Avalonia.Controls;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
{
|
||||
public class LayoutInfo : ObservableObject
|
||||
{
|
||||
public double LauncherWidth
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = 1280;
|
||||
|
||||
public double LauncherHeight
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = 720;
|
||||
|
||||
public WindowState LauncherWindowState
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = WindowState.Normal;
|
||||
|
||||
[JsonConverter(typeof(GridLengthConverter))]
|
||||
public GridLength RepositorySidebarWidth
|
||||
{
|
||||
get => _repositorySidebarWidth;
|
||||
set => SetProperty(ref _repositorySidebarWidth, value);
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(GridLengthConverter))]
|
||||
public GridLength WorkingCopyLeftWidth
|
||||
{
|
||||
get => _workingCopyLeftWidth;
|
||||
set => SetProperty(ref _workingCopyLeftWidth, value);
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(GridLengthConverter))]
|
||||
public GridLength StashesLeftWidth
|
||||
{
|
||||
get => _stashesLeftWidth;
|
||||
set => SetProperty(ref _stashesLeftWidth, value);
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(GridLengthConverter))]
|
||||
public GridLength CommitDetailChangesLeftWidth
|
||||
{
|
||||
get => _commitDetailChangesLeftWidth;
|
||||
set => SetProperty(ref _commitDetailChangesLeftWidth, value);
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(GridLengthConverter))]
|
||||
public GridLength CommitDetailFilesLeftWidth
|
||||
{
|
||||
get => _commitDetailFilesLeftWidth;
|
||||
set => SetProperty(ref _commitDetailFilesLeftWidth, value);
|
||||
}
|
||||
|
||||
private GridLength _repositorySidebarWidth = new GridLength(250, GridUnitType.Pixel);
|
||||
private GridLength _workingCopyLeftWidth = new GridLength(300, GridUnitType.Pixel);
|
||||
private GridLength _stashesLeftWidth = new GridLength(300, GridUnitType.Pixel);
|
||||
private GridLength _commitDetailChangesLeftWidth = new GridLength(256, GridUnitType.Pixel);
|
||||
private GridLength _commitDetailFilesLeftWidth = new GridLength(256, GridUnitType.Pixel);
|
||||
}
|
||||
|
||||
public class GridLengthConverter : JsonConverter<GridLength>
|
||||
{
|
||||
public override GridLength Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var size = reader.GetDouble();
|
||||
return new GridLength(size, GridUnitType.Pixel);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, GridLength value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteNumberValue(value.Value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,6 +109,12 @@ namespace SourceGit.ViewModels
|
|||
set => SetProperty(ref _defaultFontSize, value);
|
||||
}
|
||||
|
||||
public LayoutInfo Layout
|
||||
{
|
||||
get => _layout;
|
||||
set => SetProperty(ref _layout, value);
|
||||
}
|
||||
|
||||
public string AvatarServer
|
||||
{
|
||||
get => Models.AvatarManager.SelectedServer;
|
||||
|
@ -531,6 +537,7 @@ namespace SourceGit.ViewModels
|
|||
private FontFamily _defaultFont = null;
|
||||
private FontFamily _monospaceFont = null;
|
||||
private double _defaultFontSize = 13;
|
||||
private LayoutInfo _layout = new LayoutInfo();
|
||||
|
||||
private int _maxHistoryCommits = 20000;
|
||||
private bool _restoreTabs = false;
|
||||
|
|
|
@ -51,13 +51,6 @@ namespace SourceGit.ViewModels
|
|||
set;
|
||||
} = new AvaloniaList<string>();
|
||||
|
||||
[JsonIgnore]
|
||||
public Models.GitFlow GitFlow
|
||||
{
|
||||
get => _gitflow;
|
||||
set => SetProperty(ref _gitflow, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int SelectedViewIndex
|
||||
{
|
||||
|
@ -298,7 +291,6 @@ namespace SourceGit.ViewModels
|
|||
Task.Run(RefreshSubmodules);
|
||||
Task.Run(RefreshWorkingCopyChanges);
|
||||
Task.Run(RefreshStashes);
|
||||
Task.Run(RefreshGitFlow);
|
||||
}
|
||||
|
||||
public void OpenInFileManager()
|
||||
|
@ -697,22 +689,6 @@ namespace SourceGit.ViewModels
|
|||
});
|
||||
}
|
||||
|
||||
public void RefreshGitFlow()
|
||||
{
|
||||
var config = new Commands.Config(_fullpath).ListAll();
|
||||
var gitFlow = new Models.GitFlow();
|
||||
if (config.TryGetValue("gitflow.prefix.feature", out var feature))
|
||||
gitFlow.Feature = feature;
|
||||
if (config.TryGetValue("gitflow.prefix.release", out var release))
|
||||
gitFlow.Release = release;
|
||||
if (config.TryGetValue("gitflow.prefix.hotfix", out var hotfix))
|
||||
gitFlow.Hotfix = hotfix;
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
GitFlow = gitFlow;
|
||||
});
|
||||
}
|
||||
|
||||
public void CreateNewBranch()
|
||||
{
|
||||
var current = Branches.Find(x => x.IsCurrent);
|
||||
|
@ -797,7 +773,8 @@ namespace SourceGit.ViewModels
|
|||
var menu = new ContextMenu();
|
||||
menu.Placement = PlacementMode.BottomEdgeAlignedLeft;
|
||||
|
||||
if (GitFlow.IsEnabled)
|
||||
var isGitFlowEnabled = Commands.GitFlow.IsEnabled(_fullpath, _branches);
|
||||
if (isGitFlowEnabled)
|
||||
{
|
||||
var startFeature = new MenuItem();
|
||||
startFeature.Header = App.Text("GitFlow.StartFeature");
|
||||
|
@ -805,7 +782,7 @@ namespace SourceGit.ViewModels
|
|||
startFeature.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Feature));
|
||||
PopupHost.ShowPopup(new GitFlowStart(this, "feature"));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -815,7 +792,7 @@ namespace SourceGit.ViewModels
|
|||
startRelease.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Release));
|
||||
PopupHost.ShowPopup(new GitFlowStart(this, "release"));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -825,7 +802,7 @@ namespace SourceGit.ViewModels
|
|||
startHotfix.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new GitFlowStart(this, Models.GitFlowBranchType.Hotfix));
|
||||
PopupHost.ShowPopup(new GitFlowStart(this, "hotfix"));
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -909,6 +886,13 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
|
||||
menu.Items.Add(push);
|
||||
|
||||
var compareWithBranch = CreateMenuItemToCompareBranches(branch);
|
||||
if (compareWithBranch != null)
|
||||
{
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(compareWithBranch);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -968,24 +952,6 @@ namespace SourceGit.ViewModels
|
|||
menu.Items.Add(merge);
|
||||
menu.Items.Add(rebase);
|
||||
|
||||
var compare = new MenuItem();
|
||||
compare.Header = App.Text("BranchCM.CompareWithHead");
|
||||
compare.Icon = App.CreateMenuIcon("Icons.Compare");
|
||||
compare.Click += (o, e) =>
|
||||
{
|
||||
SearchResultSelectedCommit = null;
|
||||
|
||||
if (_histories != null)
|
||||
{
|
||||
var target = new Commands.QuerySingleCommit(FullPath, branch.Head).Result();
|
||||
var head = new Commands.QuerySingleCommit(FullPath, current.Head).Result();
|
||||
_histories.AutoSelectedCommit = null;
|
||||
_histories.DetailContext = new RevisionCompare(FullPath, target, head);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
if (WorkingCopyChangesCount > 0)
|
||||
{
|
||||
var compareWithWorktree = new MenuItem();
|
||||
|
@ -1002,15 +968,22 @@ namespace SourceGit.ViewModels
|
|||
_histories.DetailContext = new RevisionCompare(FullPath, target, null);
|
||||
}
|
||||
};
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(compareWithWorktree);
|
||||
}
|
||||
|
||||
var compareWithBranch = CreateMenuItemToCompareBranches(branch);
|
||||
if (compareWithBranch != null)
|
||||
{
|
||||
if (WorkingCopyChangesCount == 0)
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(compare);
|
||||
|
||||
menu.Items.Add(compareWithBranch);
|
||||
}
|
||||
}
|
||||
|
||||
var type = GitFlow.GetBranchType(branch.Name);
|
||||
if (type != Models.GitFlowBranchType.None)
|
||||
var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name);
|
||||
if (detect.IsGitFlowBranch)
|
||||
{
|
||||
var finish = new MenuItem();
|
||||
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
|
||||
|
@ -1018,7 +991,7 @@ namespace SourceGit.ViewModels
|
|||
finish.Click += (o, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
PopupHost.ShowPopup(new GitFlowFinish(this, branch, type));
|
||||
PopupHost.ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix));
|
||||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
@ -1263,28 +1236,9 @@ namespace SourceGit.ViewModels
|
|||
menu.Items.Add(merge);
|
||||
menu.Items.Add(rebase);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
||||
if (current.Head != branch.Head)
|
||||
{
|
||||
var compare = new MenuItem();
|
||||
compare.Header = App.Text("BranchCM.CompareWithHead");
|
||||
compare.Icon = App.CreateMenuIcon("Icons.Compare");
|
||||
compare.Click += (o, e) =>
|
||||
{
|
||||
SearchResultSelectedCommit = null;
|
||||
|
||||
if (_histories != null)
|
||||
{
|
||||
var target = new Commands.QuerySingleCommit(FullPath, branch.Head).Result();
|
||||
var head = new Commands.QuerySingleCommit(FullPath, current.Head).Result();
|
||||
_histories.AutoSelectedCommit = null;
|
||||
_histories.DetailContext = new RevisionCompare(FullPath, target, head);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
};
|
||||
menu.Items.Add(compare);
|
||||
|
||||
var hasCompare = false;
|
||||
if (WorkingCopyChangesCount > 0)
|
||||
{
|
||||
var compareWithWorktree = new MenuItem();
|
||||
|
@ -1302,11 +1256,18 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
};
|
||||
menu.Items.Add(compareWithWorktree);
|
||||
hasCompare = true;
|
||||
}
|
||||
|
||||
var compareWithBranch = CreateMenuItemToCompareBranches(branch);
|
||||
if (compareWithBranch != null)
|
||||
{
|
||||
menu.Items.Add(compareWithBranch);
|
||||
hasCompare = true;
|
||||
}
|
||||
|
||||
if (hasCompare)
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
}
|
||||
}
|
||||
|
||||
var delete = new MenuItem();
|
||||
delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", $"{branch.Remote}/{branch.Name}");
|
||||
|
@ -1485,6 +1446,41 @@ namespace SourceGit.ViewModels
|
|||
return menu;
|
||||
}
|
||||
|
||||
private MenuItem CreateMenuItemToCompareBranches(Models.Branch branch)
|
||||
{
|
||||
if (Branches.Count == 1)
|
||||
return null;
|
||||
|
||||
var compare = new MenuItem();
|
||||
compare.Header = App.Text("BranchCM.CompareWithBranch");
|
||||
compare.Icon = App.CreateMenuIcon("Icons.Compare");
|
||||
|
||||
foreach (var b in Branches)
|
||||
{
|
||||
if (b.FullName != branch.FullName)
|
||||
{
|
||||
var dup = b;
|
||||
var target = new MenuItem();
|
||||
target.Header = b.IsLocal ? b.Name : $"{b.Remote}/{b.Name}";
|
||||
target.Icon = App.CreateMenuIcon(b.IsCurrent ? "Icons.Check" : "Icons.Branch");
|
||||
target.Click += (_, e) =>
|
||||
{
|
||||
var wnd = new Views.BranchCompare()
|
||||
{
|
||||
DataContext = new BranchCompare(FullPath, branch, dup)
|
||||
};
|
||||
|
||||
wnd.Show(App.GetTopLevel() as Window);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
compare.Items.Add(target);
|
||||
}
|
||||
}
|
||||
|
||||
return compare;
|
||||
}
|
||||
|
||||
private BranchTreeNode.Builder BuildBranchTree(List<Models.Branch> branches, List<Models.Remote> remotes)
|
||||
{
|
||||
var builder = new BranchTreeNode.Builder();
|
||||
|
@ -1513,7 +1509,6 @@ namespace SourceGit.ViewModels
|
|||
|
||||
private string _fullpath = string.Empty;
|
||||
private string _gitDir = string.Empty;
|
||||
private Models.GitFlow _gitflow = new Models.GitFlow();
|
||||
|
||||
private Models.Watcher _watcher = null;
|
||||
private Histories _histories = null;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using Avalonia;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace SourceGit.ViewModels
|
||||
|
@ -11,7 +11,13 @@ namespace SourceGit.ViewModels
|
|||
public List<Models.TextDiffLine> New { get; set; } = new List<Models.TextDiffLine>();
|
||||
public int MaxLineNumber = 0;
|
||||
|
||||
public TwoSideTextDiff(Models.TextDiff diff)
|
||||
public Vector SyncScrollOffset
|
||||
{
|
||||
get => _syncScrollOffset;
|
||||
set => SetProperty(ref _syncScrollOffset, value);
|
||||
}
|
||||
|
||||
public TwoSideTextDiff(Models.TextDiff diff, TwoSideTextDiff previous = null)
|
||||
{
|
||||
File = diff.File;
|
||||
MaxLineNumber = diff.MaxLineNumber;
|
||||
|
@ -35,6 +41,9 @@ namespace SourceGit.ViewModels
|
|||
}
|
||||
|
||||
FillEmptyLines();
|
||||
|
||||
if (previous != null && previous.File == File)
|
||||
_syncScrollOffset = previous._syncScrollOffset;
|
||||
}
|
||||
|
||||
private void FillEmptyLines()
|
||||
|
@ -52,5 +61,7 @@ namespace SourceGit.ViewModels
|
|||
New.Add(new Models.TextDiffLine());
|
||||
}
|
||||
}
|
||||
|
||||
private Vector _syncScrollOffset = Vector.Zero;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -379,27 +379,19 @@ namespace SourceGit.ViewModels
|
|||
if (isUnstaged)
|
||||
{
|
||||
if (changes.Count == _unstaged.Count && _staged.Count == 0)
|
||||
{
|
||||
PopupHost.ShowPopup(new Discard(_repo));
|
||||
}
|
||||
else
|
||||
{
|
||||
PopupHost.ShowPopup(new Discard(_repo, changes, true));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (changes.Count == _staged.Count && _unstaged.Count == 0)
|
||||
{
|
||||
PopupHost.ShowPopup(new Discard(_repo));
|
||||
}
|
||||
else
|
||||
{
|
||||
PopupHost.ShowPopup(new Discard(_repo, changes, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
|
@ -413,7 +405,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
public ContextMenu CreateContextMenuForUnstagedChanges()
|
||||
{
|
||||
if (_selectedUnstaged.Count == 0)
|
||||
if (_selectedUnstaged == null || _selectedUnstaged.Count == 0)
|
||||
return null;
|
||||
|
||||
var menu = new ContextMenu();
|
||||
|
@ -536,6 +528,16 @@ namespace SourceGit.ViewModels
|
|||
e.Handled = true;
|
||||
};
|
||||
|
||||
var assumeUnchanged = new MenuItem();
|
||||
assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged");
|
||||
assumeUnchanged.Icon = App.CreateMenuIcon("Icons.File.Ignore");
|
||||
assumeUnchanged.IsVisible = change.WorkTree != Models.ChangeState.Untracked;
|
||||
assumeUnchanged.Click += (_, e) =>
|
||||
{
|
||||
new Commands.AssumeUnchanged(_repo.FullPath).Add(change.Path);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
var history = new MenuItem();
|
||||
history.Header = App.Text("FileHistory");
|
||||
history.Icon = App.CreateMenuIcon("Icons.Histories");
|
||||
|
@ -546,24 +548,67 @@ namespace SourceGit.ViewModels
|
|||
e.Handled = true;
|
||||
};
|
||||
|
||||
var assumeUnchanged = new MenuItem();
|
||||
assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged");
|
||||
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);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
menu.Items.Add(stage);
|
||||
menu.Items.Add(discard);
|
||||
menu.Items.Add(stash);
|
||||
menu.Items.Add(patch);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(history);
|
||||
menu.Items.Add(assumeUnchanged);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
menu.Items.Add(history);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
|
||||
if (change.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
var isRooted = change.Path.IndexOf('/', StringComparison.Ordinal) <= 0;
|
||||
var addToIgnore = new MenuItem();
|
||||
addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore");
|
||||
addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore");
|
||||
|
||||
var singleFile = new MenuItem();
|
||||
singleFile.Header = App.Text("WorkingCopy.AddToGitIgnore.SingleFile");
|
||||
singleFile.Click += (_, e) =>
|
||||
{
|
||||
Commands.GitIgnore.Add(_repo.FullPath, change.Path);
|
||||
e.Handled = true;
|
||||
};
|
||||
addToIgnore.Items.Add(singleFile);
|
||||
|
||||
var byParentFolder = new MenuItem();
|
||||
byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder");
|
||||
byParentFolder.IsVisible = !isRooted;
|
||||
byParentFolder.Click += (_, e) =>
|
||||
{
|
||||
Commands.GitIgnore.Add(_repo.FullPath, Path.GetDirectoryName(change.Path) + "/");
|
||||
e.Handled = true;
|
||||
};
|
||||
addToIgnore.Items.Add(byParentFolder);
|
||||
|
||||
var extension = Path.GetExtension(change.Path);
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
var byExtension = new MenuItem();
|
||||
byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension);
|
||||
byExtension.Click += (_, e) =>
|
||||
{
|
||||
Commands.GitIgnore.Add(_repo.FullPath, "*" + extension);
|
||||
e.Handled = true;
|
||||
};
|
||||
addToIgnore.Items.Add(byExtension);
|
||||
|
||||
var byExtensionInSameFolder = new MenuItem();
|
||||
byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension);
|
||||
byExtensionInSameFolder.IsVisible = !isRooted;
|
||||
byExtensionInSameFolder.Click += (_, e) =>
|
||||
{
|
||||
Commands.GitIgnore.Add(_repo.FullPath, Path.GetDirectoryName(change.Path) + "/*" + extension);
|
||||
e.Handled = true;
|
||||
};
|
||||
addToIgnore.Items.Add(byExtensionInSameFolder);
|
||||
}
|
||||
|
||||
menu.Items.Add(addToIgnore);
|
||||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
}
|
||||
}
|
||||
|
||||
var copy = new MenuItem();
|
||||
|
@ -699,7 +744,7 @@ namespace SourceGit.ViewModels
|
|||
|
||||
public ContextMenu CreateContextMenuForStagedChanges()
|
||||
{
|
||||
if (_selectedStaged.Count == 0)
|
||||
if (_selectedStaged == null || _selectedStaged.Count == 0)
|
||||
return null;
|
||||
|
||||
var menu = new ContextMenu();
|
||||
|
@ -921,24 +966,11 @@ namespace SourceGit.ViewModels
|
|||
|
||||
var isUnstaged = _selectedUnstaged != null && _selectedUnstaged.Count > 0;
|
||||
if (change == null)
|
||||
{
|
||||
DetailContext = null;
|
||||
}
|
||||
else if (change.IsConflit && isUnstaged)
|
||||
{
|
||||
DetailContext = new ConflictContext(_repo.FullPath, change);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_detailContext is DiffContext previous)
|
||||
{
|
||||
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), previous);
|
||||
}
|
||||
else
|
||||
{
|
||||
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged));
|
||||
}
|
||||
}
|
||||
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext);
|
||||
}
|
||||
|
||||
private async void UseTheirs(List<Models.Change> changes)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -9,20 +9,10 @@
|
|||
x:DataType="v:About"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.About}"
|
||||
Background="Transparent"
|
||||
SizeToContent="WidthAndHeight"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
|
@ -59,7 +49,7 @@
|
|||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*" Background="{DynamicResource Brush.Window}">
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
|
||||
<Image Grid.Column="0"
|
||||
Width="200" Height="200"
|
||||
Margin="8,0"
|
||||
|
@ -100,4 +90,4 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
using System.Reflection;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class About : Window
|
||||
public partial class About : ChromelessWindow
|
||||
{
|
||||
public string Version
|
||||
{
|
||||
|
|
|
@ -28,11 +28,11 @@
|
|||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Tag">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -10,20 +10,10 @@
|
|||
x:DataType="vm:AssumeUnchangedManager"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.AssumeUnchanged}"
|
||||
Background="Transparent"
|
||||
Width="600" Height="400"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
|
@ -61,7 +51,7 @@
|
|||
</Grid>
|
||||
|
||||
<!-- Unchanged Files -->
|
||||
<Grid Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<Grid Grid.Row="1">
|
||||
<DataGrid Margin="8"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
ItemsSource="{Binding Files}"
|
||||
|
@ -110,4 +100,4 @@
|
|||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -4,7 +4,7 @@ using Avalonia.Interactivity;
|
|||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class AssumeUnchangedManager : Window
|
||||
public partial class AssumeUnchangedManager : ChromelessWindow
|
||||
{
|
||||
public AssumeUnchangedManager()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -12,25 +12,15 @@
|
|||
x:DataType="vm:Blame"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.Blame}"
|
||||
Background="Transparent"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid Margin="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToContentMargin}}">
|
||||
MinWidth="1280" MinHeight="720">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
|
@ -38,7 +28,9 @@
|
|||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
PointerPressed="BeginMoveWindow"
|
||||
PointerMoved="MoveWindow"
|
||||
PointerReleased="EndMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
|
@ -58,12 +50,12 @@
|
|||
</Grid>
|
||||
|
||||
<!-- File -->
|
||||
<Border Grid.Row="1" Padding="8,0" Background="{DynamicResource Brush.Window}">
|
||||
<Border Grid.Row="1" Padding="8,0">
|
||||
<TextBlock Text="{Binding Title}" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Row="2" Background="{DynamicResource Brush.Window}">
|
||||
<Grid Grid.Row="2">
|
||||
<!-- Blame View -->
|
||||
<v:BlameTextEditor HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
|
@ -86,64 +78,5 @@
|
|||
<!-- Loading -->
|
||||
<v:LoadingIcon Width="48" Height="48" IsVisible="{Binding Data, Converter={x:Static ObjectConverters.IsNull}}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Custom window sizer for Linux -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="3" IsVisible="{OnPlatform False, Linux=True}" IsHitTestVisible="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.IsNormal}}">
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -319,7 +319,7 @@ namespace SourceGit.Views
|
|||
private TextMate.Installation _textMate = null;
|
||||
}
|
||||
|
||||
public partial class Blame : Window
|
||||
public partial class Blame : ChromelessWindow
|
||||
{
|
||||
public Blame()
|
||||
{
|
||||
|
@ -333,31 +333,41 @@ namespace SourceGit.Views
|
|||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
_pressedTitleBar = false;
|
||||
|
||||
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
if (border.Tag is WindowEdge edge)
|
||||
{
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
if (WindowState == WindowState.Maximized)
|
||||
WindowState = WindowState.Normal;
|
||||
else
|
||||
WindowState = WindowState.Maximized;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
if (e.ClickCount != 2)
|
||||
_pressedTitleBar = true;
|
||||
}
|
||||
|
||||
private void MoveWindow(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (!_pressedTitleBar)
|
||||
return;
|
||||
|
||||
var visual = (Visual)e.Source;
|
||||
BeginMoveDrag(new PointerPressedEventArgs(
|
||||
e.Source,
|
||||
e.Pointer,
|
||||
visual,
|
||||
e.GetPosition(visual),
|
||||
e.Timestamp,
|
||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
|
||||
e.KeyModifiers));
|
||||
}
|
||||
|
||||
private void EndMoveWindow(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
_pressedTitleBar = false;
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
|
@ -375,5 +385,7 @@ namespace SourceGit.Views
|
|||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private bool _pressedTitleBar = false;
|
||||
}
|
||||
}
|
||||
|
|
173
src/Views/BranchCompare.axaml
Normal file
173
src/Views/BranchCompare.axaml
Normal file
|
@ -0,0 +1,173 @@
|
|||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.BranchCompare"
|
||||
x:DataType="vm:BranchCompare"
|
||||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.BranchCompare}"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="64"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="4"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"
|
||||
PointerMoved="MoveWindow"
|
||||
PointerReleased="EndMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
<v:CaptionButtonsMacOS/>
|
||||
</Border>
|
||||
|
||||
<!-- Icon -->
|
||||
<Path Grid.Column="1" Margin="8,0,0,0" Width="12" Height="12" Data="{StaticResource Icons.Compare}"/>
|
||||
|
||||
<!-- Title -->
|
||||
<TextBlock Grid.Column="2" Margin="8,0,0,0" Text="{DynamicResource Text.BranchCompare}" FontWeight="Bold" IsHitTestVisible="False" VerticalAlignment="Center"/>
|
||||
|
||||
<!-- Caption Buttons (Windows/Linux) -->
|
||||
<Border Grid.Column="3" IsVisible="{OnPlatform True, macOS=False}">
|
||||
<v:CaptionButtons/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Compare Targets -->
|
||||
<Border Grid.Row="1">
|
||||
<Grid Margin="48,8,48,8" ColumnDefinitions="*,48,*">
|
||||
<Border Grid.Column="0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}" CornerRadius="4" Padding="4">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
|
||||
<v:Avatar Width="16" Height="16"
|
||||
VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"
|
||||
User="{Binding BaseHead.Author}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding BaseHead.Author.Name}" Margin="8,0,0,0"/>
|
||||
<Border Grid.Column="2" Background="{DynamicResource Brush.Accent}" CornerRadius="4">
|
||||
<TextBlock Text="{Binding Base, Converter={x:Static c:BranchConverters.ToName}}" Classes="monospace" Margin="4,0" Foreground="#FFDDDDDD"/>
|
||||
</Border>
|
||||
<TextBlock Grid.Column="3" Classes="monospace" Text="{Binding BaseHead.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" PointerPressed="OnPressedSHA"/>
|
||||
<TextBlock Grid.Column="4" Classes="monospace" Text="{Binding BaseHead.CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Classes="monospace" Text="{Binding BaseHead.Subject}" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Path Grid.Column="1" Width="16" Height="16" Fill="{DynamicResource Brush.FG2}" Data="{DynamicResource Icons.Down}" RenderTransformOrigin="50%,50%" RenderTransform="rotate(270deg)"/>
|
||||
|
||||
<Border Grid.Column="2" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}" CornerRadius="4" Padding="4">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
|
||||
<v:Avatar Width="16" Height="16"
|
||||
VerticalAlignment="Center"
|
||||
IsHitTestVisible="False"
|
||||
User="{Binding ToHead.Author}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding ToHead.Author.Name}" Margin="8,0,0,0"/>
|
||||
<Border Grid.Column="2" Background="{DynamicResource Brush.Accent}" CornerRadius="4">
|
||||
<TextBlock Text="{Binding To, Converter={x:Static c:BranchConverters.ToName}}" Classes="monospace" Margin="4,0" Foreground="#FFDDDDDD"/>
|
||||
</Border>
|
||||
<TextBlock Grid.Column="3" Classes="monospace" Text="{Binding ToHead.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0" TextDecorations="Underline" PointerPressed="OnPressedSHA"/>
|
||||
<TextBlock Grid.Column="4" Classes="monospace" Text="{Binding ToHead.CommitterTimeStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Classes="monospace" Text="{Binding ToHead.Subject}" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Changes -->
|
||||
<Border Grid.Row="2">
|
||||
<Grid Margin="8,0,8,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="256" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0" RowDefinitions="26,*">
|
||||
<!-- Search & Display Mode -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="*,18">
|
||||
<TextBox Grid.Column="0"
|
||||
Height="26"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
|
||||
Background="Transparent"
|
||||
CornerRadius="4"
|
||||
Watermark="{DynamicResource Text.CommitDetail.Changes.Search}"
|
||||
Text="{Binding SearchFilter, Mode=TwoWay}">
|
||||
<TextBox.InnerLeftContent>
|
||||
<Path Width="14" Height="14" Margin="4,0,0,0" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Search}"/>
|
||||
</TextBox.InnerLeftContent>
|
||||
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button"
|
||||
IsVisible="{Binding SearchFilter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Command="{Binding ClearSearchFilter}">
|
||||
<Path Width="14" Height="14" Fill="{DynamicResource Brush.FG2}" Data="{StaticResource Icons.Clear}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
|
||||
<v:ChangeViewModeSwitcher Grid.Column="1"
|
||||
Width="14" Height="14"
|
||||
HorizontalAlignment="Right"
|
||||
ViewMode="{Binding Source={x:Static vm:Preference.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Changes -->
|
||||
<Border Grid.Row="1" Margin="0,4,0,0" BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="1" Background="{DynamicResource Brush.Contents}">
|
||||
<v:ChangeCollectionView IsWorkingCopyChange="False"
|
||||
ViewMode="{Binding Source={x:Static vm:Preference.Instance}, Path=CommitChangeViewMode}"
|
||||
Changes="{Binding VisibleChanges}"
|
||||
SelectedChanges="{Binding SelectedChanges, Mode=TwoWay}"
|
||||
ContextRequested="OnChangeContextRequested"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<GridSplitter Grid.Column="1"
|
||||
MinWidth="1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
Background="Transparent"/>
|
||||
|
||||
<Grid Grid.Column="2">
|
||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
|
||||
<Path Width="64" Height="64" Data="{StaticResource Icons.Diff}" Fill="{DynamicResource Brush.FG2}"/>
|
||||
<TextBlock Margin="0,16,0,0"
|
||||
Text="{DynamicResource Text.Diff.Welcome}"
|
||||
FontSize="18" FontWeight="Bold"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<ContentControl Content="{Binding DiffContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:DiffContext">
|
||||
<v:DiffView/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</v:ChromelessWindow>
|
74
src/Views/BranchCompare.axaml.cs
Normal file
74
src/Views/BranchCompare.axaml.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class BranchCompare : ChromelessWindow
|
||||
{
|
||||
public BranchCompare()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
{
|
||||
_pressedTitleBar = false;
|
||||
|
||||
if (WindowState == WindowState.Maximized)
|
||||
WindowState = WindowState.Normal;
|
||||
else
|
||||
WindowState = WindowState.Maximized;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.ClickCount != 2)
|
||||
_pressedTitleBar = true;
|
||||
}
|
||||
|
||||
private void MoveWindow(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (!_pressedTitleBar)
|
||||
return;
|
||||
|
||||
var visual = (Visual)e.Source;
|
||||
BeginMoveDrag(new PointerPressedEventArgs(
|
||||
e.Source,
|
||||
e.Pointer,
|
||||
visual,
|
||||
e.GetPosition(visual),
|
||||
e.Timestamp,
|
||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
|
||||
e.KeyModifiers));
|
||||
}
|
||||
|
||||
private void EndMoveWindow(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
_pressedTitleBar = false;
|
||||
}
|
||||
|
||||
private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.BranchCompare vm && sender is ChangeCollectionView view)
|
||||
{
|
||||
var menu = vm.CreateChangeContextMenu();
|
||||
view.OpenContextMenu(menu);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnPressedSHA(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.BranchCompare vm && sender is TextBlock block)
|
||||
vm.NavigateTo(block.Text);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private bool _pressedTitleBar = false;
|
||||
}
|
||||
}
|
|
@ -12,22 +12,24 @@
|
|||
Classes="bold"
|
||||
Text="{DynamicResource Text.Checkout.Commit}" />
|
||||
|
||||
<TextBlock Margin="0,8,0,16"
|
||||
<StackPanel Orientation="Horizontal" Margin="0,12,0,16">
|
||||
<Path Width="14" Height="14" Data="{StaticResource Icons.Error}" Fill="DarkOrange"/>
|
||||
<TextBlock Margin="4,0,0,0"
|
||||
Text="{DynamicResource Text.Checkout.Commit.Warning}"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
FontStyle="Italic"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid RowDefinitions="32,Auto" ColumnDefinitions="Auto,*" ClipToBounds="True">
|
||||
<Grid RowDefinitions="32,Auto" ColumnDefinitions="Auto,*" ClipToBounds="True" HorizontalAlignment="Center">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Checkout.Commit.Target}" />
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}" />
|
||||
<TextBlock Classes="monospace" Foreground="DarkOrange" VerticalAlignment="Center" Margin="8,0" Text="{Binding Commit.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" />
|
||||
<TextBlock Text="{Binding Commit.Subject}"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="0" Grid.Column="1" ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}" />
|
||||
<TextBlock Grid.Column="1" Classes="monospace" Foreground="DarkOrange" VerticalAlignment="Center" Margin="8,0" Text="{Binding Commit.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" />
|
||||
<TextBlock Grid.Column="2" Text="{Binding Commit.Subject}" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.CherryPick}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.CherryPick.Commit}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding Target.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Target.Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Column="1" ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" VerticalAlignment="Center" Text="{Binding Target.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Target.Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1"
|
||||
Content="{DynamicResource Text.CherryPick.CommitChanges}"
|
||||
|
|
56
src/Views/ChromelessWindow.cs
Normal file
56
src/Views/ChromelessWindow.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class ChromelessWindow : Window
|
||||
{
|
||||
protected override Type StyleKeyOverride => typeof(Window);
|
||||
|
||||
public ChromelessWindow()
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
Classes.Add("custom_window_frame");
|
||||
else if (OperatingSystem.IsWindows())
|
||||
Classes.Add("fix_maximized_padding");
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
if (Classes.Contains("custom_window_frame") && CanResize)
|
||||
{
|
||||
string[] borderNames = [
|
||||
"PART_BorderTopLeft",
|
||||
"PART_BorderTop",
|
||||
"PART_BorderTopRight",
|
||||
"PART_BorderLeft",
|
||||
"PART_BorderRight",
|
||||
"PART_BorderBottomLeft",
|
||||
"PART_BorderBottom",
|
||||
"PART_BorderBottomRight",
|
||||
];
|
||||
|
||||
foreach (var name in borderNames)
|
||||
{
|
||||
var border = e.NameScope.Find<Border>(name);
|
||||
if (border != null)
|
||||
{
|
||||
border.PointerPressed -= OnWindowBorderPointerPressed;
|
||||
border.PointerPressed += OnWindowBorderPointerPressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWindowBorderPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border && border.Tag is WindowEdge edge && CanResize)
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,46 +10,71 @@
|
|||
<StackPanel Orientation="Vertical" Margin="8,0,0,0">
|
||||
<TextBlock Classes="bold" FontSize="18" Text="{DynamicResource Text.Clone}"/>
|
||||
|
||||
<Grid Margin="8,16,0,0" Height="28" ColumnDefinitions="140,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.RemoteURL}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Text="{Binding Remote, Mode=TwoWay}" v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="140,*" IsVisible="{Binding UseSSH}">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.SSHKey}"/>
|
||||
<TextBox Grid.Column="1"
|
||||
<Grid Margin="8,16,0,0" RowDefinitions="32,Auto,32,32,32" ColumnDefinitions="Auto,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Clone.RemoteURL}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding Remote, Mode=TwoWay}"
|
||||
v:AutoFocusBehaviour.IsEnabled="True"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.SSHKey}"
|
||||
IsVisible="{Binding UseSSH}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
x:Name="TxtSshKey"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Watermark="{DynamicResource Text.SSHKey.Placeholder}"
|
||||
Text="{Binding SSHKey, Mode=TwoWay}">
|
||||
Text="{Binding SSHKey, Mode=TwoWay}"
|
||||
IsVisible="{Binding UseSSH}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Click="SelectSSHKey">
|
||||
<Button Classes="icon_button" Width="28" Height="28" Click="SelectSSHKey">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="140,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.ParentFolder}"/>
|
||||
<TextBox Grid.Column="1"
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Clone.ParentFolder}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1"
|
||||
x:Name="TxtParentFolder"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Text="{Binding ParentFolder, Mode=TwoWay}">
|
||||
<TextBox.InnerRightContent>
|
||||
<Button Classes="icon_button" Width="30" Height="30" Margin="4,0,0,0" Click="SelectParentFolder">
|
||||
<Button Classes="icon_button" Width="28" Height="28" Margin="4,0,0,0" Click="SelectParentFolder">
|
||||
<Path Data="{StaticResource Icons.Folder.Open}" Fill="{DynamicResource Brush.FG1}"/>
|
||||
</Button>
|
||||
</TextBox.InnerRightContent>
|
||||
</TextBox>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="140,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.LocalName}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Watermark="{DynamicResource Text.Clone.LocalName.Placeholder}" Text="{Binding Local, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
<Grid Margin="8,4,0,0" Height="28" ColumnDefinitions="140,*">
|
||||
<TextBlock Grid.Column="0" HorizontalAlignment="Right" Margin="0,0,8,0" Text="{DynamicResource Text.Clone.AdditionalParam}"/>
|
||||
<TextBox Grid.Column="1" CornerRadius="3" Watermark="{DynamicResource Text.Clone.AdditionalParam.Placeholder}" Text="{Binding ExtraArgs, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Clone.LocalName}"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Watermark="{DynamicResource Text.Clone.LocalName.Placeholder}"
|
||||
Text="{Binding Local, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Clone.AdditionalParam}"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1"
|
||||
Height="28"
|
||||
CornerRadius="3"
|
||||
Watermark="{DynamicResource Text.Clone.AdditionalParam.Placeholder}"
|
||||
Text="{Binding ExtraArgs, Mode=TwoWay}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
x:DataType="vm:CommitDetail">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="256" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.CommitDetailChangesLeftWidth, Mode=TwoWay}" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Tag">
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.CreateTag}"/>
|
||||
<Grid Margin="0,16,8,0" RowDefinitions="32,32,32,Auto,Auto,32" ColumnDefinitions="150,*">
|
||||
<Grid Margin="0,16,8,0" RowDefinitions="32,32,32,Auto,Auto,32" ColumnDefinitions="120,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
|
@ -28,11 +28,11 @@
|
|||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
|
|
@ -234,9 +234,7 @@
|
|||
|
||||
<!-- Text Diff -->
|
||||
<DataTemplate DataType="m:TextDiff">
|
||||
<v:TextDiffView TextDiff="{Binding}"
|
||||
SyncScrollOffset="{Binding SyncScrollOffset, Mode=TwoWay}"
|
||||
UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"/>
|
||||
<v:TextDiffView UseSideBySideDiff="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSideBySideDiff, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Empty or only EOL changes -->
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -12,23 +12,13 @@
|
|||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.FileHistory}"
|
||||
Background="Transparent"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid Margin="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToContentMargin}}">
|
||||
MinWidth="1280" MinHeight="720">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
|
@ -36,7 +26,9 @@
|
|||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
PointerPressed="BeginMoveWindow"
|
||||
PointerMoved="MoveWindow"
|
||||
PointerReleased="EndMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" IsVisible="{OnPlatform False, macOS=True}">
|
||||
|
@ -56,7 +48,7 @@
|
|||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" MinWidth="300" MaxWidth="600"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
|
@ -143,64 +135,5 @@
|
|||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Custom window sizer for Linux -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="2" IsVisible="{OnPlatform False, Linux=True}" IsHitTestVisible="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.IsNormal}}">
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class FileHistories : Window
|
||||
public partial class FileHistories : ChromelessWindow
|
||||
{
|
||||
public FileHistories()
|
||||
{
|
||||
|
@ -12,31 +13,43 @@ namespace SourceGit.Views
|
|||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
_pressedTitleBar = false;
|
||||
|
||||
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
if (border.Tag is WindowEdge edge)
|
||||
{
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
if (WindowState == WindowState.Maximized)
|
||||
WindowState = WindowState.Normal;
|
||||
else
|
||||
WindowState = WindowState.Maximized;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
if (e.ClickCount != 2)
|
||||
_pressedTitleBar = true;
|
||||
}
|
||||
|
||||
private void MoveWindow(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (!_pressedTitleBar)
|
||||
return;
|
||||
|
||||
var visual = (Visual)e.Source;
|
||||
BeginMoveDrag(new PointerPressedEventArgs(
|
||||
e.Source,
|
||||
e.Pointer,
|
||||
visual,
|
||||
e.GetPosition(visual),
|
||||
e.Timestamp,
|
||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
|
||||
e.KeyModifiers));
|
||||
}
|
||||
|
||||
private void EndMoveWindow(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
_pressedTitleBar = false;
|
||||
}
|
||||
|
||||
private bool _pressedTitleBar = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,18 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:c="using:SourceGit.Converters"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.Hotkeys"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.Hotkeys}"
|
||||
Background="Transparent"
|
||||
SizeToContent="WidthAndHeight"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
|
@ -59,7 +50,7 @@
|
|||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Border Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<Border Grid.Row="1">
|
||||
<StackPanel Orientation="Vertical" Margin="16,8,16,16">
|
||||
<TextBlock Text="{DynamicResource Text.Hotkeys.Global}"
|
||||
Foreground="{DynamicResource Brush.FG2}"
|
||||
|
@ -93,7 +84,7 @@
|
|||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
||||
Margin="0,8"/>
|
||||
|
||||
<Grid RowDefinitions="20,20,20,20,20,20" ColumnDefinitions="150,*">
|
||||
<Grid RowDefinitions="20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+F, macOS=⌘+F}"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.OpenSearchCommits}" />
|
||||
|
||||
|
@ -109,8 +100,14 @@
|
|||
<TextBlock Grid.Row="4" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Space, macOS=␣}"/>
|
||||
<TextBlock Grid.Row="4" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.StageOrUnstageSelected}" />
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Classes="monospace bold" Text="F5"/>
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+Enter, macOS=⌘+Enter}"/>
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Commit}" />
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Classes="monospace bold" Text="{OnPlatform Ctrl+Shift+Enter, macOS=⌘+⇧+Enter}"/>
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.CommitAndPush}" />
|
||||
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Classes="monospace bold" Text="F5"/>
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"
|
||||
|
@ -135,4 +132,4 @@
|
|||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Hotkeys : Window
|
||||
public partial class Hotkeys : ChromelessWindow
|
||||
{
|
||||
public Hotkeys()
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -13,36 +13,27 @@
|
|||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="SourceGit"
|
||||
Background="Transparent"
|
||||
MinWidth="1280" MinHeight="720"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Window.Resources>
|
||||
<SolidColorBrush x:Key="SystemControlErrorTextForegroundBrush" Color="Red"/>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToContentMargin}}">
|
||||
Width="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.LauncherWidth, Mode=TwoWay}"
|
||||
Height="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.LauncherHeight, Mode=TwoWay}"
|
||||
WindowState="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.LauncherWindowState, Mode=TwoWay}"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.ToTitleBarHeight}}"/>
|
||||
<RowDefinition Height="{Binding #me.TitleBarHeight}"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- Custom TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto">
|
||||
<!-- Bottom border -->
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
Background="{DynamicResource Brush.TitleBar}"
|
||||
BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border0}"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"/>
|
||||
DoubleTapped="OnTitleBarDoubleTapped"
|
||||
PointerPressed="BeginMoveWindow"
|
||||
PointerMoved="MoveWindow"
|
||||
PointerReleased="EndMoveWindow"/>
|
||||
|
||||
<!-- Caption Buttons (macOS) -->
|
||||
<Border Grid.Column="0" VerticalAlignment="Stretch" Margin="2,0,8,3" IsVisible="{OnPlatform False, macOS=True}">
|
||||
|
@ -92,10 +83,9 @@
|
|||
|
||||
<ScrollViewer Grid.Column="1"
|
||||
x:Name="launcherTabsScroller"
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalScrollBarVisibility="Hidden"
|
||||
VerticalScrollBarVisibility="Disabled"
|
||||
DoubleTapped="MaximizeOrRestoreWindow"
|
||||
PointerPressed="BeginMoveWindow"
|
||||
PointerWheelChanged="ScrollTabs"
|
||||
ScrollChanged="OnTabsScrollChanged">
|
||||
<StackPanel x:Name="launcherTabsBar" Orientation="Horizontal" SizeChanged="UpdateScrollIndicator">
|
||||
|
@ -260,36 +250,21 @@
|
|||
</ContentControl>
|
||||
|
||||
<!-- Popup container -->
|
||||
<Grid Grid.Row="1" Margin="0,36,0,0" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<Grid Grid.Row="1" Margin="0,36,0,0" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}" ClipToBounds="True">
|
||||
<Border Background="Transparent" PointerPressed="OnPopupCancelByClickMask"/>
|
||||
|
||||
<Grid Width="500" HorizontalAlignment="Center" VerticalAlignment="Top">
|
||||
<ContentControl Content="{Binding ActivePage.Popup}" ClipToBounds="True">
|
||||
<Border Width="500" HorizontalAlignment="Center" VerticalAlignment="Top" Effect="drop-shadow(0 0 8 #8F000000)" CornerRadius="0,0,4,4" ClipToBounds="True">
|
||||
<ContentControl Content="{Binding ActivePage.Popup}" Background="{DynamicResource Brush.Popup}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:Popup">
|
||||
<Border Margin="8,0,8,8"
|
||||
Background="{DynamicResource Brush.Popup}"
|
||||
BorderBrush="{DynamicResource Brush.Border0}">
|
||||
<Border.CornerRadius>
|
||||
<OnPlatform Default="0,0,4,4" Linux="0"/>
|
||||
</Border.CornerRadius>
|
||||
|
||||
<Border.BorderThickness>
|
||||
<OnPlatform Default="0" Linux="1,0,1,1"/>
|
||||
</Border.BorderThickness>
|
||||
|
||||
<Border.Effect>
|
||||
<OnPlatform Default="drop-shadow(0 0 8 #8F000000)" Linux="{x:Null}"/>
|
||||
</Border.Effect>
|
||||
|
||||
<StackPanel Margin="8" Orientation="Vertical">
|
||||
<StackPanel Orientation="Vertical" Background="{DynamicResource Brush.Popup}">
|
||||
<!-- Popup Widget -->
|
||||
<ContentPresenter Margin="0,8"
|
||||
<ContentPresenter Margin="8,16,8,8"
|
||||
Content="{Binding View}"
|
||||
IsHitTestVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}"/>
|
||||
|
||||
<!-- Options -->
|
||||
<StackPanel Margin="0,8,0,0"
|
||||
<StackPanel Margin="8,4,8,8"
|
||||
Height="32"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
|
@ -307,15 +282,14 @@
|
|||
</StackPanel>
|
||||
|
||||
<!-- Running -->
|
||||
<v:PopupRunningStatus Margin="8"
|
||||
<v:PopupRunningStatus Margin="12,8"
|
||||
Description="{Binding ProgressDescription}"
|
||||
IsVisible="{Binding InProgress}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Notification container -->
|
||||
|
@ -363,64 +337,5 @@
|
|||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- Custom window sizer for Linux -->
|
||||
<Grid Grid.Row="0" Grid.RowSpan="2" IsVisible="{OnPlatform False, Linux=True}" IsHitTestVisible="{Binding #me.WindowState, Converter={x:Static c:WindowStateConverters.IsNormal}}">
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Cursor="TopLeftCorner"
|
||||
Tag="{x:Static WindowEdge.NorthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
Cursor="TopSide"
|
||||
Tag="{x:Static WindowEdge.North}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Cursor="TopRightCorner"
|
||||
Tag="{x:Static WindowEdge.NorthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch"
|
||||
Cursor="LeftSide"
|
||||
Tag="{x:Static WindowEdge.West}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Margin="0,4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Stretch"
|
||||
Cursor="RightSide"
|
||||
Tag="{x:Static WindowEdge.East}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||
Cursor="BottomLeftCorner"
|
||||
Tag="{x:Static WindowEdge.SouthWest}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Height="4" Margin="4,0"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
|
||||
Cursor="BottomSide"
|
||||
Tag="{x:Static WindowEdge.South}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
|
||||
<Border Width="4" Height="4"
|
||||
Background="Transparent"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Cursor="BottomRightCorner"
|
||||
Tag="{x:Static WindowEdge.SouthEast}"
|
||||
PointerPressed="CustomResizeWindow"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -7,8 +7,17 @@ using Avalonia.Interactivity;
|
|||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Launcher : Window, Models.INotificationReceiver
|
||||
public partial class Launcher : ChromelessWindow, Models.INotificationReceiver
|
||||
{
|
||||
public static readonly StyledProperty<GridLength> TitleBarHeightProperty =
|
||||
AvaloniaProperty.Register<Launcher, GridLength>(nameof(TitleBarHeight), new GridLength(38, GridUnitType.Pixel));
|
||||
|
||||
public GridLength TitleBarHeight
|
||||
{
|
||||
get => GetValue(TitleBarHeightProperty);
|
||||
set => SetValue(TitleBarHeightProperty, value);
|
||||
}
|
||||
|
||||
public Launcher()
|
||||
{
|
||||
DataContext = new ViewModels.Launcher();
|
||||
|
@ -34,6 +43,20 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == WindowStateProperty)
|
||||
{
|
||||
var state = (WindowState)change.NewValue;
|
||||
if (state == WindowState.Maximized)
|
||||
SetCurrentValue(TitleBarHeightProperty, new GridLength(OperatingSystem.IsMacOS() ? 34 : 30));
|
||||
else
|
||||
SetCurrentValue(TitleBarHeightProperty, new GridLength(38, GridUnitType.Pixel));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
var vm = DataContext as ViewModels.Launcher;
|
||||
|
@ -136,36 +159,43 @@ namespace SourceGit.Views
|
|||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void MaximizeOrRestoreWindow(object sender, TappedEventArgs e)
|
||||
private void OnTitleBarDoubleTapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowState = WindowState.Maximized;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
_pressedTitleBar = false;
|
||||
|
||||
private void CustomResizeWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is Border border)
|
||||
{
|
||||
if (border.Tag is WindowEdge edge)
|
||||
{
|
||||
BeginResizeDrag(edge, e);
|
||||
}
|
||||
}
|
||||
if (WindowState == WindowState.Maximized)
|
||||
WindowState = WindowState.Normal;
|
||||
else
|
||||
WindowState = WindowState.Maximized;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void BeginMoveWindow(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.ClickCount != 2)
|
||||
{
|
||||
BeginMoveDrag(e);
|
||||
_pressedTitleBar = true;
|
||||
}
|
||||
|
||||
private void MoveWindow(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (!_pressedTitleBar)
|
||||
return;
|
||||
|
||||
var visual = (Visual)e.Source;
|
||||
BeginMoveDrag(new PointerPressedEventArgs(
|
||||
e.Source,
|
||||
e.Pointer,
|
||||
visual,
|
||||
e.GetPosition(visual),
|
||||
e.Timestamp,
|
||||
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
|
||||
e.KeyModifiers));
|
||||
}
|
||||
|
||||
private void EndMoveWindow(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
_pressedTitleBar = false;
|
||||
}
|
||||
|
||||
private void ScrollTabs(object sender, PointerWheelEventArgs e)
|
||||
|
@ -229,26 +259,26 @@ namespace SourceGit.Views
|
|||
private void OnPointerPressedTab(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
_pressedTab = true;
|
||||
_startDrag = false;
|
||||
_startDragTab = false;
|
||||
_pressedTabPosition = e.GetPosition(sender as Border);
|
||||
}
|
||||
|
||||
private void OnPointerReleasedTab(object sender, PointerReleasedEventArgs e)
|
||||
{
|
||||
_pressedTab = false;
|
||||
_startDrag = false;
|
||||
_startDragTab = false;
|
||||
}
|
||||
|
||||
private void OnPointerMovedOverTab(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (_pressedTab && !_startDrag && sender is Border border)
|
||||
if (_pressedTab && !_startDragTab && sender is Border border)
|
||||
{
|
||||
var delta = e.GetPosition(border) - _pressedTabPosition;
|
||||
var sizeSquired = delta.X * delta.X + delta.Y * delta.Y;
|
||||
if (sizeSquired < 64)
|
||||
return;
|
||||
|
||||
_startDrag = true;
|
||||
_startDragTab = true;
|
||||
|
||||
var data = new DataObject();
|
||||
data.Set("MovedTab", border.DataContext);
|
||||
|
@ -270,7 +300,7 @@ namespace SourceGit.Views
|
|||
}
|
||||
|
||||
_pressedTab = false;
|
||||
_startDrag = false;
|
||||
_startDragTab = false;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
@ -297,8 +327,9 @@ namespace SourceGit.Views
|
|||
OnPopupCancel(sender, e);
|
||||
}
|
||||
|
||||
private bool _pressedTitleBar = false;
|
||||
private bool _pressedTab = false;
|
||||
private Point _pressedTabPosition = new Point();
|
||||
private bool _startDrag = false;
|
||||
private bool _startDragTab = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
x:Class="SourceGit.Views.PopupRunningStatus"
|
||||
x:Name="me">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Rectangle Height="1" Margin="-8,0" HorizontalAlignment="Stretch" Fill="{DynamicResource Brush.Border1}" />
|
||||
<Rectangle Height="1" HorizontalAlignment="Stretch" Fill="{DynamicResource Brush.Border1}" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8">
|
||||
<ContentPresenter x:Name="icon" Width="12" Height="12"/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -14,20 +14,10 @@
|
|||
x:Name="me"
|
||||
Icon="/App.ico"
|
||||
Title="{DynamicResource Text.Preference}"
|
||||
Background="Transparent"
|
||||
Width="600" SizeToContent="Height"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,Auto" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
|
@ -62,7 +52,7 @@
|
|||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Border Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<Border Grid.Row="1">
|
||||
<TabControl>
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
|
@ -210,20 +200,7 @@
|
|||
Padding="4"
|
||||
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
|
||||
CornerRadius="3"
|
||||
Value="{Binding DefaultFontSize, Mode=TwoWay}">
|
||||
<NumericUpDown.Styles>
|
||||
<Style Selector="NumericUpDown /template/ ButtonSpinner#PART_Spinner">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
</Style>
|
||||
<Style Selector="NumericUpDown /template/ TextBox#PART_TextBox">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="CornerRadius" Value="3,0,0,3"/>
|
||||
</Style>
|
||||
</NumericUpDown.Styles>
|
||||
</NumericUpDown>
|
||||
Value="{Binding DefaultFontSize, Mode=TwoWay}"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0"
|
||||
Text="{DynamicResource Text.Preference.Appearance.ColorOverrides}"
|
||||
|
@ -392,20 +369,7 @@
|
|||
CornerRadius="3"
|
||||
ParsingNumberStyle="Integer"
|
||||
FormatString="0"
|
||||
Value="{Binding GitAutoFetchInterval, Mode=TwoWay, FallbackValue=10}">
|
||||
<NumericUpDown.Styles>
|
||||
<Style Selector="NumericUpDown /template/ ButtonSpinner#PART_Spinner">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
</Style>
|
||||
<Style Selector="NumericUpDown /template/ TextBox#PART_TextBox">
|
||||
<Setter Property="MinHeight" Value="0"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="CornerRadius" Value="3,0,0,3"/>
|
||||
</Style>
|
||||
</NumericUpDown.Styles>
|
||||
</NumericUpDown>
|
||||
Value="{Binding GitAutoFetchInterval, Mode=TwoWay, FallbackValue=10}"/>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
|
@ -553,4 +517,4 @@
|
|||
</TabControl>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -5,7 +5,6 @@ using System.Threading.Tasks;
|
|||
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
@ -14,7 +13,7 @@ using Avalonia.Threading;
|
|||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class Preference : Window
|
||||
public partial class Preference : ChromelessWindow
|
||||
{
|
||||
public AvaloniaList<FontFamily> InstalledFonts
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Rebase}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="150,*">
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="130,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
|
@ -36,11 +36,11 @@
|
|||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="m:Commit">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
<!-- Body -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="250" MinWidth="200" MaxWidth="400"/>
|
||||
<ColumnDefinition Width="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.RepositorySidebarWidth, Mode=TwoWay}" MinWidth="200" MaxWidth="400"/>
|
||||
<ColumnDefinition Width="3"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
@ -615,19 +615,19 @@
|
|||
<ContentControl Grid.Column="0" Margin="8,0" Content="{Binding InProgressContext}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="vm:CherryPickInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.CherryPick}"/>
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.CherryPick}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:RebaseInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.Rebase}"/>
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Rebase}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:RevertInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.Revert}"/>
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Revert}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="vm:MergeInProgress">
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.FG3}" Text="{DynamicResource Text.InProgress.Merge}"/>
|
||||
<TextBlock FontWeight="Bold" Foreground="{DynamicResource Brush.ConflictForeground}" Text="{DynamicResource Text.InProgress.Merge}"/>
|
||||
</DataTemplate>
|
||||
</ContentControl.DataTemplates>
|
||||
</ContentControl>
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Reset.MoveTo}"/>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Text="{Binding To.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Text="{Binding To.Subject}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="1" Grid.Column="1" ColumnDefinitions="Auto,Auto,*" Height="20" VerticalAlignment="Center">
|
||||
<Path Grid.Column="0" Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding To.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding To.Subject}" Margin="8,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Revert}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="150,*">
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="130,*">
|
||||
<TextBlock Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Revert.Commit}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Path Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Classes="monospace" VerticalAlignment="Center" Text="{Binding Target.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding Target.Subject}" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Column="1" ColumnDefinitions="Auto,Auto,*">
|
||||
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Classes="monospace" VerticalAlignment="Center" Text="{Binding Target.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Target.Subject}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox Grid.Row="1" Grid.Column="1"
|
||||
Content="{DynamicResource Text.Revert.CommitChanges}"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
x:DataType="vm:CommitDetail">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="256" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.CommitDetailFilesLeftWidth, Mode=TwoWay}" MinWidth="200" MaxWidth="480"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
|
|
@ -12,22 +12,23 @@
|
|||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Reword}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32" ColumnDefinitions="100,*">
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32" ColumnDefinitions="100,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Reword.On}"/>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Text="{Binding Head.Subject}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="0" Grid.Column="1" ColumnDefinitions="Auto,Auto,*" Height="20" VerticalAlignment="Center">
|
||||
<Path Grid.Column="0" Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Head.Subject}" Margin="8,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Reword.Message}"/>
|
||||
<TextBox Grid.Row="1" Grid.RowSpan="2" Grid.Column="1"
|
||||
<TextBox Grid.Row="1" Grid.RowSpan="3" Grid.Column="1"
|
||||
Margin="0,4,0,0"
|
||||
CornerRadius="2"
|
||||
AcceptsReturn="True"
|
||||
VerticalContentAlignment="Top"
|
||||
|
|
|
@ -1,29 +1,20 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:m="using:SourceGit.Models"
|
||||
xmlns:vm="using:SourceGit.ViewModels"
|
||||
xmlns:v="using:SourceGit.Views"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="SourceGit.Views.SelfUpdate"
|
||||
x:DataType="vm:SelfUpdate"
|
||||
Title="{DynamicResource Text.SelfUpdate.Title}"
|
||||
Icon="/App.ico"
|
||||
Background="Transparent"
|
||||
SizeToContent="WidthAndHeight"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- TitleBar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
|
@ -61,7 +52,7 @@
|
|||
</Grid>
|
||||
|
||||
<!-- Body -->
|
||||
<Grid Grid.Row="1" Background="{DynamicResource Brush.Window}">
|
||||
<Grid Grid.Row="1">
|
||||
<ContentControl Content="{Binding Data}">
|
||||
<ContentControl.DataTemplates>
|
||||
<DataTemplate DataType="m:Version">
|
||||
|
@ -150,4 +141,4 @@
|
|||
</ContentControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -4,7 +4,7 @@ using Avalonia.Interactivity;
|
|||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public partial class SelfUpdate : Window
|
||||
public partial class SelfUpdate : ChromelessWindow
|
||||
{
|
||||
public SelfUpdate()
|
||||
{
|
||||
|
|
|
@ -12,32 +12,33 @@
|
|||
<TextBlock FontSize="18"
|
||||
Classes="bold"
|
||||
Text="{DynamicResource Text.Squash}"/>
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32" ColumnDefinitions="100,*">
|
||||
<Grid Margin="0,16,0,0" RowDefinitions="32,32,32,32,32" ColumnDefinitions="100,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Squash.Head}"/>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Text="{Binding Head.Subject}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="0" Grid.Column="1" ColumnDefinitions="Auto,Auto,*" Height="20" VerticalAlignment="Center">
|
||||
<Path Grid.Column="0" Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Head.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Head.Subject}" Margin="8,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Squash.To}"/>
|
||||
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" Height="20" VerticalAlignment="Center">
|
||||
<Path Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Text="{Binding Parent.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Text="{Binding Parent.Subject}" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="1" Grid.Column="1" ColumnDefinitions="Auto,Auto,*" Height="20" VerticalAlignment="Center">
|
||||
<Path Grid.Column="0" Margin="0,6,8,0" Width="14" Height="14" Fill="{DynamicResource Brush.FG1}" Data="{StaticResource Icons.Commit}"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Parent.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Parent.Subject}" Margin="8,0,0,0" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"
|
||||
Text="{DynamicResource Text.Squash.Message}"/>
|
||||
<TextBox Grid.Row="2" Grid.RowSpan="2" Grid.Column="1"
|
||||
<TextBox Grid.Row="2" Grid.RowSpan="3" Grid.Column="1"
|
||||
Margin="0,4,0,0"
|
||||
CornerRadius="2"
|
||||
AcceptsReturn="True"
|
||||
VerticalContentAlignment="Top"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
x:DataType="vm:StashesPage">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" MinWidth="300"/>
|
||||
<ColumnDefinition Width="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.StashesLeftWidth, Mode=TwoWay}" MinWidth="300"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Window xmlns="https://github.com/avaloniaui"
|
||||
<v:ChromelessWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
@ -9,25 +9,10 @@
|
|||
x:Class="SourceGit.Views.Statistics"
|
||||
x:DataType="vm:Statistics"
|
||||
Title="{DynamicResource Text.Statistics}"
|
||||
Background="Transparent"
|
||||
Width="800" Height="450"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
SystemDecorations="{OnPlatform Full, Linux=None}">
|
||||
<Grid RowDefinitions="Auto,Auto,*" Margin="{OnPlatform 0, Linux=6}">
|
||||
<!-- Custom window shadow for Linux -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
Effect="drop-shadow(0 0 6 #A0000000)"
|
||||
IsVisible="{OnPlatform False, Linux=True}"/>
|
||||
|
||||
<!-- Window BG -->
|
||||
<Border Grid.Row="1" Grid.RowSpan="2"
|
||||
Background="{DynamicResource Brush.Window}"
|
||||
IsVisible="{OnPlatform True, Linux=False}"/>
|
||||
|
||||
CanResize="False">
|
||||
<Grid RowDefinitions="Auto,Auto,*">
|
||||
<!-- Title bar -->
|
||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto" Height="30">
|
||||
<Border Grid.Column="0" Grid.ColumnSpan="3"
|
||||
|
@ -185,4 +170,4 @@
|
|||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
IsVisible="{Binding IsLoading}"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
</v:ChromelessWindow>
|
||||
|
|
|
@ -226,7 +226,7 @@ namespace SourceGit.Views
|
|||
private int _lastHitIdx = -1;
|
||||
}
|
||||
|
||||
public partial class Statistics : Window
|
||||
public partial class Statistics : ChromelessWindow
|
||||
{
|
||||
public Statistics()
|
||||
{
|
||||
|
|
|
@ -11,18 +11,16 @@
|
|||
Background="{DynamicResource Brush.Contents}">
|
||||
<UserControl.DataTemplates>
|
||||
<DataTemplate DataType="m:TextDiff">
|
||||
<v:CombinedTextDiffPresenter BorderBrush="{DynamicResource Brush.Border2}"
|
||||
BorderThickness="0"
|
||||
LineBGEmpty = "{DynamicResource Brush.TextDiffView.LineBG1.EMPTY}"
|
||||
LineBGAdd = "{DynamicResource Brush.TextDiffView.LineBG1.ADD}"
|
||||
LineBGDeleted = "{DynamicResource Brush.TextDiffView.LineBG1.DELETED}"
|
||||
SecondaryLineBGAdd = "{DynamicResource Brush.TextDiffView.LineBG2.ADD}"
|
||||
SecondaryLineBGDeleted = "{DynamicResource Brush.TextDiffView.LineBG2.DELETED}"
|
||||
<v:CombinedTextDiffPresenter FileName="{Binding File}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
SecondaryFG="{DynamicResource Brush.FG2}"
|
||||
LineBrush="{DynamicResource Brush.Border2}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
|
||||
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
|
||||
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
|
||||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}"
|
||||
DiffData="{Binding}"
|
||||
SyncScrollOffset="{Binding #ThisControl.SyncScrollOffset, Mode=TwoWay}"
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"/>
|
||||
</DataTemplate>
|
||||
|
@ -30,40 +28,36 @@
|
|||
<DataTemplate DataType="vm:TwoSideTextDiff">
|
||||
<Grid ColumnDefinitions="*,1,*">
|
||||
<v:SingleSideTextDiffPresenter Grid.Column="0"
|
||||
SyncScrollOffset="{Binding #ThisControl.SyncScrollOffset, Mode=TwoWay}"
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
|
||||
IsOld="True"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
BorderThickness="0"
|
||||
LineBGEmpty = "{DynamicResource Brush.TextDiffView.LineBG1.EMPTY}"
|
||||
LineBGAdd = "{DynamicResource Brush.TextDiffView.LineBG1.ADD}"
|
||||
LineBGDeleted = "{DynamicResource Brush.TextDiffView.LineBG1.DELETED}"
|
||||
SecondaryLineBGAdd = "{DynamicResource Brush.TextDiffView.LineBG2.ADD}"
|
||||
SecondaryLineBGDeleted = "{DynamicResource Brush.TextDiffView.LineBG2.DELETED}"
|
||||
FileName="{Binding File}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
SecondaryFG="{DynamicResource Brush.FG2}"
|
||||
LineBrush="{DynamicResource Brush.Border2}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
|
||||
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
|
||||
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
|
||||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}"
|
||||
DiffData="{Binding}"/>
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"/>
|
||||
|
||||
<Rectangle Grid.Column="1" Fill="{DynamicResource Brush.Border2}" Width="1" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
|
||||
|
||||
<v:SingleSideTextDiffPresenter Grid.Column="2"
|
||||
SyncScrollOffset="{Binding #ThisControl.SyncScrollOffset, Mode=TwoWay}"
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"
|
||||
IsOld="False"
|
||||
BorderBrush="{DynamicResource Brush.Border2}"
|
||||
BorderThickness="0"
|
||||
LineBGEmpty = "{DynamicResource Brush.TextDiffView.LineBG1.EMPTY}"
|
||||
LineBGAdd = "{DynamicResource Brush.TextDiffView.LineBG1.ADD}"
|
||||
LineBGDeleted = "{DynamicResource Brush.TextDiffView.LineBG1.DELETED}"
|
||||
SecondaryLineBGAdd = "{DynamicResource Brush.TextDiffView.LineBG2.ADD}"
|
||||
SecondaryLineBGDeleted = "{DynamicResource Brush.TextDiffView.LineBG2.DELETED}"
|
||||
FileName="{Binding File}"
|
||||
Foreground="{DynamicResource Brush.FG1}"
|
||||
SecondaryFG="{DynamicResource Brush.FG2}"
|
||||
LineBrush="{DynamicResource Brush.Border2}"
|
||||
EmptyContentBackground="{DynamicResource Brush.Diff.EmptyBG}"
|
||||
AddedContentBackground="{DynamicResource Brush.Diff.AddedBG}"
|
||||
DeletedContentBackground="{DynamicResource Brush.Diff.DeletedBG}"
|
||||
AddedHighlightBrush="{DynamicResource Brush.Diff.AddedHighlight}"
|
||||
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
|
||||
IndicatorForeground="{DynamicResource Brush.FG2}"
|
||||
FontFamily="{Binding Source={x:Static vm:Preference.Instance}, Path=MonospaceFont}"
|
||||
DiffData="{Binding}"/>
|
||||
UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
|
||||
WordWrap="{Binding Source={x:Static vm:Preference.Instance}, Path=EnableDiffViewWordWrap}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</UserControl.DataTemplates>
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Text;
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
@ -21,7 +22,161 @@ using AvaloniaEdit.Utils;
|
|||
|
||||
namespace SourceGit.Views
|
||||
{
|
||||
public class CombinedTextDiffPresenter : TextEditor
|
||||
public class IThemedTextDiffPresenter : TextEditor
|
||||
{
|
||||
public static readonly StyledProperty<string> FileNameProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, string>(nameof(FileName), string.Empty);
|
||||
|
||||
public string FileName
|
||||
{
|
||||
get => GetValue(FileNameProperty);
|
||||
set => SetValue(FileNameProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBrushProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(LineBrush), new SolidColorBrush(Colors.DarkGray));
|
||||
|
||||
public IBrush LineBrush
|
||||
{
|
||||
get => GetValue(LineBrushProperty);
|
||||
set => SetValue(LineBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> EmptyContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(EmptyContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0)));
|
||||
|
||||
public IBrush EmptyContentBackground
|
||||
{
|
||||
get => GetValue(EmptyContentBackgroundProperty);
|
||||
set => SetValue(EmptyContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> AddedContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(AddedContentBackground), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
|
||||
|
||||
public IBrush AddedContentBackground
|
||||
{
|
||||
get => GetValue(AddedContentBackgroundProperty);
|
||||
set => SetValue(AddedContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> DeletedContentBackgroundProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(DeletedContentBackground), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
|
||||
|
||||
public IBrush DeletedContentBackground
|
||||
{
|
||||
get => GetValue(DeletedContentBackgroundProperty);
|
||||
set => SetValue(DeletedContentBackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> AddedHighlightBrushProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(AddedHighlightBrush), new SolidColorBrush(Color.FromArgb(90, 0, 255, 0)));
|
||||
|
||||
public IBrush AddedHighlightBrush
|
||||
{
|
||||
get => GetValue(AddedHighlightBrushProperty);
|
||||
set => SetValue(AddedHighlightBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> DeletedHighlightBrushProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(DeletedHighlightBrush), new SolidColorBrush(Color.FromArgb(80, 255, 0, 0)));
|
||||
|
||||
public IBrush DeletedHighlightBrush
|
||||
{
|
||||
get => GetValue(DeletedHighlightBrushProperty);
|
||||
set => SetValue(DeletedHighlightBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> IndicatorForegroundProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, IBrush>(nameof(IndicatorForeground), Brushes.Gray);
|
||||
|
||||
public IBrush IndicatorForeground
|
||||
{
|
||||
get => GetValue(IndicatorForegroundProperty);
|
||||
set => SetValue(IndicatorForegroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> UseSyntaxHighlightingProperty =
|
||||
AvaloniaProperty.Register<IThemedTextDiffPresenter, bool>(nameof(UseSyntaxHighlighting), false);
|
||||
|
||||
public bool UseSyntaxHighlighting
|
||||
{
|
||||
get => GetValue(UseSyntaxHighlightingProperty);
|
||||
set => SetValue(UseSyntaxHighlightingProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(TextEditor);
|
||||
|
||||
public IThemedTextDiffPresenter(TextArea area, TextDocument doc) : base(area, doc)
|
||||
{
|
||||
IsReadOnly = true;
|
||||
ShowLineNumbers = false;
|
||||
BorderThickness = new Thickness(0);
|
||||
|
||||
TextArea.TextView.Margin = new Thickness(4, 0);
|
||||
TextArea.TextView.Options.EnableHyperlinks = false;
|
||||
TextArea.TextView.Options.EnableEmailHyperlinks = false;
|
||||
}
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLoaded(e);
|
||||
UpdateTextMate();
|
||||
}
|
||||
|
||||
protected override void OnUnloaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnUnloaded(e);
|
||||
|
||||
if (_textMate != null)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == UseSyntaxHighlightingProperty)
|
||||
UpdateTextMate();
|
||||
else if (change.Property == FileNameProperty)
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, FileName);
|
||||
else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null)
|
||||
Models.TextMateHelper.SetThemeByApp(_textMate);
|
||||
}
|
||||
|
||||
protected void UpdateTextMate()
|
||||
{
|
||||
if (UseSyntaxHighlighting)
|
||||
{
|
||||
if (_textMate == null)
|
||||
{
|
||||
TextArea.TextView.LineTransformers.Remove(_lineStyleTransformer);
|
||||
_textMate = Models.TextMateHelper.CreateForEditor(this);
|
||||
TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, FileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_textMate != null)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
GC.Collect();
|
||||
|
||||
TextArea.TextView.Redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TextMate.Installation _textMate = null;
|
||||
protected IVisualLineTransformer _lineStyleTransformer = null;
|
||||
}
|
||||
|
||||
public class CombinedTextDiffPresenter : IThemedTextDiffPresenter
|
||||
{
|
||||
public class LineNumberMargin : AbstractMargin
|
||||
{
|
||||
|
@ -104,7 +259,7 @@ namespace SourceGit.Views
|
|||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var pen = new Pen(_editor.BorderBrush, 1);
|
||||
var pen = new Pen(_editor.LineBrush, 1);
|
||||
context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
|
||||
}
|
||||
|
||||
|
@ -155,11 +310,11 @@ namespace SourceGit.Views
|
|||
switch (type)
|
||||
{
|
||||
case Models.TextDiffLineType.None:
|
||||
return _editor.LineBGEmpty;
|
||||
return _editor.EmptyContentBackground;
|
||||
case Models.TextDiffLineType.Added:
|
||||
return _editor.LineBGAdd;
|
||||
return _editor.AddedContentBackground;
|
||||
case Models.TextDiffLineType.Deleted:
|
||||
return _editor.LineBGDeleted;
|
||||
return _editor.DeletedContentBackground;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -186,7 +341,7 @@ namespace SourceGit.Views
|
|||
{
|
||||
ChangeLinePart(line.Offset, line.EndOffset, v =>
|
||||
{
|
||||
v.TextRunProperties.SetForegroundBrush(_editor.SecondaryFG);
|
||||
v.TextRunProperties.SetForegroundBrush(_editor.IndicatorForeground);
|
||||
v.TextRunProperties.SetTypeface(new Typeface(_editor.FontFamily, FontStyle.Italic));
|
||||
});
|
||||
|
||||
|
@ -195,7 +350,7 @@ namespace SourceGit.Views
|
|||
|
||||
if (info.Highlights.Count > 0)
|
||||
{
|
||||
var bg = info.Type == Models.TextDiffLineType.Added ? _editor.SecondaryLineBGAdd : _editor.SecondaryLineBGDeleted;
|
||||
var bg = info.Type == Models.TextDiffLineType.Added ? _editor.AddedHighlightBrush : _editor.DeletedHighlightBrush;
|
||||
foreach (var highlight in info.Highlights)
|
||||
{
|
||||
ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v =>
|
||||
|
@ -209,129 +364,57 @@ namespace SourceGit.Views
|
|||
private readonly CombinedTextDiffPresenter _editor;
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Models.TextDiff> DiffDataProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, Models.TextDiff>(nameof(DiffData));
|
||||
|
||||
public Models.TextDiff DiffData
|
||||
{
|
||||
get => GetValue(DiffDataProperty);
|
||||
set => SetValue(DiffDataProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBGEmptyProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, IBrush>(nameof(LineBGEmpty), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0)));
|
||||
|
||||
public IBrush LineBGEmpty
|
||||
{
|
||||
get => GetValue(LineBGEmptyProperty);
|
||||
set => SetValue(LineBGEmptyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBGAddProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, IBrush>(nameof(LineBGAdd), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
|
||||
|
||||
public IBrush LineBGAdd
|
||||
{
|
||||
get => GetValue(LineBGAddProperty);
|
||||
set => SetValue(LineBGAddProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBGDeletedProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, IBrush>(nameof(LineBGDeleted), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
|
||||
|
||||
public IBrush LineBGDeleted
|
||||
{
|
||||
get => GetValue(LineBGDeletedProperty);
|
||||
set => SetValue(LineBGDeletedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> SecondaryLineBGAddProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, IBrush>(nameof(SecondaryLineBGAdd), new SolidColorBrush(Color.FromArgb(90, 0, 255, 0)));
|
||||
|
||||
public IBrush SecondaryLineBGAdd
|
||||
{
|
||||
get => GetValue(SecondaryLineBGAddProperty);
|
||||
set => SetValue(SecondaryLineBGAddProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> SecondaryLineBGDeletedProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, IBrush>(nameof(SecondaryLineBGDeleted), new SolidColorBrush(Color.FromArgb(80, 255, 0, 0)));
|
||||
|
||||
public IBrush SecondaryLineBGDeleted
|
||||
{
|
||||
get => GetValue(SecondaryLineBGDeletedProperty);
|
||||
set => SetValue(SecondaryLineBGDeletedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> SecondaryFGProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, IBrush>(nameof(SecondaryFG), Brushes.Gray);
|
||||
|
||||
public IBrush SecondaryFG
|
||||
{
|
||||
get => GetValue(SecondaryFGProperty);
|
||||
set => SetValue(SecondaryFGProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Vector> SyncScrollOffsetProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, Vector>(nameof(SyncScrollOffset));
|
||||
|
||||
public Vector SyncScrollOffset
|
||||
{
|
||||
get => GetValue(SyncScrollOffsetProperty);
|
||||
set => SetValue(SyncScrollOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> UseSyntaxHighlightingProperty =
|
||||
AvaloniaProperty.Register<CombinedTextDiffPresenter, bool>(nameof(UseSyntaxHighlighting), false);
|
||||
|
||||
public bool UseSyntaxHighlighting
|
||||
{
|
||||
get => GetValue(UseSyntaxHighlightingProperty);
|
||||
set => SetValue(UseSyntaxHighlightingProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(TextEditor);
|
||||
public Models.TextDiff DiffData => DataContext as Models.TextDiff;
|
||||
|
||||
public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument())
|
||||
{
|
||||
_lineStyleTransformer = new LineStyleTransformer(this);
|
||||
|
||||
IsReadOnly = true;
|
||||
ShowLineNumbers = false;
|
||||
|
||||
TextArea.LeftMargins.Add(new LineNumberMargin(this, true) { Margin = new Thickness(8, 0) });
|
||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
|
||||
TextArea.LeftMargins.Add(new LineNumberMargin(this, false) { Margin = new Thickness(8, 0) });
|
||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
|
||||
|
||||
TextArea.TextView.Margin = new Thickness(4, 0);
|
||||
TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
|
||||
TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
|
||||
TextArea.TextView.Options.EnableHyperlinks = false;
|
||||
TextArea.TextView.Options.EnableEmailHyperlinks = false;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
var scroller = (ScrollViewer)e.NameScope.Find("PART_ScrollViewer");
|
||||
scroller.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.TwoWay));
|
||||
}
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLoaded(e);
|
||||
|
||||
UpdateTextMate();
|
||||
|
||||
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
|
||||
TextArea.TextView.ScrollOffsetChanged += OnTextViewScrollOffsetChanged;
|
||||
}
|
||||
|
||||
protected override void OnUnloaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnUnloaded(e);
|
||||
|
||||
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
|
||||
TextArea.TextView.ScrollOffsetChanged -= OnTextViewScrollOffsetChanged;
|
||||
}
|
||||
|
||||
if (_textMate != null)
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
base.OnDataContextChanged(e);
|
||||
|
||||
var textDiff = DataContext as Models.TextDiff;
|
||||
if (textDiff != null)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var line in textDiff.Lines)
|
||||
builder.AppendLine(line.Content);
|
||||
|
||||
Text = builder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = string.Empty;
|
||||
}
|
||||
|
||||
GC.Collect();
|
||||
|
@ -346,9 +429,7 @@ namespace SourceGit.Views
|
|||
var menu = new ContextMenu();
|
||||
var parentView = this.FindAncestorOfType<TextDiffView>();
|
||||
if (parentView != null)
|
||||
{
|
||||
parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, false);
|
||||
}
|
||||
|
||||
var copy = new MenuItem();
|
||||
copy.Header = App.Text("Copy");
|
||||
|
@ -364,84 +445,9 @@ namespace SourceGit.Views
|
|||
TextArea.TextView.OpenContextMenu(menu);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnTextViewScrollOffsetChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetCurrentValue(SyncScrollOffsetProperty, TextArea.TextView.ScrollOffset);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == DiffDataProperty)
|
||||
{
|
||||
if (DiffData != null)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var line in DiffData.Lines)
|
||||
{
|
||||
builder.AppendLine(line.Content);
|
||||
}
|
||||
|
||||
Text = builder.ToString();
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File);
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = string.Empty;
|
||||
}
|
||||
}
|
||||
else if (change.Property == SyncScrollOffsetProperty)
|
||||
{
|
||||
if (TextArea.TextView.ScrollOffset != SyncScrollOffset)
|
||||
{
|
||||
IScrollable scrollable = TextArea.TextView;
|
||||
scrollable.Offset = SyncScrollOffset;
|
||||
}
|
||||
}
|
||||
else if (change.Property == UseSyntaxHighlightingProperty)
|
||||
{
|
||||
UpdateTextMate();
|
||||
}
|
||||
else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null)
|
||||
{
|
||||
Models.TextMateHelper.SetThemeByApp(_textMate);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextMate()
|
||||
{
|
||||
if (UseSyntaxHighlighting)
|
||||
{
|
||||
if (_textMate == null)
|
||||
{
|
||||
TextArea.TextView.LineTransformers.Remove(_lineStyleTransformer);
|
||||
_textMate = Models.TextMateHelper.CreateForEditor(this);
|
||||
TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
|
||||
|
||||
if (DiffData != null)
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_textMate != null)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
GC.Collect();
|
||||
|
||||
TextArea.TextView.Redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TextMate.Installation _textMate;
|
||||
private readonly LineStyleTransformer _lineStyleTransformer = null;
|
||||
}
|
||||
|
||||
public class SingleSideTextDiffPresenter : TextEditor
|
||||
public class SingleSideTextDiffPresenter : IThemedTextDiffPresenter
|
||||
{
|
||||
public class LineNumberMargin : AbstractMargin
|
||||
{
|
||||
|
@ -523,7 +529,7 @@ namespace SourceGit.Views
|
|||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
var pen = new Pen(_editor.BorderBrush, 1);
|
||||
var pen = new Pen(_editor.LineBrush, 1);
|
||||
context.DrawLine(pen, new Point(0, 0), new Point(0, Bounds.Height));
|
||||
}
|
||||
|
||||
|
@ -575,11 +581,11 @@ namespace SourceGit.Views
|
|||
switch (type)
|
||||
{
|
||||
case Models.TextDiffLineType.None:
|
||||
return _editor.LineBGEmpty;
|
||||
return _editor.EmptyContentBackground;
|
||||
case Models.TextDiffLineType.Added:
|
||||
return _editor.LineBGAdd;
|
||||
return _editor.AddedContentBackground;
|
||||
case Models.TextDiffLineType.Deleted:
|
||||
return _editor.LineBGDeleted;
|
||||
return _editor.DeletedContentBackground;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -607,7 +613,7 @@ namespace SourceGit.Views
|
|||
{
|
||||
ChangeLinePart(line.Offset, line.EndOffset, v =>
|
||||
{
|
||||
v.TextRunProperties.SetForegroundBrush(_editor.SecondaryFG);
|
||||
v.TextRunProperties.SetForegroundBrush(_editor.IndicatorForeground);
|
||||
v.TextRunProperties.SetTypeface(new Typeface(_editor.FontFamily, FontStyle.Italic));
|
||||
});
|
||||
|
||||
|
@ -616,7 +622,7 @@ namespace SourceGit.Views
|
|||
|
||||
if (info.Highlights.Count > 0)
|
||||
{
|
||||
var bg = info.Type == Models.TextDiffLineType.Added ? _editor.LineBGAdd : _editor.LineBGDeleted;
|
||||
var bg = info.Type == Models.TextDiffLineType.Added ? _editor.AddedHighlightBrush : _editor.DeletedHighlightBrush;
|
||||
foreach (var highlight in info.Highlights)
|
||||
{
|
||||
ChangeLinePart(line.Offset + highlight.Start, line.Offset + highlight.Start + highlight.Count, v =>
|
||||
|
@ -639,103 +645,16 @@ namespace SourceGit.Views
|
|||
set => SetValue(IsOldProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<ViewModels.TwoSideTextDiff> DiffDataProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, ViewModels.TwoSideTextDiff>(nameof(DiffData));
|
||||
|
||||
public ViewModels.TwoSideTextDiff DiffData
|
||||
{
|
||||
get => GetValue(DiffDataProperty);
|
||||
set => SetValue(DiffDataProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBGEmptyProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, IBrush>(nameof(LineBGEmpty), new SolidColorBrush(Color.FromArgb(60, 0, 0, 0)));
|
||||
|
||||
public IBrush LineBGEmpty
|
||||
{
|
||||
get => GetValue(LineBGEmptyProperty);
|
||||
set => SetValue(LineBGEmptyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBGAddProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, IBrush>(nameof(LineBGAdd), new SolidColorBrush(Color.FromArgb(60, 0, 255, 0)));
|
||||
|
||||
public IBrush LineBGAdd
|
||||
{
|
||||
get => GetValue(LineBGAddProperty);
|
||||
set => SetValue(LineBGAddProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> LineBGDeletedProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, IBrush>(nameof(LineBGDeleted), new SolidColorBrush(Color.FromArgb(60, 255, 0, 0)));
|
||||
|
||||
public IBrush LineBGDeleted
|
||||
{
|
||||
get => GetValue(LineBGDeletedProperty);
|
||||
set => SetValue(LineBGDeletedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> SecondaryLineBGAddProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, IBrush>(nameof(SecondaryLineBGAdd), new SolidColorBrush(Color.FromArgb(90, 0, 255, 0)));
|
||||
|
||||
public IBrush SecondaryLineBGAdd
|
||||
{
|
||||
get => GetValue(SecondaryLineBGAddProperty);
|
||||
set => SetValue(SecondaryLineBGAddProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> SecondaryLineBGDeletedProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, IBrush>(nameof(SecondaryLineBGDeleted), new SolidColorBrush(Color.FromArgb(80, 255, 0, 0)));
|
||||
|
||||
public IBrush SecondaryLineBGDeleted
|
||||
{
|
||||
get => GetValue(SecondaryLineBGDeletedProperty);
|
||||
set => SetValue(SecondaryLineBGDeletedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<IBrush> SecondaryFGProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, IBrush>(nameof(SecondaryFG), Brushes.Gray);
|
||||
|
||||
public IBrush SecondaryFG
|
||||
{
|
||||
get => GetValue(SecondaryFGProperty);
|
||||
set => SetValue(SecondaryFGProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Vector> SyncScrollOffsetProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, Vector>(nameof(SyncScrollOffset), Vector.Zero);
|
||||
|
||||
public Vector SyncScrollOffset
|
||||
{
|
||||
get => GetValue(SyncScrollOffsetProperty);
|
||||
set => SetValue(SyncScrollOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> UseSyntaxHighlightingProperty =
|
||||
AvaloniaProperty.Register<SingleSideTextDiffPresenter, bool>(nameof(UseSyntaxHighlighting), false);
|
||||
|
||||
public bool UseSyntaxHighlighting
|
||||
{
|
||||
get => GetValue(UseSyntaxHighlightingProperty);
|
||||
set => SetValue(UseSyntaxHighlightingProperty, value);
|
||||
}
|
||||
|
||||
protected override Type StyleKeyOverride => typeof(TextEditor);
|
||||
public ViewModels.TwoSideTextDiff DiffData => DataContext as ViewModels.TwoSideTextDiff;
|
||||
|
||||
public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument())
|
||||
{
|
||||
_lineStyleTransformer = new LineStyleTransformer(this);
|
||||
|
||||
IsReadOnly = true;
|
||||
ShowLineNumbers = false;
|
||||
|
||||
TextArea.LeftMargins.Add(new LineNumberMargin(this) { Margin = new Thickness(8, 0) });
|
||||
TextArea.LeftMargins.Add(new VerticalSeperatorMargin(this));
|
||||
TextArea.TextView.Margin = new Thickness(4, 0);
|
||||
TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
|
||||
TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
|
||||
TextArea.TextView.Options.EnableHyperlinks = false;
|
||||
TextArea.TextView.Options.EnableEmailHyperlinks = false;
|
||||
}
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
|
@ -745,12 +664,10 @@ namespace SourceGit.Views
|
|||
_scrollViewer = this.FindDescendantOfType<ScrollViewer>();
|
||||
if (_scrollViewer != null)
|
||||
{
|
||||
_scrollViewer.Offset = SyncScrollOffset;
|
||||
_scrollViewer.ScrollChanged += OnTextViewScrollChanged;
|
||||
_scrollViewer.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.OneWay));
|
||||
}
|
||||
|
||||
UpdateTextMate();
|
||||
|
||||
TextArea.PointerWheelChanged += OnTextAreaPointerWheelChanged;
|
||||
TextArea.TextView.ContextRequested += OnTextViewContextRequested;
|
||||
}
|
||||
|
@ -765,18 +682,31 @@ namespace SourceGit.Views
|
|||
_scrollViewer = null;
|
||||
}
|
||||
|
||||
if (_textMate != null)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
}
|
||||
|
||||
TextArea.PointerWheelChanged -= OnTextAreaPointerWheelChanged;
|
||||
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
|
||||
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnDataContextChanged(e);
|
||||
|
||||
if (DataContext is ViewModels.TwoSideTextDiff diff)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
var lines = IsOld ? diff.Old : diff.New;
|
||||
foreach (var line in lines)
|
||||
builder.AppendLine(line.Content);
|
||||
|
||||
Text = builder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextAreaPointerWheelChanged(object sender, PointerWheelEventArgs e)
|
||||
{
|
||||
if (!TextArea.IsFocused)
|
||||
|
@ -785,8 +715,8 @@ namespace SourceGit.Views
|
|||
|
||||
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||
{
|
||||
if (TextArea.IsFocused)
|
||||
SetCurrentValue(SyncScrollOffsetProperty, _scrollViewer.Offset);
|
||||
if (TextArea.IsFocused && DataContext is ViewModels.TwoSideTextDiff diff)
|
||||
diff.SyncScrollOffset = _scrollViewer.Offset;
|
||||
}
|
||||
|
||||
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
|
||||
|
@ -798,9 +728,7 @@ namespace SourceGit.Views
|
|||
var menu = new ContextMenu();
|
||||
var parentView = this.FindAncestorOfType<TextDiffView>();
|
||||
if (parentView != null)
|
||||
{
|
||||
parentView.FillContextMenuForWorkingCopyChange(menu, selection.StartPosition.Line, selection.EndPosition.Line, IsOld);
|
||||
}
|
||||
|
||||
var copy = new MenuItem();
|
||||
copy.Header = App.Text("Copy");
|
||||
|
@ -817,96 +745,11 @@ namespace SourceGit.Views
|
|||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
||||
if (change.Property == DiffDataProperty)
|
||||
{
|
||||
if (DiffData != null)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
if (IsOld)
|
||||
{
|
||||
foreach (var line in DiffData.Old)
|
||||
{
|
||||
builder.AppendLine(line.Content);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var line in DiffData.New)
|
||||
{
|
||||
builder.AppendLine(line.Content);
|
||||
}
|
||||
}
|
||||
|
||||
Text = builder.ToString();
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File);
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = string.Empty;
|
||||
}
|
||||
}
|
||||
else if (change.Property == SyncScrollOffsetProperty)
|
||||
{
|
||||
if (!TextArea.IsFocused && _scrollViewer != null)
|
||||
_scrollViewer.Offset = SyncScrollOffset;
|
||||
}
|
||||
else if (change.Property == UseSyntaxHighlightingProperty)
|
||||
{
|
||||
UpdateTextMate();
|
||||
}
|
||||
else if (change.Property.Name == "ActualThemeVariant" && change.NewValue != null)
|
||||
{
|
||||
Models.TextMateHelper.SetThemeByApp(_textMate);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextMate()
|
||||
{
|
||||
if (UseSyntaxHighlighting)
|
||||
{
|
||||
if (_textMate == null)
|
||||
{
|
||||
TextArea.TextView.LineTransformers.Remove(_lineStyleTransformer);
|
||||
_textMate = Models.TextMateHelper.CreateForEditor(this);
|
||||
TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
|
||||
|
||||
if (DiffData != null)
|
||||
Models.TextMateHelper.SetGrammarByFileName(_textMate, DiffData.File);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_textMate != null)
|
||||
{
|
||||
_textMate.Dispose();
|
||||
_textMate = null;
|
||||
GC.Collect();
|
||||
|
||||
TextArea.TextView.Redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TextMate.Installation _textMate;
|
||||
private readonly LineStyleTransformer _lineStyleTransformer = null;
|
||||
private ScrollViewer _scrollViewer = null;
|
||||
}
|
||||
|
||||
public partial class TextDiffView : UserControl
|
||||
{
|
||||
public static readonly StyledProperty<Models.TextDiff> TextDiffProperty =
|
||||
AvaloniaProperty.Register<TextDiffView, Models.TextDiff>(nameof(TextDiff), null);
|
||||
|
||||
public Models.TextDiff TextDiff
|
||||
{
|
||||
get => GetValue(TextDiffProperty);
|
||||
set => SetValue(TextDiffProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<bool> UseSideBySideDiffProperty =
|
||||
AvaloniaProperty.Register<TextDiffView, bool>(nameof(UseSideBySideDiff), false);
|
||||
|
||||
|
@ -916,13 +759,20 @@ namespace SourceGit.Views
|
|||
set => SetValue(UseSideBySideDiffProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Vector> SyncScrollOffsetProperty =
|
||||
AvaloniaProperty.Register<TextDiffView, Vector>(nameof(SyncScrollOffset));
|
||||
|
||||
public Vector SyncScrollOffset
|
||||
static TextDiffView()
|
||||
{
|
||||
get => GetValue(SyncScrollOffsetProperty);
|
||||
set => SetValue(SyncScrollOffsetProperty, value);
|
||||
UseSideBySideDiffProperty.Changed.AddClassHandler<TextDiffView>((v, e) =>
|
||||
{
|
||||
if (v.DataContext is Models.TextDiff diff)
|
||||
{
|
||||
diff.SyncScrollOffset = Vector.Zero;
|
||||
|
||||
if (v.UseSideBySideDiff)
|
||||
v.Content = new ViewModels.TwoSideTextDiff(diff);
|
||||
else
|
||||
v.Content = diff;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public TextDiffView()
|
||||
|
@ -932,6 +782,10 @@ namespace SourceGit.Views
|
|||
|
||||
public void FillContextMenuForWorkingCopyChange(ContextMenu menu, int startLine, int endLine, bool isOldSide)
|
||||
{
|
||||
var diff = DataContext as Models.TextDiff;
|
||||
if (diff == null)
|
||||
return;
|
||||
|
||||
var parentView = this.FindAncestorOfType<DiffView>();
|
||||
if (parentView == null)
|
||||
return;
|
||||
|
@ -951,7 +805,7 @@ namespace SourceGit.Views
|
|||
endLine = tmp;
|
||||
}
|
||||
|
||||
var selection = GetUnifiedSelection(startLine, endLine, isOldSide);
|
||||
var selection = GetUnifiedSelection(diff, startLine, endLine, isOldSide);
|
||||
if (!selection.HasChanges)
|
||||
return;
|
||||
|
||||
|
@ -1033,17 +887,17 @@ namespace SourceGit.Views
|
|||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
TextDiff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change, null, selection, false, tmpFile);
|
||||
}
|
||||
else if (!UseSideBySideDiff)
|
||||
{
|
||||
var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result();
|
||||
TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, false, tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result();
|
||||
TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, isOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, false, isOldSide, tmpFile);
|
||||
}
|
||||
|
||||
new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--cache --index").Exec();
|
||||
|
@ -1065,17 +919,17 @@ namespace SourceGit.Views
|
|||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
TextDiff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
|
||||
}
|
||||
else if (!UseSideBySideDiff)
|
||||
{
|
||||
var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result();
|
||||
TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result();
|
||||
TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
|
||||
}
|
||||
|
||||
new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--reverse").Exec();
|
||||
|
@ -1103,15 +957,15 @@ namespace SourceGit.Views
|
|||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.Index == Models.ChangeState.Added)
|
||||
{
|
||||
TextDiff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
}
|
||||
else if (!UseSideBySideDiff)
|
||||
{
|
||||
TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
|
||||
}
|
||||
|
||||
new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--cache --index --reverse").Exec();
|
||||
|
@ -1133,17 +987,17 @@ namespace SourceGit.Views
|
|||
var tmpFile = Path.GetTempFileName();
|
||||
if (change.WorkTree == Models.ChangeState.Untracked)
|
||||
{
|
||||
TextDiff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
|
||||
diff.GenerateNewPatchFromSelection(change, null, selection, true, tmpFile);
|
||||
}
|
||||
else if (!UseSideBySideDiff)
|
||||
{
|
||||
var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result();
|
||||
TextDiff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
diff.GeneratePatchFromSelection(change, treeGuid, selection, true, tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
var treeGuid = new Commands.QueryStagedFileBlobGuid(ctx.RepositoryPath, change.Path).Result();
|
||||
TextDiff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
|
||||
diff.GeneratePatchFromSelectionSingleSide(change, treeGuid, selection, true, isOldSide, tmpFile);
|
||||
}
|
||||
|
||||
new Commands.Apply(ctx.RepositoryPath, tmpFile, true, "nowarn", "--index --reverse").Exec();
|
||||
|
@ -1162,44 +1016,29 @@ namespace SourceGit.Views
|
|||
menu.Items.Add(new MenuItem() { Header = "-" });
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
base.OnDataContextChanged(e);
|
||||
|
||||
var data = TextDiff;
|
||||
if (data == null)
|
||||
var diff = DataContext as Models.TextDiff;
|
||||
if (diff == null)
|
||||
{
|
||||
Content = null;
|
||||
SyncScrollOffset = Vector.Zero;
|
||||
GC.Collect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (change.Property == TextDiffProperty)
|
||||
{
|
||||
if (UseSideBySideDiff)
|
||||
Content = new ViewModels.TwoSideTextDiff(TextDiff);
|
||||
Content = new ViewModels.TwoSideTextDiff(diff, Content as ViewModels.TwoSideTextDiff);
|
||||
else
|
||||
Content = TextDiff;
|
||||
|
||||
SetCurrentValue(SyncScrollOffsetProperty, TextDiff.SyncScrollOffset);
|
||||
}
|
||||
else if (change.Property == UseSideBySideDiffProperty)
|
||||
{
|
||||
if (UseSideBySideDiff)
|
||||
Content = new ViewModels.TwoSideTextDiff(TextDiff);
|
||||
else
|
||||
Content = TextDiff;
|
||||
|
||||
SetCurrentValue(SyncScrollOffsetProperty, Vector.Zero);
|
||||
}
|
||||
Content = diff;
|
||||
}
|
||||
|
||||
private Models.TextDiffSelection GetUnifiedSelection(int startLine, int endLine, bool isOldSide)
|
||||
private Models.TextDiffSelection GetUnifiedSelection(Models.TextDiff diff, int startLine, int endLine, bool isOldSide)
|
||||
{
|
||||
var rs = new Models.TextDiffSelection();
|
||||
var diff = TextDiff;
|
||||
|
||||
endLine = Math.Min(endLine, TextDiff.Lines.Count);
|
||||
endLine = Math.Min(endLine, diff.Lines.Count);
|
||||
if (Content is ViewModels.TwoSideTextDiff twoSides)
|
||||
{
|
||||
var target = isOldSide ? twoSides.Old : twoSides.New;
|
||||
|
@ -1233,8 +1072,8 @@ namespace SourceGit.Views
|
|||
|
||||
var firstContent = target[firstContentLine];
|
||||
var endContent = target[endContentLine];
|
||||
startLine = TextDiff.Lines.IndexOf(firstContent) + 1;
|
||||
endLine = TextDiff.Lines.IndexOf(endContent) + 1;
|
||||
startLine = diff.Lines.IndexOf(firstContent) + 1;
|
||||
endLine = diff.Lines.IndexOf(endContent) + 1;
|
||||
}
|
||||
|
||||
rs.StartLine = startLine;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
x:DataType="vm:WorkingCopy">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" MinWidth="300"/>
|
||||
<ColumnDefinition Width="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.WorkingCopyLeftWidth, Mode=TwoWay}" MinWidth="300"/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
@ -198,7 +198,9 @@
|
|||
Height="28"
|
||||
Margin="8,0,0,0"
|
||||
Padding="8,0"
|
||||
Command="{Binding Commit}"/>
|
||||
Command="{Binding Commit}"
|
||||
HotKey="{OnPlatform Ctrl+Enter, macOS=⌘+Enter}"
|
||||
ToolTip.Tip="{OnPlatform Ctrl+Enter, macOS=⌘+Enter}"/>
|
||||
|
||||
<Button Grid.Column="5"
|
||||
Classes="flat"
|
||||
|
@ -207,6 +209,8 @@
|
|||
Margin="8,0,0,0"
|
||||
Padding="8,0"
|
||||
Command="{Binding CommitWithPush}"
|
||||
HotKey="{OnPlatform Ctrl+Shift+Enter, macOS=⌘+Shift+Enter}"
|
||||
ToolTip.Tip="{OnPlatform Ctrl+Shift+Enter, macOS=⌘+Shift+Enter}"
|
||||
IsVisible="{Binding IsCommitWithPushVisible}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
|
Loading…
Reference in a new issue