Merge branch 'release/v8.28'

This commit is contained in:
leo 2024-09-02 09:55:29 +08:00
commit 775e4cfecc
No known key found for this signature in database
96 changed files with 1879 additions and 1427 deletions

View file

@ -7,7 +7,7 @@ Opensource Git GUI client.
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
* English/German/Português/简体中文/繁體中文
* English/Français/Deutsch/Português/简体中文/繁體中文
* Built-in light/dark themes
* Customize theme
* Visual commit graph

View file

@ -1 +1 @@
8.27
8.28

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

After

Width:  |  Height:  |  Size: 911 KiB

View file

@ -22,7 +22,6 @@
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
<StyleInclude Source="/Resources/Styles.axaml"/>
</Application.Styles>

View file

@ -98,7 +98,7 @@ namespace SourceGit
public static void OpenDialog(Window window)
{
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner})
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
window.ShowDialog(owner);
}

View file

@ -58,7 +58,7 @@ namespace SourceGit.Commands
public bool FileWithRevision(string file, string revision)
{
Args = $"checkout {revision} -- \"{file}\"";
Args = $"checkout --no-overlay {revision} -- \"{file}\"";
return Exec();
}

View file

@ -2,12 +2,12 @@
{
public class CherryPick : Command
{
public CherryPick(string repo, string commit, bool noCommit)
public CherryPick(string repo, string commits, bool noCommit)
{
var mode = noCommit ? "-n" : "--ff";
WorkingDirectory = repo;
Context = repo;
Args = $"cherry-pick {mode} {commit}";
Args = $"cherry-pick {mode} {commits}";
}
}
}

View file

@ -17,8 +17,9 @@ namespace SourceGit.Commands
public class ReadToEndResult
{
public bool IsSuccess { get; set; }
public string StdOut { get; set; }
public bool IsSuccess { get; set; } = false;
public string StdOut { get; set; } = "";
public string StdErr { get; set; } = "";
}
public enum EditorType
@ -198,18 +199,20 @@ namespace SourceGit.Commands
{
proc.Start();
}
catch
catch (Exception e)
{
return new ReadToEndResult()
{
IsSuccess = false,
StdOut = string.Empty,
StdErr = e.Message,
};
}
var rs = new ReadToEndResult()
{
StdOut = proc.StandardOutput.ReadToEnd(),
StdErr = proc.StandardError.ReadToEnd(),
};
proc.WaitForExit();

View file

@ -14,17 +14,22 @@ namespace SourceGit.Commands
_findFirstMerged = needFindHead;
}
public QueryCommits(string repo, int maxCount, string messageFilter, bool isFile)
public QueryCommits(string repo, string filter, Models.CommitSearchMethod method)
{
string search;
if (isFile)
if (method == Models.CommitSearchMethod.ByUser)
{
search = $"-- \"{messageFilter}\"";
search = $"-i --author=\"{filter}\" --committer=\"{filter}\"";
}
else if (method == Models.CommitSearchMethod.ByFile)
{
search = $"-- \"{filter}\"";
}
else
{
var argsBuilder = new StringBuilder();
var words = messageFilter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var words = filter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var word in words)
{
var escaped = word.Trim().Replace("\"", "\\\"", StringComparison.Ordinal);
@ -36,7 +41,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo;
Context = repo;
Args = $"log -{maxCount} --date-order --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s --branches --remotes " + search;
Args = $"log -1000 --date-order --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s --branches --remotes " + search;
_findFirstMerged = false;
}

View file

@ -6,15 +6,6 @@
{
WorkingDirectory = path;
Args = "rev-parse --show-toplevel";
RaiseError = false;
}
public string Result()
{
var rs = ReadToEnd().StdOut;
if (string.IsNullOrEmpty(rs))
return null;
return rs.Trim();
}
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
namespace SourceGit.Commands
{

View file

@ -10,7 +10,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo;
Context = repo;
Args = $"log --date-order --branches --remotes --since=\"{_statistics.Since()}\" --pretty=format:\"%ct$%cn\"";
Args = $"log --date-order --branches --remotes --since=\"{_statistics.Since()}\" --pretty=format:\"%ct$%an\"";
}
public Models.Statistics Result()

View file

@ -6,6 +6,13 @@ using Avalonia.Media;
namespace SourceGit.Models
{
public enum CommitSearchMethod
{
ByUser,
ByMessage,
ByFile,
}
public class Commit
{
public static double OpacityForNotMerged

View file

@ -191,6 +191,7 @@ namespace SourceGit.Models
}
isMerged = isMerged || l.IsMerged;
major.IsMerged = isMerged;
}
else
{
@ -202,12 +203,17 @@ namespace SourceGit.Models
}
// Create new curve for branch head
if (major == null && commit.Parents.Count > 0)
if (major == null)
{
offsetX += UNIT_WIDTH;
if (commit.Parents.Count > 0)
{
major = new PathHelper(commit.Parents[0], isMerged, colorIdx, new Point(offsetX, offsetY));
unsolved.Add(major);
temp.Paths.Add(major.Path);
}
colorIdx = (colorIdx + 1) % _penCount;
}
@ -216,11 +222,9 @@ namespace SourceGit.Models
int dotColor = 0;
if (major != null)
{
major.IsMerged = isMerged;
position = new Point(major.LastX, offsetY);
dotColor = major.Path.Color;
}
Dot anchor = new Dot() { Center = position, Color = dotColor };
if (commit.IsCurrentHead)
anchor.Type = DotType.Head;
@ -271,7 +275,7 @@ namespace SourceGit.Models
unsolved.Remove(l);
}
// Margins & merge state (used by datagrid).
// Margins & merge state (used by Views.Histories).
commit.IsMerged = isMerged;
commit.Margin = new Thickness(Math.Max(offsetX + HALF_WIDTH, oldCount * UNIT_WIDTH + H_MARGIN) + H_MARGIN, 0, 0, 0);

View file

@ -3,42 +3,44 @@ using System.Collections.Generic;
namespace SourceGit.Models
{
public class StatisticsSample
public class StatisticsSample(string name)
{
public string Name { get; set; }
public int Count { get; set; }
public string Name { get; set; } = name;
public int Count { get; set; } = 0;
}
public class StatisticsReport
{
public int Total { get; set; } = 0;
public List<StatisticsSample> Samples { get; set; } = new List<StatisticsSample>();
public List<StatisticsSample> ByCommitter { get; set; } = new List<StatisticsSample>();
public List<StatisticsSample> ByAuthor { get; set; } = new List<StatisticsSample>();
public void AddCommit(int index, string committer)
public void AddCommit(int index, string author)
{
Total++;
Samples[index].Count++;
if (_mapByCommitter.TryGetValue(committer, out var value))
if (_mapUsers.TryGetValue(author, out var value))
{
value.Count++;
}
else
{
var sample = new StatisticsSample() { Name = committer, Count = 1 };
_mapByCommitter.Add(committer, sample);
ByCommitter.Add(sample);
var sample = new StatisticsSample(author);
sample.Count++;
_mapUsers.Add(author, sample);
ByAuthor.Add(sample);
}
}
public void Complete()
{
ByCommitter.Sort((l, r) => r.Count - l.Count);
_mapByCommitter.Clear();
ByAuthor.Sort((l, r) => r.Count - l.Count);
_mapUsers.Clear();
}
private readonly Dictionary<string, StatisticsSample> _mapByCommitter = new Dictionary<string, StatisticsSample>();
private readonly Dictionary<string, StatisticsSample> _mapUsers = new Dictionary<string, StatisticsSample>();
}
public class Statistics
@ -53,79 +55,33 @@ namespace SourceGit.Models
_thisWeekStart = _today.AddSeconds(-(int)_today.DayOfWeek * 3600 * 24 - _today.Hour * 3600 - _today.Minute * 60 - _today.Second);
_thisWeekEnd = _thisWeekStart.AddDays(7);
string[] monthNames = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
for (int i = 0; i < monthNames.Length; i++)
{
Year.Samples.Add(new StatisticsSample
{
Name = monthNames[i],
Count = 0,
});
}
for (int i = 0; i < 12; i++)
Year.Samples.Add(new StatisticsSample(""));
var monthDays = DateTime.DaysInMonth(_today.Year, _today.Month);
for (int i = 0; i < monthDays; i++)
{
Month.Samples.Add(new StatisticsSample
{
Name = $"{i + 1}",
Count = 0,
});
}
string[] weekDayNames = [
"SUN",
"MON",
"TUE",
"WED",
"THU",
"FRI",
"SAT",
];
Month.Samples.Add(new StatisticsSample($"{i + 1}"));
string[] weekDayNames = [ "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" ];
for (int i = 0; i < weekDayNames.Length; i++)
{
Week.Samples.Add(new StatisticsSample
{
Name = weekDayNames[i],
Count = 0,
});
}
Week.Samples.Add(new StatisticsSample(weekDayNames[i]));
}
public string Since()
{
return _today.ToString("yyyy-01-01 00:00:00");
return _today.AddMonths(-11).ToString("yyyy-MM-01 00:00:00");
}
public void AddCommit(string committer, double timestamp)
public void AddCommit(string author, double timestamp)
{
var time = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
if (time.CompareTo(_thisWeekStart) >= 0 && time.CompareTo(_thisWeekEnd) < 0)
{
Week.AddCommit((int)time.DayOfWeek, committer);
}
Week.AddCommit((int)time.DayOfWeek, author);
if (time.Month == _today.Month)
{
Month.AddCommit(time.Day - 1, committer);
}
Month.AddCommit(time.Day - 1, author);
Year.AddCommit(time.Month - 1, committer);
Year.AddCommit(time.Month - 1, author);
}
public void Complete()
@ -133,6 +89,30 @@ namespace SourceGit.Models
Year.Complete();
Month.Complete();
Week.Complete();
// Year is start from 11 months ago from now.
var thisYear = _today.Year;
var start = _today.AddMonths(-11);
if (start.Month == 1)
{
for (int i = 0; i < 12; i++)
Year.Samples[i].Name = $"{thisYear}/{i + 1:00}";
}
else
{
var lastYearIdx = start.Month - 1;
var lastYearMonths = Year.Samples.GetRange(lastYearIdx, 12 - lastYearIdx);
for (int i = 0; i < lastYearMonths.Count; i++)
lastYearMonths[i].Name = $"{thisYear - 1}/{lastYearIdx + i + 1:00}";
var thisYearMonths = Year.Samples.GetRange(0, lastYearIdx);
for (int i = 0; i < thisYearMonths.Count; i++)
thisYearMonths[i].Name = $"{thisYear}/{i + 1:00}";
Year.Samples.Clear();
Year.Samples.AddRange(lastYearMonths);
Year.Samples.AddRange(thisYearMonths);
}
}
private readonly DateTime _today;

View file

@ -91,7 +91,7 @@ namespace SourceGit.Native
{
var dir = string.IsNullOrEmpty(workdir) ? "~" : workdir;
if (_terminal == null)
App.RaiseException(dir, $"Only supports gnome-terminal/konsole/xfce4-terminal/lxterminal/deepin-terminal!");
App.RaiseException(dir, $"Only supports gnome-terminal/konsole/xfce4-terminal/lxterminal/deepin-terminal/mate-terminal/foot!");
else
_terminal.Open(dir);
}
@ -159,6 +159,10 @@ namespace SourceGit.Native
test = Path.Combine(path, "mate-terminal");
if (File.Exists(test))
return new Terminal(test, "--working-directory=\"{0}\"");
test = Path.Combine(path, "foot");
if (File.Exists(test))
return new Terminal(test, "--working-directory=\"{0}\"");
}
return null;

View file

@ -88,6 +88,7 @@
<StreamGeometry x:Key="Icons.Repositories">M960 146v91C960 318 759 384 512 384S64 318 64 238V146C64 66 265 0 512 0s448 66 448 146zM960 352v206C960 638 759 704 512 704S64 638 64 558V352c96 66 272 97 448 97S864 418 960 352zm0 320v206C960 958 759 1024 512 1024S64 958 64 878V672c96 66 272 97 448 97S864 738 960 672z</StreamGeometry>
<StreamGeometry x:Key="Icons.Reset">M883 567l-128-128c-17-17-43-17-60 0l-128 128c-17 17-17 43 0 60 17 17 43 17 60 0l55-55V683c0 21-21 43-43 43H418c-13-38-43-64-77-77V375c51-17 85-64 85-119 0-73-60-128-128-128-73 0-128 55-128 128 0 55 34 102 85 119v269c-51 17-85 64-85 119 0 73 55 128 128 128 55 0 102-34 119-85H640c73 0 128-55 128-128v-111l55 55c9 9 17 13 30 13 13 0 21-4 30-13 17-13 17-43 0-55zM299 213c26 0 43 17 43 43 0 21-21 43-43 43-26 0-43-21-43-43 0-26 17-43 43-43zm0 597c-26 0-43-21-43-43 0-26 17-43 43-43s43 17 43 43c0 21-17 43-43 43zM725 384c-73 0-128-60-128-128 0-73 55-128 128-128s128 55 128 128c0 68-55 128-128 128zm0-171c-26 0-43 17-43 43s17 43 43 43 43-17 43-43-17-43-43-43z</StreamGeometry>
<StreamGeometry x:Key="Icons.Save">M293 122v244h439V146l171 175V829a73 73 0 01-73 73h-98V536H293v366H195a73 73 0 01-73-73V195a73 73 0 0173-73h98zm366 512v268H366V634h293zm-49 49h-195v73h195v-73zm49-561v171H366V122h293z</StreamGeometry>
<StreamGeometry x:Key="Icons.Scan">M0 551V472c0-11 9-19 19-19h984c11 0 19 9 19 19v79c0 11-9 19-19 19H19c-11 0-19-9-19-19zM114 154v240c0 11-9 19-19 19H19C9 413 0 404 0 394V79C0 35 35 0 79 0h315c11 0 19 9 19 19v75c0 11-9 19-19 19H154c-21 0-39 18-39 39zm795 0c0-22-17-39-39-39h-240c-11 0-19-9-19-19V19c0-11 9-19 19-19h315c43 0 79 35 79 79v315c0 11-9 19-19 19h-75c-11 0-19-9-19-19l-1-240zm0 716v-240c0-11 9-19 19-19h75c11 0 19 9 19 19v315c0 43-35 79-79 79h-315c-11 0-19-9-19-19v-75c0-11 9-19 19-19H870c21-1 39-18 39-40zm-795 0c0 21 18 39 39 39h240c11 0 19 9 19 19v75c0 11-9 19-19 19H79C35 1023 0 988 0 945v-315c0-11 9-19 19-19h75c11 0 19 9 19 19V870z</StreamGeometry>
<StreamGeometry x:Key="Icons.Search">M702 677 590 565a148 148 0 10-25 27L676 703zm-346-200a115 115 0 11115 115A115 115 0 01355 478z</StreamGeometry>
<StreamGeometry x:Key="Icons.Settings">M928 500a21 21 0 00-19-20L858 472a11 11 0 01-9-9c-1-6-2-13-3-19a11 11 0 015-12l46-25a21 21 0 0010-26l-8-22a21 21 0 00-24-13l-51 10a11 11 0 01-12-6c-3-6-6-11-10-17a11 11 0 011-13l34-39a21 21 0 001-28l-15-18a20 20 0 00-27-4l-45 27a11 11 0 01-13-1c-5-4-10-9-15-12a11 11 0 01-3-12l19-49a21 21 0 00-9-26l-20-12a21 21 0 00-27 6L650 193a9 9 0 01-11 3c-1-1-12-5-20-7a11 11 0 01-7-10l1-52a21 21 0 00-17-22l-23-4a21 21 0 00-24 14L532 164a11 11 0 01-11 7h-20a11 11 0 01-11-7l-17-49a21 21 0 00-24-15l-23 4a21 21 0 00-17 22l1 52a11 11 0 01-8 11c-5 2-15 6-19 7c-4 1-8 0-12-4l-33-40A21 21 0 00313 146l-20 12A21 21 0 00285 184l19 49a11 11 0 01-3 12c-5 4-10 8-15 12a11 11 0 01-13 1L228 231a21 21 0 00-27 4L186 253a21 21 0 001 28L221 320a11 11 0 011 13c-3 5-7 11-10 17a11 11 0 01-12 6l-51-10a21 21 0 00-24 13l-8 22a21 21 0 0010 26l46 25a11 11 0 015 12l0 3c-1 6-2 11-3 16a11 11 0 01-9 9l-51 8A21 21 0 0096 500v23A21 21 0 00114 544l51 8a11 11 0 019 9c1 6 2 13 3 19a11 11 0 01-5 12l-46 25a21 21 0 00-10 26l8 22a21 21 0 0024 13l51-10a11 11 0 0112 6c3 6 6 11 10 17a11 11 0 01-1 13l-34 39a21 21 0 00-1 28l15 18a20 20 0 0027 4l45-27a11 11 0 0113 1c5 4 10 9 15 12a11 11 0 013 12l-19 49a21 21 0 009 26l20 12a21 21 0 0027-6L374 832c3-3 7-5 10-4c7 3 12 5 20 7a11 11 0 018 10l-1 52a21 21 0 0017 22l23 4a21 21 0 0024-14l17-50a11 11 0 0111-7h20a11 11 0 0111 7l17 49a21 21 0 0020 15a19 19 0 004 0l23-4a21 21 0 0017-22l-1-52a11 11 0 018-10c8-3 13-5 18-7l1 0c6-2 9 0 11 3l34 41A21 21 0 00710 878l20-12a21 21 0 009-26l-18-49a11 11 0 013-12c5-4 10-8 15-12a11 11 0 0113-1l45 27a21 21 0 0027-4l15-18a21 21 0 00-1-28l-34-39a11 11 0 01-1-13c3-5 7-11 10-17a11 11 0 0112-6l51 10a21 21 0 0024-13l8-22a21 21 0 00-10-26l-46-25a11 11 0 01-5-12l0-3c1-6 2-11 3-16a11 11 0 019-9l51-8a21 21 0 0018-21v-23zm-565 188a32 32 0 01-51 5a270 270 0 011-363a32 32 0 0151 6l91 161a32 32 0 010 31zM512 782a270 270 0 01-57-6a32 32 0 01-20-47l92-160a32 32 0 0127-16h184a32 32 0 0130 41c-35 109-137 188-257 188zm15-328L436 294a32 32 0 0121-47a268 268 0 0155-6c120 0 222 79 257 188a32 32 0 01-30 41h-184a32 32 0 01-28-16z</StreamGeometry>
<StreamGeometry x:Key="Icons.SoftwareUpdate">M900 287c40 69 60 144 60 225s-20 156-60 225c-40 69-94 123-163 163-69 40-144 60-225 60s-156-20-225-60c-69-40-123-94-163-163C84 668 64 593 64 512s20-156 60-225 94-123 163-163c69-40 144-60 225-60s156 20 225 60 123 94 163 163zM762 512c0-9-3-16-9-22L578 315l-44-44c-6-6-13-9-22-9s-16 3-22 9l-44 44-176 176c-6 6-9 13-9 22s3 16 9 22l44 44c6 6 13 9 22 9s16-3 22-9l92-92v269c0 9 3 16 9 22 6 6 13 9 22 9h62c8 0 16-3 22-9 6-6 9-13 9-22V486l92 92c6 6 13 9 22 9 8 0 16-3 22-9l44-44c6-6 9-13 9-22z</StreamGeometry>

View file

@ -82,10 +82,9 @@
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Verwerfen</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Nichts tun</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stashen &amp; wieder anwenden</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Diesen Commit cherry-picken</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Alle Änderungen committen</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Stashes löschen</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Du versuchst alle Stashes zu löschen. Möchtest du wirklich fortfahren?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Remote Repository klonen</x:String>
@ -109,7 +108,8 @@
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Commit rückgängig machen</x:String>
<x:String x:Key="Text.CommitCM.Reword" xml:space="preserve">Umformulieren</x:String>
<x:String x:Key="Text.CommitCM.SaveAsPatch" xml:space="preserve">Als Patch speichern...</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Squash Commits</x:String>
<x:String x:Key="Text.CommitCM.Squash" xml:space="preserve">Squash in den Vorgänger</x:String>
<x:String x:Key="Text.CommitCM.SquashCommitsSinceThis" xml:space="preserve">Squash Nachfolger Commits bis hier</x:String>
<x:String x:Key="Text.CommitDetail.Changes" xml:space="preserve">ÄNDERUNGEN</x:String>
<x:String x:Key="Text.CommitDetail.Changes.Search" xml:space="preserve">Änderungen durchsuchen...</x:String>
<x:String x:Key="Text.CommitDetail.Files" xml:space="preserve">DATEIEN</x:String>
@ -148,6 +148,7 @@
<x:String x:Key="Text.Configure.User" xml:space="preserve">Benutzername</x:String>
<x:String x:Key="Text.Configure.User.Placeholder" xml:space="preserve">Benutzername für dieses Repository</x:String>
<x:String x:Key="Text.Copy" xml:space="preserve">Kopieren</x:String>
<x:String x:Key="Text.CopyAllText" xml:space="preserve">Kopiere gesamten Text</x:String>
<x:String x:Key="Text.CopyMessage" xml:space="preserve">COMMIT-NACHRICHT KOPIEREN</x:String>
<x:String x:Key="Text.CopyPath" xml:space="preserve">Pfad kopieren</x:String>
<x:String x:Key="Text.CopyFileName" xml:space="preserve">Dateinamen kopieren</x:String>
@ -246,6 +247,8 @@
<x:String x:Key="Text.FileCM.UseTheirs" xml:space="preserve">"Ihre" verwenden (checkout --theirs)</x:String>
<x:String x:Key="Text.FileCM.UseMine" xml:space="preserve">"Meine" verwenden (checkout --ours)</x:String>
<x:String x:Key="Text.FileHistory" xml:space="preserve">Datei Historie</x:String>
<x:String x:Key="Text.FileHistory.FileContent" xml:space="preserve">INHALT</x:String>
<x:String x:Key="Text.FileHistory.FileChange" xml:space="preserve">ÄNDERUNGEN</x:String>
<x:String x:Key="Text.Filter" xml:space="preserve">FILTER</x:String>
<x:String x:Key="Text.GitFlow" xml:space="preserve">Git-Flow</x:String>
<x:String x:Key="Text.GitFlow.DevelopBranch" xml:space="preserve">Development-Branch:</x:String>
@ -334,7 +337,6 @@
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Verwerfen</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialisiere Repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Pfad:</x:String>
<x:String x:Key="Text.Init.Tip" xml:space="preserve">Ungültiges Repository erkannt. `git init` auf diesem Pfad ausführen?</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase wird durchgeführt. Drücke 'Abbrechen' um den originalen HEAD wiederherzustellen.</x:String>
@ -381,7 +383,7 @@
<x:String x:Key="Text.Preference.Appearance.DefaultFont" xml:space="preserve">Standardschriftart</x:String>
<x:String x:Key="Text.Preference.Appearance.DefaultFontSize" xml:space="preserve">Standardschriftgröße</x:String>
<x:String x:Key="Text.Preference.Appearance.MonospaceFont" xml:space="preserve">Monospace-Schriftart</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Verwende nur die Monospace-Schriftart im Texteditor</x:String>
<x:String x:Key="Text.Preference.Appearance.OnlyUseMonoFontInEditor" xml:space="preserve">Verwende die Monospace-Schriftart nur im Texteditor</x:String>
<x:String x:Key="Text.Preference.Appearance.Theme" xml:space="preserve">Design</x:String>
<x:String x:Key="Text.Preference.Appearance.ThemeOverrides" xml:space="preserve">Design-Anpassungen</x:String>
<x:String x:Key="Text.Preference.Appearance.UseFixedTabWidth" xml:space="preserve">Fixe Tab-Breite in Titelleiste</x:String>
@ -531,7 +533,7 @@
<x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">Diese Version überspringen</x:String>
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">Software Update</x:String>
<x:String x:Key="Text.SelfUpdate.UpToDate" xml:space="preserve">Es sind momentan kein Updates verfügbar.</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash HEAD in Vorgänger</x:String>
<x:String x:Key="Text.Squash" xml:space="preserve">Squash Commits</x:String>
<x:String x:Key="Text.SSHKey" xml:space="preserve">SSH privater Schlüssel:</x:String>
<x:String x:Key="Text.SSHKey.Placeholder" xml:space="preserve">Pfad zum privaten SSH Schlüssel</x:String>
<x:String x:Key="Text.Start" xml:space="preserve">START</x:String>
@ -553,9 +555,9 @@
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">MONAT</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">WOCHE</x:String>
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">JAHR</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">JAHR</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">COMMITTERS: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTOREN: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULE</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Submodul hinzufügen</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Relativen Pfad kopieren</x:String>

View file

@ -79,10 +79,9 @@
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Discard</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Do Nothing</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Reapply</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick This Commit</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commit all changes</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Clear Stashes</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">You are trying to clear all stashes. Are you sure to continue?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Clone Remote Repository</x:String>
@ -95,6 +94,7 @@
<x:String x:Key="Text.Close" xml:space="preserve">CLOSE</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">Editor</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">Cherry-Pick This Commit</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">Cherry-Pick ...</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">Checkout Commit</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">Compare with HEAD</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">Compare with Worktree</x:String>
@ -124,6 +124,7 @@
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">PARENTS</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">REFS</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">SHA</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">Open in Browser</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">Enter commit subject</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">Description</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">Repository Configure</x:String>
@ -318,6 +319,7 @@
<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.DiscardSelected" xml:space="preserve">Discard selected changes</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard mode (Default)</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>
@ -335,7 +337,6 @@
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Discard</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialize Repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Path:</x:String>
<x:String x:Key="Text.Init.Tip" xml:space="preserve">Invalid repository detected. Run `git init` under this path?</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase in progress. Press 'Abort' to restore original HEAD.</x:String>
@ -525,6 +526,8 @@
<x:String x:Key="Text.Save" xml:space="preserve">SAVE</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">Save As...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">Patch has been saved successfully!</x:String>
<x:String x:Key="Text.ScanRepositories" xml:space="preserve">Scan Repositories</x:String>
<x:String x:Key="Text.ScanRepositories.RootDir" xml:space="preserve">Root Dir:</x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">Check for Updates...</x:String>
<x:String x:Key="Text.SelfUpdate.Available" xml:space="preserve">New version of this software is available: </x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">Check for updates failed!</x:String>
@ -555,9 +558,9 @@
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">MONTH</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">WEEK</x:String>
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">YEAR</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">YEAR</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">COMMITTERS: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTHORS: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULES</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Add Submodule</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Copy Relative Path</x:String>
@ -588,6 +591,7 @@
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">Open All Repositories</x:String>
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">Open Repository</x:String>
<x:String x:Key="Text.Welcome.OpenTerminal" xml:space="preserve">Open Terminal</x:String>
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">Rescan Repositories in Default Clone Dir</x:String>
<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>

View file

@ -83,10 +83,9 @@
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Rejeter</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Ne rien faire</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash et Réappliquer</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick ce commit</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit :</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s) :</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commit tous les changements</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">Cherry Pick</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Vider les Stashes</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Voulez-vous vider tous les stashes. Êtes-vous sûr de vouloir continuer ?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Cloner le dépôt distant</x:String>
@ -337,7 +336,6 @@
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Rejeter</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Initialize Repository</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Path:</x:String>
<x:String x:Key="Text.Init.Tip" xml:space="preserve">Invalid repository detected. Run `git init` under this path?</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge request in progress. Press 'Abort' to restore original HEAD.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase in progress. Press 'Abort' to restore original HEAD.</x:String>
@ -556,9 +554,9 @@
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">MONTH</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">WEEK</x:String>
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">YEAR</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">YEAR</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">COMMITTERS: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTHORS: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMODULES</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Add Submodule</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Copy Relative Path</x:String>

View file

@ -82,10 +82,9 @@
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">Descartar</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">Nada</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">Stash &amp; Reaplicar</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick Este Commit</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit:</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">Cherry-Pick</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">Commit(s):</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">Commitar todas as alterações</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">Cherry-Pick</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">Limpar Stashes</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">Você está tentando limpar todas as stashes. Tem certeza que deseja continuar?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">Clonar Repositório Remoto</x:String>
@ -332,7 +331,6 @@
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">Descartar</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">Inicializar Repositório</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">Caminho:</x:String>
<x:String x:Key="Text.Init.Tip" xml:space="preserve">Repositório inválido detectado. Executar `git init` neste caminho?</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">Cherry-Pick em andamento. Pressione 'Abort' para restaurar o HEAD original.</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">Merge em andamento. Pressione 'Abort' para restaurar o HEAD original.</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">Rebase em andamento. Pressione 'Abort' para restaurar o HEAD original.</x:String>
@ -549,9 +547,9 @@
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">COMMITTER</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">MÊS</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">SEMANA</x:String>
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">ANO</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">ANO</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">COMMITS: </x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">COMMITTERS: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">AUTORES: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">SUBMÓDULOS</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Adicionar Submódulo</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Copiar Caminho Relativo</x:String>

View file

@ -82,10 +82,9 @@
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">丢弃更改</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">不做处理</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">贮藏并自动恢复</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">挑选(cherry-pick)此提交</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交ID </x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">挑选提交</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表 </x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">提交变化</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">挑选提交</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">丢弃贮藏确认</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">您正在丢弃所有的贮藏,一经操作,无法回退,是否继续?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">克隆远程仓库</x:String>
@ -98,6 +97,7 @@
<x:String x:Key="Text.Close" xml:space="preserve">关闭</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">提交信息编辑器</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">挑选(cherry-pick)此提交</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">挑选(cherry-pick)...</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">检出此提交</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">与当前HEAD比较</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">与本地工作树比较</x:String>
@ -127,6 +127,7 @@
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">父提交</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">相关引用</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">提交指纹</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">浏览器中查看</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">填写提交信息主题</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">详细描述</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">仓库配置</x:String>
@ -321,6 +322,7 @@
<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.DiscardSelected" xml:space="preserve">丢弃选中的更改</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" 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>
@ -338,7 +340,6 @@
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">丢弃</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">初始化新仓库</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">路径 </x:String>
<x:String x:Key="Text.Init.Tip" xml:space="preserve">选择目录不是有效的Git仓库。是否需要在此目录执行`git init`操作?</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">挑选Cherry-Pick操作进行中。点击【终止】回滚到操作前的状态。</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">合并操作进行中。点击【终止】回滚到操作前的状态。</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">变基Rebase操作进行中。点击【终止】回滚到操作前的状态。</x:String>
@ -527,6 +528,8 @@
<x:String x:Key="Text.Save" xml:space="preserve">保 存</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">另存为...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">补丁已成功保存!</x:String>
<x:String x:Key="Text.ScanRepositories" xml:space="preserve">扫描仓库</x:String>
<x:String x:Key="Text.ScanRepositories.RootDir" xml:space="preserve">根路径 </x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">检测更新...</x:String>
<x:String x:Key="Text.SelfUpdate.Available" xml:space="preserve">检测到软件有版本更新: </x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">获取最新版本信息失败!</x:String>
@ -557,9 +560,9 @@
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">提交者</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">本月</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">本周</x:String>
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">本年</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">最近一年</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">提交次数: </x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">提交者: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">贡献者人数: </x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">子模块</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">添加子模块</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">复制路径</x:String>
@ -590,6 +593,7 @@
<x:String x:Key="Text.Welcome.OpenAllInNode" xml:space="preserve">打开所有包含仓库</x:String>
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">打开本地仓库</x:String>
<x:String x:Key="Text.Welcome.OpenTerminal" xml:space="preserve">打开终端</x:String>
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">重新扫描默认克隆路径下的仓库</x:String>
<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>

View file

@ -82,10 +82,9 @@
<x:String x:Key="Text.Checkout.LocalChanges.Discard" xml:space="preserve">捨棄變更</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.DoNothing" xml:space="preserve">不做處理</x:String>
<x:String x:Key="Text.Checkout.LocalChanges.StashAndReply" xml:space="preserve">擱置變更並自動復原</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">揀選 (cherry-pick) 此提交</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交編號:</x:String>
<x:String x:Key="Text.CherryPick" xml:space="preserve">揀選提交</x:String>
<x:String x:Key="Text.CherryPick.Commit" xml:space="preserve">提交列表:</x:String>
<x:String x:Key="Text.CherryPick.CommitChanges" xml:space="preserve">提交變更</x:String>
<x:String x:Key="Text.CherryPick.Title" xml:space="preserve">揀選提交</x:String>
<x:String x:Key="Text.ClearStashes" xml:space="preserve">捨棄擱置變更確認</x:String>
<x:String x:Key="Text.ClearStashes.Message" xml:space="preserve">您正在捨棄所有的擱置變更,一經操作便無法復原,是否繼續?</x:String>
<x:String x:Key="Text.Clone" xml:space="preserve">複製 (clone) 遠端存放庫</x:String>
@ -98,6 +97,7 @@
<x:String x:Key="Text.Close" xml:space="preserve">關閉</x:String>
<x:String x:Key="Text.CodeEditor" xml:space="preserve">提交訊息編輯器</x:String>
<x:String x:Key="Text.CommitCM.CherryPick" xml:space="preserve">揀選 (cherry-pick) 此提交</x:String>
<x:String x:Key="Text.CommitCM.CherryPickMultiple" xml:space="preserve">揀選 (cherry-pick)...</x:String>
<x:String x:Key="Text.CommitCM.Checkout" xml:space="preserve">簽出 (checkout) 此提交</x:String>
<x:String x:Key="Text.CommitCM.CompareWithHead" xml:space="preserve">與目前 HEAD 比較</x:String>
<x:String x:Key="Text.CommitCM.CompareWithWorktree" xml:space="preserve">與本機工作區比較</x:String>
@ -127,6 +127,7 @@
<x:String x:Key="Text.CommitDetail.Info.Parents" xml:space="preserve">前次提交</x:String>
<x:String x:Key="Text.CommitDetail.Info.Refs" xml:space="preserve">相關參照</x:String>
<x:String x:Key="Text.CommitDetail.Info.SHA" xml:space="preserve">提交編號</x:String>
<x:String x:Key="Text.CommitDetail.Info.WebLinks" xml:space="preserve">在瀏覽器中檢視</x:String>
<x:String x:Key="Text.CommitMessageTextBox.SubjectPlaceholder" xml:space="preserve">填寫提交訊息標題</x:String>
<x:String x:Key="Text.CommitMessageTextBox.MessagePlaceholder" xml:space="preserve">詳細描述</x:String>
<x:String x:Key="Text.Configure" xml:space="preserve">存放庫設定</x:String>
@ -137,7 +138,7 @@
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">電子郵件地址</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">Git 設定</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">Issue 追蹤</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增符合 Github Issue 規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增符合 GitHub Issue 規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增符合 Jira 規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.NewRule" xml:space="preserve">新增自訂規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.Regex" xml:space="preserve">符合 Issue 的正則表達式:</x:String>
@ -165,7 +166,7 @@
<x:String x:Key="Text.CreateBranch.Title" xml:space="preserve">建立本機分支</x:String>
<x:String x:Key="Text.CreateTag" xml:space="preserve">新增標籤...</x:String>
<x:String x:Key="Text.CreateTag.BasedOn" xml:space="preserve">標籤位於:</x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">使用 GPG 簽</x:String>
<x:String x:Key="Text.CreateTag.GPGSign" xml:space="preserve">使用 GPG 簽</x:String>
<x:String x:Key="Text.CreateTag.Message" xml:space="preserve">標籤描述:</x:String>
<x:String x:Key="Text.CreateTag.Message.Placeholder" xml:space="preserve">選填。</x:String>
<x:String x:Key="Text.CreateTag.Name" xml:space="preserve">標籤名稱:</x:String>
@ -321,9 +322,10 @@
<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.DiscardSelected" xml:space="preserve">捨棄選取的變更</x:String>
<x:String x:Key="Text.Hotkeys.Repo.GoHome" 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.StageOrUnstageSelected" xml:space="preserve">暫存或取消暫存選取的變更</x:String>
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">切換左邊欄為歷史搜尋模式</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewChanges" xml:space="preserve">顯示本機變更</x:String>
<x:String x:Key="Text.Hotkeys.Repo.ViewHistories" xml:space="preserve">顯示歷史記錄</x:String>
@ -338,7 +340,6 @@
<x:String x:Key="Text.Hunk.Discard" xml:space="preserve">捨棄</x:String>
<x:String x:Key="Text.Init" xml:space="preserve">初始化存放庫</x:String>
<x:String x:Key="Text.Init.Path" xml:space="preserve">路徑:</x:String>
<x:String x:Key="Text.Init.Tip" xml:space="preserve">選擇目錄並非有效的 Git 存放庫。是否要在此目錄執行 `git init` 以進行初始化?</x:String>
<x:String x:Key="Text.InProgress.CherryPick" xml:space="preserve">揀選 (cherry-pick) 操作進行中。點選 [中止] 復原到操作前的狀態。</x:String>
<x:String x:Key="Text.InProgress.Merge" xml:space="preserve">合併操作進行中。點選 [中止] 復原到操作前的狀態。</x:String>
<x:String x:Key="Text.InProgress.Rebase" xml:space="preserve">重定基底 (rebase) 操作進行中。點選 [中止] 復原到操作前的狀態。</x:String>
@ -410,14 +411,14 @@
<x:String x:Key="Text.Preference.Git.User.Placeholder" xml:space="preserve">預設 Git 使用者名稱</x:String>
<x:String x:Key="Text.Preference.Git.Version" xml:space="preserve">Git 版本</x:String>
<x:String x:Key="Text.Preference.Git.Invalid" xml:space="preserve">本軟體要求 Git 最低版本為 2.23.0</x:String>
<x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG 簽</x:String>
<x:String x:Key="Text.Preference.GPG.CommitEnabled" xml:space="preserve">啟用提交簽</x:String>
<x:String x:Key="Text.Preference.GPG.TagEnabled" xml:space="preserve">啟用標籤簽</x:String>
<x:String x:Key="Text.Preference.GPG.Format" xml:space="preserve">GPG 簽格式</x:String>
<x:String x:Key="Text.Preference.GPG" xml:space="preserve">GPG 簽</x:String>
<x:String x:Key="Text.Preference.GPG.CommitEnabled" xml:space="preserve">啟用提交簽</x:String>
<x:String x:Key="Text.Preference.GPG.TagEnabled" xml:space="preserve">啟用標籤簽</x:String>
<x:String x:Key="Text.Preference.GPG.Format" xml:space="preserve">GPG 簽格式</x:String>
<x:String x:Key="Text.Preference.GPG.Path" xml:space="preserve">可執行檔案路徑</x:String>
<x:String x:Key="Text.Preference.GPG.Path.Placeholder" xml:space="preserve">填寫 gpg.exe 所在路徑</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">使用者簽金鑰</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">填寫簽提交所使用的金鑰</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey" xml:space="preserve">使用者簽金鑰</x:String>
<x:String x:Key="Text.Preference.GPG.UserKey.Placeholder" xml:space="preserve">填寫簽提交所使用的金鑰</x:String>
<x:String x:Key="Text.Preference.DiffMerge" xml:space="preserve">對比/合併工具</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path" xml:space="preserve">安裝路徑</x:String>
<x:String x:Key="Text.Preference.DiffMerge.Path.Placeholder" xml:space="preserve">填寫可執行檔案所在路徑</x:String>
@ -528,9 +529,11 @@
<x:String x:Key="Text.Save" xml:space="preserve">儲存</x:String>
<x:String x:Key="Text.SaveAs" xml:space="preserve">另存新檔...</x:String>
<x:String x:Key="Text.SaveAsPatchSuccess" xml:space="preserve">修補檔已成功儲存!</x:String>
<x:String x:Key="Text.ScanRepositories" xml:space="preserve">掃描存放庫</x:String>
<x:String x:Key="Text.ScanRepositories.RootDir" xml:space="preserve">頂層目錄:</x:String>
<x:String x:Key="Text.SelfUpdate" xml:space="preserve">檢查更新...</x:String>
<x:String x:Key="Text.SelfUpdate.Available" xml:space="preserve">軟體有版本更新:</x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">取最新版本資訊失敗!</x:String>
<x:String x:Key="Text.SelfUpdate.Error" xml:space="preserve">取最新版本資訊失敗!</x:String>
<x:String x:Key="Text.SelfUpdate.GotoDownload" xml:space="preserve">下載</x:String>
<x:String x:Key="Text.SelfUpdate.IgnoreThisVersion" xml:space="preserve">忽略此版本</x:String>
<x:String x:Key="Text.SelfUpdate.Title" xml:space="preserve">軟體更新</x:String>
@ -544,7 +547,7 @@
<x:String x:Key="Text.Stash.IncludeUntracked" xml:space="preserve">包含未追蹤的檔案</x:String>
<x:String x:Key="Text.Stash.Message" xml:space="preserve">擱置變更訊息:</x:String>
<x:String x:Key="Text.Stash.Message.Placeholder" xml:space="preserve">選填,用於命名此擱置變更</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">擱置變更本機變更</x:String>
<x:String x:Key="Text.Stash.Title" xml:space="preserve">擱置本機變更</x:String>
<x:String x:Key="Text.StashCM.Apply" xml:space="preserve">套用 (apply)</x:String>
<x:String x:Key="Text.StashCM.Drop" xml:space="preserve">刪除 (drop)</x:String>
<x:String x:Key="Text.StashCM.Pop" xml:space="preserve">套用並刪除 (pop)</x:String>
@ -558,9 +561,9 @@
<x:String x:Key="Text.Statistics.Committer" xml:space="preserve">提交者</x:String>
<x:String x:Key="Text.Statistics.ThisMonth" xml:space="preserve">本月</x:String>
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">本週</x:String>
<x:String x:Key="Text.Statistics.ThisYear" xml:space="preserve">本年</x:String>
<x:String x:Key="Text.Statistics.MostRecentYear" xml:space="preserve">最近一年</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">提交次數:</x:String>
<x:String x:Key="Text.Statistics.TotalCommitters" xml:space="preserve">提交者:</x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">貢獻者人數:</x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">子模組</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">新增子模組</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">複製路徑</x:String>
@ -592,6 +595,7 @@
<x:String x:Key="Text.Welcome.OpenOrInit" xml:space="preserve">開啟本機存放庫</x:String>
<x:String x:Key="Text.Welcome.OpenTerminal" xml:space="preserve">開啟終端機</x:String>
<x:String x:Key="Text.Welcome.Search" xml:space="preserve">快速搜尋存放庫...</x:String>
<x:String x:Key="Text.Welcome.ScanDefaultCloneDir" xml:space="preserve">重新掃描預設複製 (clone) 目錄下的存放庫</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>

View file

@ -191,6 +191,38 @@
<Style Selector="FlyoutPresenter">
<Setter Property="MaxWidth" Value="1024"/>
<Setter Property="MaxHeight" Value="768"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Template">
<ControlTemplate>
<Grid>
<Border Background="{DynamicResource Brush.Popup}" BorderThickness="0" Margin="4" CornerRadius="{TemplateBinding CornerRadius}">
<Border.Effect>
<DropShadowEffect OffsetX="0" OffsetY="0" BlurRadius="4" Color="Black" Opacity=".6"/>
</Border.Effect>
</Border>
<Border Name="LayoutRoot"
Margin="4"
Padding="12"
Background="{DynamicResource Brush.Popup}"
BorderThickness="0"
CornerRadius="{TemplateBinding CornerRadius}">
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ContentPresenter x:Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch" />
</ScrollViewer>
</Border>
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Path">
@ -397,39 +429,6 @@
<Setter Property="Stroke" Value="Red"/>
</Style>
<Style Selector="Button.caption_button_macos">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style Selector="Button.caption_button_macos:nth-child(1)">
<Setter Property="Margin" Value="6,0,0,0"/>
</Style>
<Style Selector="Button.caption_button_macos Ellipse">
<Setter Property="Width" Value="14"/>
<Setter Property="Height" Value="14"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="StrokeThickness" Value=".5"/>
<Setter Property="Stroke" Value="#40000000"/>
</Style>
<Style Selector="Button.caption_button_macos Path">
<Setter Property="Width" Value="8"/>
<Setter Property="Height" Value="8"/>
<Setter Property="Fill" Value="Black"/>
<Setter Property="IsVisible" Value="False"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style Selector="Grid.caption_button_box:pointerover Button.caption_button_macos Path">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="Button.caption_button_macos /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.caption_button_macos:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button.caption_button">
<Setter Property="Width" Value="48"/>
<Setter Property="BorderThickness" Value="0"/>
@ -1296,22 +1295,6 @@
<Setter Property="Opacity" Value="1"/>
</Style>
<Style Selector="DataGrid /template/ Rectangle#PART_ColumnHeadersAndRowsSeparator">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="DataGridCell">
<Setter Property="MinHeight" Value="24"/>
</Style>
<Style Selector="DataGridCell:focus /template/ Grid#FocusVisual">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="DataGridRow /template/ Rectangle#PART_BottomGridLine">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="DataGridRow /template/ DataGridDetailsPresenter#PART_DetailsPresenter">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="NumericUpDown">
<Style Selector="^ /template/ ButtonSpinner#PART_Spinner">
<Setter Property="MinHeight" Value="0"/>

View file

@ -2,9 +2,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<Color x:Key="Color.MacOS.Close">#FFFF6059</Color>
<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">#00000000</Color>
<Color x:Key="Color.TitleBar">#FFCFDEEA</Color>
@ -37,9 +34,6 @@
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Color x:Key="Color.MacOS.Close">#FFFF5E56</Color>
<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>
@ -72,9 +66,6 @@
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<SolidColorBrush x:Key="Brush.MacOS.Close" Color="{DynamicResource Color.MacOS.Close}"/>
<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}"/>

View file

@ -41,13 +41,12 @@
<PackageReference Include="Avalonia" Version="11.1.3" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.3" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.3" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.1.3" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.1.3" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.1.0" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.1.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="TextMateSharp" Version="1.0.62" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.62" />
<PackageReference Include="TextMateSharp" Version="1.0.63" />
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.63" />
</ItemGroup>
<ItemGroup>

View file

@ -1,10 +1,12 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace SourceGit.ViewModels
{
public class CherryPick : Popup
{
public Models.Commit Target
public List<Models.Commit> Targets
{
get;
private set;
@ -16,10 +18,10 @@ namespace SourceGit.ViewModels
set;
}
public CherryPick(Repository repo, Models.Commit target)
public CherryPick(Repository repo, List<Models.Commit> targets)
{
_repo = repo;
Target = target;
Targets = targets;
AutoCommit = true;
View = new Views.CherryPick() { DataContext = this };
}
@ -27,11 +29,16 @@ namespace SourceGit.ViewModels
public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);
ProgressDescription = $"Cherry-Pick commit '{Target.SHA}' ...";
ProgressDescription = $"Cherry-Pick commit(s) ...";
return Task.Run(() =>
{
var succ = new Commands.CherryPick(_repo.FullPath, Target.SHA, !AutoCommit).Exec();
// Get commit SHAs reverted
var builder = new StringBuilder();
for (int i = Targets.Count - 1; i >= 0; i--)
builder.Append($"{Targets[i].SHA} ");
var succ = new Commands.CherryPick(_repo.FullPath, builder.ToString(), !AutoCommit).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});

View file

@ -250,8 +250,6 @@ namespace SourceGit.ViewModels
public ContextMenu CreateChangeContextMenu(Models.Change change)
{
var menu = new ContextMenu();
var diffWithMerger = new MenuItem();
diffWithMerger.Header = App.Text("DiffWithMerger");
diffWithMerger.Icon = App.CreateMenuIcon("Icons.OpenWith");
@ -264,49 +262,18 @@ namespace SourceGit.ViewModels
Task.Run(() => Commands.MergeTool.OpenForDiff(_repo.FullPath, toolType, toolPath, opt));
ev.Handled = true;
};
menu.Items.Add(diffWithMerger);
menu.Items.Add(new MenuItem { Header = "-" });
var fullPath = Path.Combine(_repo.FullPath, change.Path);
if (File.Exists(fullPath))
{
var resetToThisRevision = new MenuItem();
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}");
ev.Handled = true;
};
var resetToFirstParent = new MenuItem();
resetToFirstParent.Header = App.Text("ChangeCM.CheckoutFirstParentRevision");
resetToFirstParent.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToFirstParent.IsEnabled = _commit.Parents.Count > 0 && change.Index != Models.ChangeState.Added && change.Index != Models.ChangeState.Renamed;
resetToFirstParent.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}~1");
ev.Handled = true;
};
var explore = new MenuItem();
explore.Header = App.Text("RevealFile");
explore.Icon = App.CreateMenuIcon("Icons.Explore");
explore.IsEnabled = File.Exists(fullPath);
explore.Click += (_, ev) =>
{
Native.OS.OpenInFileManager(fullPath, true);
ev.Handled = true;
};
menu.Items.Add(resetToThisRevision);
menu.Items.Add(resetToFirstParent);
menu.Items.Add(new MenuItem { Header = "-" });
menu.Items.Add(explore);
menu.Items.Add(new MenuItem { Header = "-" });
}
if (change.Index != Models.ChangeState.Deleted)
{
var history = new MenuItem();
history.Header = App.Text("FileHistory");
history.Icon = App.CreateMenuIcon("Icons.Histories");
@ -320,6 +287,7 @@ namespace SourceGit.ViewModels
var blame = new MenuItem();
blame.Header = App.Text("Blame");
blame.Icon = App.CreateMenuIcon("Icons.Blame");
blame.IsEnabled = change.Index != Models.ChangeState.Deleted;
blame.Click += (_, ev) =>
{
var window = new Views.Blame() { DataContext = new Blame(_repo.FullPath, change.Path, _commit.SHA) };
@ -327,10 +295,39 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
var menu = new ContextMenu();
menu.Items.Add(diffWithMerger);
menu.Items.Add(explore);
menu.Items.Add(new MenuItem { Header = "-" });
menu.Items.Add(history);
menu.Items.Add(blame);
menu.Items.Add(new MenuItem { Header = "-" });
}
var resetToThisRevision = new MenuItem();
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}");
ev.Handled = true;
};
var resetToFirstParent = new MenuItem();
resetToFirstParent.Header = App.Text("ChangeCM.CheckoutFirstParentRevision");
resetToFirstParent.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToFirstParent.IsEnabled = _commit.Parents.Count > 0;
resetToFirstParent.Click += (_, ev) =>
{
if (change.Index == Models.ChangeState.Renamed)
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.OriginalPath, $"{_commit.SHA}~1");
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}~1");
ev.Handled = true;
};
menu.Items.Add(resetToThisRevision);
menu.Items.Add(resetToFirstParent);
menu.Items.Add(new MenuItem { Header = "-" });
var copyPath = new MenuItem();
copyPath.Header = App.Text("CopyPath");
@ -340,7 +337,6 @@ namespace SourceGit.ViewModels
App.CopyText(change.Path);
ev.Handled = true;
};
menu.Items.Add(copyPath);
var copyFileName = new MenuItem();
copyFileName.Header = App.Text("CopyFileName");
@ -350,25 +346,15 @@ namespace SourceGit.ViewModels
App.CopyText(Path.GetFileName(change.Path));
e.Handled = true;
};
menu.Items.Add(copyFileName);
menu.Items.Add(copyPath);
menu.Items.Add(copyFileName);
return menu;
}
public ContextMenu CreateRevisionFileContextMenu(Models.Object file)
{
var fullPath = Path.Combine(_repo.FullPath, file.Path);
var resetToThisRevision = new MenuItem();
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.IsEnabled = File.Exists(fullPath);
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(file.Path, $"{_commit.SHA}");
ev.Handled = true;
};
var explore = new MenuItem();
explore.Header = App.Text("RevealFile");
explore.Icon = App.CreateMenuIcon("Icons.Explore");
@ -390,12 +376,19 @@ namespace SourceGit.ViewModels
return;
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
try
{
var selected = await storageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
{
var saveTo = Path.Combine(selected[0].Path.LocalPath, Path.GetFileName(file.Path));
Commands.SaveRevisionFile.Run(_repo.FullPath, _commit.SHA, file.Path, saveTo);
}
}
catch (Exception e)
{
App.RaiseException(_repo.FullPath, $"Failed to save file: {e.Message}");
}
ev.Handled = true;
};
@ -421,6 +414,28 @@ namespace SourceGit.ViewModels
ev.Handled = true;
};
var resetToThisRevision = new MenuItem();
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.IsEnabled = File.Exists(fullPath);
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(file.Path, $"{_commit.SHA}");
ev.Handled = true;
};
var resetToFirstParent = new MenuItem();
resetToFirstParent.Header = App.Text("ChangeCM.CheckoutFirstParentRevision");
resetToFirstParent.Icon = App.CreateMenuIcon("Icons.File.Checkout");
var fileInChanges = _changes.Find(x => x.Path == file.Path);
var fileIndex = fileInChanges?.Index;
resetToFirstParent.IsEnabled = _commit.Parents.Count > 0 && fileIndex != Models.ChangeState.Renamed;
resetToFirstParent.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(file.Path, $"{_commit.SHA}~1");
ev.Handled = true;
};
var copyPath = new MenuItem();
copyPath.Header = App.Text("CopyPath");
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
@ -440,14 +455,15 @@ namespace SourceGit.ViewModels
};
var menu = new ContextMenu();
menu.Items.Add(resetToThisRevision);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(explore);
menu.Items.Add(saveAs);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(history);
menu.Items.Add(blame);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(resetToThisRevision);
menu.Items.Add(resetToFirstParent);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(copyPath);
menu.Items.Add(copyFileName);
return menu;
@ -529,7 +545,7 @@ namespace SourceGit.ViewModels
private static readonly HashSet<string> IMG_EXTS = new HashSet<string>()
{
".ico", ".bmp", ".jpg", ".png", ".jpeg"
".ico", ".bmp", ".jpg", ".png", ".jpeg", ".webp"
};
private Repository _repo = null;

View file

@ -139,7 +139,7 @@ namespace SourceGit.ViewModels
else if (latest.IsBinary)
{
var oldPath = string.IsNullOrEmpty(_option.OrgPath) ? _option.Path : _option.OrgPath;
var ext = Path.GetExtension(oldPath);
var ext = Path.GetExtension(_option.Path);
if (IMG_EXTS.Contains(ext))
{
@ -147,13 +147,14 @@ namespace SourceGit.ViewModels
if (_option.Revisions.Count == 2)
{
(imgDiff.Old, imgDiff.OldFileSize) = BitmapFromRevisionFile(_repo, _option.Revisions[0], oldPath);
(imgDiff.New, imgDiff.NewFileSize) = BitmapFromRevisionFile(_repo, _option.Revisions[1], oldPath);
(imgDiff.New, imgDiff.NewFileSize) = BitmapFromRevisionFile(_repo, _option.Revisions[1], _option.Path);
}
else
{
var fullPath = Path.Combine(_repo, _option.Path);
if (!oldPath.Equals("/dev/null", StringComparison.Ordinal))
(imgDiff.Old, imgDiff.OldFileSize) = BitmapFromRevisionFile(_repo, "HEAD", oldPath);
var fullPath = Path.Combine(_repo, _option.Path);
if (File.Exists(fullPath))
{
imgDiff.New = new Bitmap(fullPath);
@ -226,7 +227,7 @@ namespace SourceGit.ViewModels
private static readonly HashSet<string> IMG_EXTS = new HashSet<string>()
{
".ico", ".bmp", ".jpg", ".png", ".jpeg"
".ico", ".bmp", ".jpg", ".png", ".jpeg", ".webp"
};
private readonly string _repo;

View file

@ -186,7 +186,7 @@ namespace SourceGit.ViewModels
private static readonly HashSet<string> IMG_EXTS = new HashSet<string>()
{
".ico", ".bmp", ".jpg", ".png", ".jpeg"
".ico", ".bmp", ".jpg", ".png", ".jpeg", ".webp"
};
private readonly Repository _repo = null;

View file

@ -1,10 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using CommunityToolkit.Mvvm.ComponentModel;
@ -180,16 +180,76 @@ namespace SourceGit.ViewModels
}
}
public ContextMenu MakeContextMenu(DataGrid datagrid)
public ContextMenu MakeContextMenu(ListBox list)
{
if (datagrid.SelectedItems.Count != 1)
return null;
var current = _repo.CurrentBranch;
if (current == null)
return null;
var commit = (datagrid.SelectedItem as Models.Commit)!;
if (list.SelectedItems.Count > 1)
{
var selected = new List<Models.Commit>();
var canCherryPick = true;
foreach (var item in list.SelectedItems)
{
if (item is Models.Commit c)
{
selected.Add(c);
if (c.IsMerged || c.Parents.Count > 1)
canCherryPick = false;
}
}
var multipleMenu = new ContextMenu();
if (canCherryPick)
{
var cherryPickMultiple = new MenuItem();
cherryPickMultiple.Header = App.Text("CommitCM.CherryPickMultiple");
cherryPickMultiple.Icon = App.CreateMenuIcon("Icons.CherryPick");
cherryPickMultiple.Click += (_, e) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CherryPick(_repo, selected));
e.Handled = true;
};
multipleMenu.Items.Add(cherryPickMultiple);
multipleMenu.Items.Add(new MenuItem() { Header = "-" });
}
var copyMultipleSHAs = new MenuItem();
copyMultipleSHAs.Header = App.Text("CommitCM.CopySHA");
copyMultipleSHAs.Icon = App.CreateMenuIcon("Icons.Copy");
copyMultipleSHAs.Click += (_, e) =>
{
var builder = new StringBuilder();
foreach (var c in selected)
builder.AppendLine(c.SHA);
App.CopyText(builder.ToString());
e.Handled = true;
};
multipleMenu.Items.Add(copyMultipleSHAs);
var copyMultipleInfo = new MenuItem();
copyMultipleInfo.Header = App.Text("CommitCM.CopyInfo");
copyMultipleInfo.Icon = App.CreateMenuIcon("Icons.Copy");
copyMultipleInfo.Click += (_, e) =>
{
var builder = new StringBuilder();
foreach (var c in selected)
builder.AppendLine($"{c.SHA.Substring(0, 10)} - {c.Subject}");
App.CopyText(builder.ToString());
e.Handled = true;
};
multipleMenu.Items.Add(copyMultipleInfo);
return multipleMenu;
}
var commit = (list.SelectedItem as Models.Commit)!;
var menu = new ContextMenu();
var tags = new List<Models.Tag>();
@ -324,7 +384,7 @@ namespace SourceGit.ViewModels
cherryPick.Click += (_, e) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CherryPick(_repo, commit));
PopupHost.ShowPopup(new CherryPick(_repo, [commit]));
e.Handled = true;
};
menu.Items.Add(cherryPick);
@ -354,12 +414,11 @@ namespace SourceGit.ViewModels
return;
}
var toplevel = datagrid.FindAncestorOfType<Views.Launcher>();
if (toplevel == null)
return;
App.OpenDialog(new Views.InteractiveRebase()
{
DataContext = new InteractiveRebase(_repo, current, commit)
});
var dialog = new Views.InteractiveRebase() { DataContext = new InteractiveRebase(_repo, current, commit) };
dialog.ShowDialog(toplevel);
e.Handled = true;
};
menu.Items.Add(interactiveRebase);
@ -398,7 +457,7 @@ namespace SourceGit.ViewModels
}
else
{
datagrid.SelectedItems.Add(head);
list.SelectedItems.Add(head);
}
e.Handled = true;
@ -454,6 +513,8 @@ namespace SourceGit.ViewModels
return;
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
try
{
var selected = await storageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
{
@ -461,6 +522,11 @@ namespace SourceGit.ViewModels
if (succ)
App.SendNotification(_repo.FullPath, App.Text("SaveAsPatchSuccess"));
}
}
catch (Exception exception)
{
App.RaiseException(_repo.FullPath, $"Failed to save as patch: {exception.Message}");
}
e.Handled = true;
};

View file

@ -10,11 +10,18 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _targetPath, value);
}
public Init(string path, RepositoryNode parent)
public string Reason
{
get;
private set;
}
public Init(string path, RepositoryNode parent, string reason)
{
_targetPath = path;
_parentNode = parent;
Reason = string.IsNullOrEmpty(reason) ? "Invalid repository detected!" : reason;
View = new Views.Init() { DataContext = this };
}

View file

@ -35,8 +35,8 @@ namespace SourceGit.ViewModels
var pref = Preference.Instance;
if (!string.IsNullOrEmpty(startupRepo))
{
var root = new Commands.QueryRepositoryRootPath(startupRepo).Result();
if (string.IsNullOrEmpty(root))
var test = new Commands.QueryRepositoryRootPath(startupRepo).ReadToEnd();
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
Pages[0].Notifications.Add(new Models.Notification
{
@ -46,7 +46,7 @@ namespace SourceGit.ViewModels
return;
}
var normalized = root.Replace("\\", "/");
var normalized = test.StdOut.Trim().Replace("\\", "/");
var node = pref.FindOrAddNodeByRepositoryPath(normalized, null, false);
Welcome.Instance.Refresh();
OpenRepositoryInTab(node, null);

View file

@ -30,6 +30,12 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _repositorySidebarWidth, value);
}
public GridLength HistoriesAuthorColumnWidth
{
get => _historiesAuthorColumnWidth;
set => SetProperty(ref _historiesAuthorColumnWidth, value);
}
public GridLength WorkingCopyLeftWidth
{
get => _workingCopyLeftWidth;
@ -55,6 +61,7 @@ namespace SourceGit.ViewModels
}
private GridLength _repositorySidebarWidth = new GridLength(250, GridUnitType.Pixel);
private GridLength _historiesAuthorColumnWidth = new GridLength(120, 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);

View file

@ -309,7 +309,11 @@ namespace SourceGit.ViewModels
public Models.Commit SearchResultSelectedCommit
{
get => _searchResultSelectedCommit;
set => SetProperty(ref _searchResultSelectedCommit, value);
set
{
if (SetProperty(ref _searchResultSelectedCommit, value) && value != null)
NavigateToCommit(value.SHA);
}
}
public void Open()
@ -331,7 +335,15 @@ namespace SourceGit.ViewModels
_settings = new Models.RepositorySettings();
}
try
{
_watcher = new Models.Watcher(this);
}
catch (Exception ex)
{
App.RaiseException(string.Empty, $"Failed to start watcher for repository: '{_fullpath}'. You may need to press 'F5' to refresh repository manually!\n\nReason: {ex.Message}");
}
_histories = new Histories(this);
_workingCopy = new WorkingCopy(this);
_stashesPage = new StashesPage(this);
@ -348,10 +360,17 @@ namespace SourceGit.ViewModels
SelectedView = null; // Do NOT modify. Used to remove exists widgets for GC.Collect
var settingsSerialized = JsonSerializer.Serialize(_settings, JsonCodeGen.Default.RepositorySettings);
try
{
File.WriteAllText(Path.Combine(_gitDir, "sourcegit.settings"), settingsSerialized);
}
catch (DirectoryNotFoundException)
{
// Ignore
}
_settings = null;
_watcher.Dispose();
_watcher?.Dispose();
_histories.Cleanup();
_workingCopy.Cleanup();
_stashesPage.Cleanup();
@ -529,6 +548,7 @@ namespace SourceGit.ViewModels
return;
IsSearchLoadingVisible = true;
SearchResultSelectedCommit = null;
IsSearchCommitSuggestionOpen = false;
SearchCommitFilterSuggestion.Clear();
@ -539,29 +559,18 @@ namespace SourceGit.ViewModels
switch (_searchCommitFilterType)
{
case 0:
foreach (var c in _histories.Commits)
{
if (c.SHA.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase))
visible.Add(c);
}
var commit = new Commands.QuerySingleCommit(_fullpath, _searchCommitFilter).Result();
if (commit != null)
visible.Add(commit);
break;
case 1:
foreach (var c in _histories.Commits)
{
if (c.Author.Name.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Committer.Name.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Author.Email.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase)
|| c.Committer.Email.Contains(_searchCommitFilter, StringComparison.OrdinalIgnoreCase))
visible.Add(c);
}
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByUser).Result();
break;
case 2:
visible = new Commands.QueryCommits(_fullpath, 1000, _searchCommitFilter, false).Result();
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByMessage).Result();
break;
case 3:
visible = new Commands.QueryCommits(_fullpath, 1000, _searchCommitFilter, true).Result();
visible = new Commands.QueryCommits(_fullpath, _searchCommitFilter, Models.CommitSearchMethod.ByFile).Result();
break;
}
@ -580,19 +589,33 @@ namespace SourceGit.ViewModels
public void SetWatcherEnabled(bool enabled)
{
if (_watcher != null)
_watcher.SetEnabled(enabled);
_watcher?.SetEnabled(enabled);
}
public void MarkBranchesDirtyManually()
{
if (_watcher != null)
if (_watcher == null)
{
Task.Run(() =>
{
RefreshBranches();
RefreshCommits();
});
Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshWorktrees);
}
else
{
_watcher.MarkBranchDirtyManually();
}
}
public void MarkWorkingCopyDirtyManually()
{
if (_watcher != null)
if (_watcher == null)
Task.Run(RefreshWorkingCopyChanges);
else
_watcher.MarkWorkingCopyDirtyManually();
}
@ -787,9 +810,7 @@ namespace SourceGit.ViewModels
public void RefreshSubmodules()
{
var submodules = new Commands.QuerySubmodules(_fullpath).Result();
if (_watcher != null)
_watcher.SetSubmodules(submodules);
_watcher?.SetSubmodules(submodules);
Dispatcher.UIThread.Invoke(() => Submodules = submodules);
}

View file

@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Avalonia.Threading;
namespace SourceGit.ViewModels
{
public class ScanRepositories : Popup
{
public string RootDir
{
get;
private set;
}
public ScanRepositories(string rootDir)
{
GetManagedRepositories(Preference.Instance.RepositoryNodes, _managed);
RootDir = rootDir;
View = new Views.ScanRepositories() { DataContext = this };
}
public override Task<bool> Sure()
{
ProgressDescription = $"Scan repositories under '{RootDir}' ...";
return Task.Run(() =>
{
// If it is too fast, the panel will disappear very quickly, then we'll have a bad experience.
Task.Delay(500).Wait();
var rootDir = new DirectoryInfo(RootDir);
var founded = new List<string>();
GetUnmanagedRepositories(rootDir, founded, new EnumerationOptions()
{
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System,
IgnoreInaccessible = true,
});
Dispatcher.UIThread.Invoke(() =>
{
var normalizedRoot = rootDir.FullName.Replace("\\", "/");
foreach (var f in founded)
{
var parent = new DirectoryInfo(f).Parent!.FullName.Replace("\\", "/");
if (parent.Equals(normalizedRoot, StringComparison.Ordinal))
{
Preference.Instance.FindOrAddNodeByRepositoryPath(f, null, false);
}
else if (parent.StartsWith(normalizedRoot, StringComparison.Ordinal))
{
var relative = parent.Substring(normalizedRoot.Length).TrimStart('/');
var group = FindOrCreateGroupRecursive(Preference.Instance.RepositoryNodes, relative);
Preference.Instance.FindOrAddNodeByRepositoryPath(f, group, false);
}
else
{
// Should not happen.
}
}
Welcome.Instance.Refresh();
});
return true;
});
}
private void GetManagedRepositories(List<RepositoryNode> group, HashSet<string> repos)
{
foreach (var node in group)
{
if (node.IsRepository)
repos.Add(node.Id);
else
GetManagedRepositories(node.SubNodes, repos);
}
}
private void GetUnmanagedRepositories(DirectoryInfo dir, List<string> outs, EnumerationOptions opts, int depth = 0)
{
var subdirs = dir.GetDirectories("*", opts);
foreach (var subdir in subdirs)
{
SetProgressDescription($"Scanning {subdir.FullName}...");
var normalizedSelf = subdir.FullName.Replace("\\", "/");
if (_managed.Contains(normalizedSelf))
continue;
var gitDir = Path.Combine(subdir.FullName, ".git");
if (Directory.Exists(gitDir) || File.Exists(gitDir))
{
var test = new Commands.QueryRepositoryRootPath(subdir.FullName).ReadToEnd();
if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
{
var normalized = test.StdOut.Trim().Replace("\\", "/");
if (!_managed.Contains(normalizedSelf))
outs.Add(normalized);
continue;
}
}
if (depth < 8)
GetUnmanagedRepositories(subdir, outs, opts, depth + 1);
}
}
private RepositoryNode FindOrCreateGroupRecursive(List<RepositoryNode> collection, string path)
{
var idx = path.IndexOf('/');
if (idx < 0)
return FindOrCreateGroup(collection, path);
var name = path.Substring(0, idx);
var tail = path.Substring(idx + 1);
var parent = FindOrCreateGroup(collection, name);
return FindOrCreateGroupRecursive(parent.SubNodes, tail);
}
private RepositoryNode FindOrCreateGroup(List<RepositoryNode> collection, string name)
{
foreach (var node in collection)
{
if (node.Name.Equals(name, StringComparison.Ordinal))
return node;
}
var added = new RepositoryNode()
{
Id = Guid.NewGuid().ToString(),
Name = name,
IsRepository = false,
IsExpanded = true,
};
collection.Add(added);
collection.Sort((l, r) =>
{
if (l.IsRepository != r.IsRepository)
return l.IsRepository ? 1 : -1;
return string.Compare(l.Name, r.Name, StringComparison.Ordinal);
});
return added;
}
private HashSet<string> _managed = new HashSet<string>();
}
}

View file

@ -57,7 +57,11 @@ namespace SourceGit.ViewModels
return Task.Run(() =>
{
new Commands.Stash(_repo.FullPath).Push(jobs, Message);
CallUIThread(() => _repo.SetWatcherEnabled(true));
CallUIThread(() =>
{
_repo.MarkWorkingCopyDirtyManually();
_repo.SetWatcherEnabled(true);
});
return true;
});
}

View file

@ -1,7 +1,5 @@
using System.Threading.Tasks;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia.Collections;
using Avalonia.Controls;
@ -82,7 +83,7 @@ namespace SourceGit.ViewModels
}
}
public void InitRepository(string path, RepositoryNode parent)
public void InitRepository(string path, RepositoryNode parent, string reason)
{
if (!Preference.Instance.IsGitConfigured())
{
@ -91,7 +92,7 @@ namespace SourceGit.ViewModels
}
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Init(path, parent));
PopupHost.ShowPopup(new Init(path, parent, reason));
}
public void Clone()
@ -114,6 +115,17 @@ namespace SourceGit.ViewModels
Native.OS.OpenTerminal(null);
}
public void ScanDefaultCloneDir()
{
var defaultCloneDir = Preference.Instance.GitDefaultCloneDir;
if (string.IsNullOrEmpty(defaultCloneDir))
App.RaiseException(PopupHost.Active.GetId(), "The default clone dir haven't been configured!");
else if (!Directory.Exists(defaultCloneDir))
App.RaiseException(PopupHost.Active.GetId(), $"The default clone dir '{defaultCloneDir}' is not exists!");
else if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new ScanRepositories(defaultCloneDir));
}
public void ClearSearchFilter()
{
SearchFilter = string.Empty;

View file

@ -952,6 +952,16 @@ namespace SourceGit.ViewModels
e.Handled = true;
};
var history = new MenuItem();
history.Header = App.Text("FileHistory");
history.Icon = App.CreateMenuIcon("Icons.Histories");
history.Click += (_, e) =>
{
var window = new Views.FileHistories() { DataContext = new FileHistories(_repo, change.Path) };
window.Show();
e.Handled = true;
};
var copyPath = new MenuItem();
copyPath.Header = App.Text("CopyPath");
copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
@ -977,6 +987,8 @@ namespace SourceGit.ViewModels
menu.Items.Add(stash);
menu.Items.Add(patch);
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(history);
menu.Items.Add(new MenuItem() { Header = "-" });
var lfsEnabled = new Commands.LFS(_repo.FullPath).IsEnabled();
if (lfsEnabled)
@ -1320,7 +1332,7 @@ namespace SourceGit.ViewModels
PopupHost.ShowAndStartPopup(new Push(_repo, null));
}
_repo.MarkWorkingCopyDirtyManually();
_repo.MarkBranchesDirtyManually();
_repo.SetWatcherEnabled(true);
IsCommitting = false;
});

View file

@ -25,14 +25,10 @@
Data="{StaticResource Icons.Info}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -40,12 +36,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">

View file

@ -1,7 +1,5 @@
using System.Reflection;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
@ -28,11 +26,6 @@ namespace SourceGit.Views
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Close();
}
private void OnVisitAvaloniaUI(object _, PointerPressedEventArgs e)
{
Native.OS.OpenBrowser("https://www.avaloniaui.net/");

View file

@ -1,3 +1,4 @@
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
@ -18,9 +19,16 @@ namespace SourceGit.Views
return;
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
try
{
var selected = await toplevel.StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
TxtLocation.Text = selected[0].Path.LocalPath;
}
catch (Exception exception)
{
App.RaiseException(string.Empty, $"Failed to select location: {exception.Message}");
}
e.Handled = true;
}

View file

@ -25,14 +25,10 @@
Data="{StaticResource Icons.Password}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -40,12 +36,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<StackPanel Grid.Row="1" Margin="0,16" Orientation="Vertical">

View file

@ -28,14 +28,10 @@
Data="{StaticResource Icons.File.Ignore}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -43,54 +39,49 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Unchanged Files -->
<Grid Grid.Row="1">
<DataGrid Margin="8"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding Files}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="26"
<ListBox Margin="8"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Path Width="14" Height="14" Margin="8,0,4,0" Data="{StaticResource Icons.File}"/>
<TextBlock Text="{Binding}" Margin="4,0"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Background="{DynamicResource Brush.Contents}"
SelectionMode="Single"
ItemsSource="{Binding Files}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="26"/>
</Style>
</ListBox.Styles>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Classes="icon_button" Click="OnRemoveButtonClicked">
<Grid Height="26" ColumnDefinitions="26,*,30">
<Path Grid.Column="0" Width="14" Height="14" Margin="8,0,0,0" HorizontalAlignment="Center" Data="{StaticResource Icons.File}"/>
<Border Grid.Column="1" Margin="4,0" ClipToBounds="True">
<TextBlock Grid.Column="1" Text="{Binding}" HorizontalAlignment="Left"/>
</Border>
<Button Grid.Column="2" Classes="icon_button" Click="OnRemoveButtonClicked">
<Path Width="14" Height="14" Data="{StaticResource Icons.Clear}"/>
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<!-- Empty -->
<StackPanel Orientation="Vertical"

View file

@ -16,11 +16,6 @@ namespace SourceGit.Views
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Close();
}
private void OnRemoveButtonClicked(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.AssumeUnchangedManager vm && sender is Button button)

View file

@ -56,11 +56,11 @@
<TextBlock Grid.Column="1"
Text="{Binding Name}"
Classes="primary"
FontWeight="{Binding NameFontWeight}"/>
FontWeight="{Binding NameFontWeight}"
TextTrimming="CharacterEllipsis"/>
<!-- Tracking status -->
<v:BranchTreeNodeTrackStatusPresenter Grid.Column="2"
Margin="8,0"
VerticalAlignment="Center"
FontFamily="{DynamicResource Fonts.Monospace}"
FontSize="10"

View file

@ -161,8 +161,8 @@ namespace SourceGit.Views
if (_label != null)
{
context.DrawRectangle(Background, null, new RoundedRect(new Rect(0, 0, _label.Width + 18, 18), new CornerRadius(9)));
context.DrawText(_label, new Point(9, 9 - _label.Height * 0.5));
context.DrawRectangle(Background, null, new RoundedRect(new Rect(8, 0, _label.Width + 18, 18), new CornerRadius(9)));
context.DrawText(_label, new Point(17, 9 - _label.Height * 0.5));
}
}
@ -192,7 +192,7 @@ namespace SourceGit.Views
}
}
return _label != null ? new Size(_label.Width + 18, 18) : new Size(0, 0);
return _label != null ? new Size(_label.Width + 18 /* Padding */ + 16 /* Margin */, 18) : new Size(0, 0);
}
private FormattedText _label = null;

View file

@ -3,12 +3,13 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CaptionButtons">
x:Class="SourceGit.Views.CaptionButtons"
x:Name="ThisControl">
<StackPanel Orientation="Horizontal">
<Button Classes="caption_button" Click="MinimizeWindow">
<Button Classes="caption_button" Click="MinimizeWindow" IsVisible="{Binding !#ThisControl.IsCloseButtonOnly}">
<Path Data="{StaticResource Icons.Window.Minimize}"/>
</Button>
<Button Classes="caption_button max_or_restore_btn" Click="MaximizeOrRestoreWindow">
<Button Classes="caption_button max_or_restore_btn" Click="MaximizeOrRestoreWindow" IsVisible="{Binding !#ThisControl.IsCloseButtonOnly}">
<Path/>
</Button>
<Button Classes="caption_button" Click="CloseWindow">

View file

@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
@ -6,6 +7,15 @@ namespace SourceGit.Views
{
public partial class CaptionButtons : UserControl
{
public static readonly StyledProperty<bool> IsCloseButtonOnlyProperty =
AvaloniaProperty.Register<CaptionButtons, bool>(nameof(IsCloseButtonOnly));
public bool IsCloseButtonOnly
{
get => GetValue(IsCloseButtonOnlyProperty);
set => SetValue(IsCloseButtonOnlyProperty, value);
}
public CaptionButtons()
{
InitializeComponent();

View file

@ -3,25 +3,155 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.CaptionButtonsMacOS">
x:Class="SourceGit.Views.CaptionButtonsMacOS"
x:Name="ThisControl">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<Color x:Key="Color.MacOS.Close">#FFED6A5E</Color>
<Color x:Key="Color.MacOS.CloseFG">#FF69110A</Color>
<Color x:Key="Color.MacOS.ClosePressed">#FFB24F46</Color>
<Color x:Key="Color.MacOS.ClosePressedFG">#FF2E0402</Color>
<Color x:Key="Color.MacOS.Minimize">#FFF4BF4F</Color>
<Color x:Key="Color.MacOS.MinimizeFG">#FF8F591D</Color>
<Color x:Key="Color.MacOS.MinimizePressed">#FFB78F3A</Color>
<Color x:Key="Color.MacOS.MinimizePressedFG">#FF522A0A</Color>
<Color x:Key="Color.MacOS.Maximize">#FF61C554</Color>
<Color x:Key="Color.MacOS.MaximizeFG">#FF296017</Color>
<Color x:Key="Color.MacOS.MaximizePressed">#FF48943F</Color>
<Color x:Key="Color.MacOS.MaximizePressedFG">#FF102F07</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<Color x:Key="Color.MacOS.Close">#FFED6A5E</Color>
<Color x:Key="Color.MacOS.CloseFG">#FF8C1A10</Color>
<Color x:Key="Color.MacOS.ClosePressed">#FFF09389</Color>
<Color x:Key="Color.MacOS.ClosePressedFG">#FF69120A</Color>
<Color x:Key="Color.MacOS.Minimize">#FFF4BF4F</Color>
<Color x:Key="Color.MacOS.MinimizeFG">#FF8F591D</Color>
<Color x:Key="Color.MacOS.MinimizePressed">#FFFBEB74</Color>
<Color x:Key="Color.MacOS.MinimizePressedFG">#FF705F1B</Color>
<Color x:Key="Color.MacOS.Maximize">#FF61C554</Color>
<Color x:Key="Color.MacOS.MaximizeFG">#FF296017</Color>
<Color x:Key="Color.MacOS.MaximizePressed">#FF86F37F</Color>
<Color x:Key="Color.MacOS.MaximizePressedFG">#FF2C681A</Color>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<SolidColorBrush x:Key="Brush.MacOS.Close" Color="{DynamicResource Color.MacOS.Close}"/>
<SolidColorBrush x:Key="Brush.MacOS.CloseFG" Color="{DynamicResource Color.MacOS.CloseFG}"/>
<SolidColorBrush x:Key="Brush.MacOS.ClosePressed" Color="{DynamicResource Color.MacOS.ClosePressed}"/>
<SolidColorBrush x:Key="Brush.MacOS.ClosePressedFG" Color="{DynamicResource Color.MacOS.ClosePressedFG}"/>
<SolidColorBrush x:Key="Brush.MacOS.Minimize" Color="{DynamicResource Color.MacOS.Minimize}"/>
<SolidColorBrush x:Key="Brush.MacOS.MinimizeFG" Color="{DynamicResource Color.MacOS.MinimizeFG}"/>
<SolidColorBrush x:Key="Brush.MacOS.MinimizePressed" Color="{DynamicResource Color.MacOS.MinimizePressed}"/>
<SolidColorBrush x:Key="Brush.MacOS.MinimizePressedFG" Color="{DynamicResource Color.MacOS.MinimizePressedFG}"/>
<SolidColorBrush x:Key="Brush.MacOS.Maximize" Color="{DynamicResource Color.MacOS.Maximize}"/>
<SolidColorBrush x:Key="Brush.MacOS.MaximizeFG" Color="{DynamicResource Color.MacOS.MaximizeFG}"/>
<SolidColorBrush x:Key="Brush.MacOS.MaximizePressed" Color="{DynamicResource Color.MacOS.MaximizePressed}"/>
<SolidColorBrush x:Key="Brush.MacOS.MaximizePressedFG" Color="{DynamicResource Color.MacOS.MaximizePressedFG}"/>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="Button">
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style Selector="Button /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button>Grid>Ellipse">
<Setter Property="Width" Value="14"/>
<Setter Property="Height" Value="14"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="StrokeThickness" Value=".5"/>
<Setter Property="Stroke" Value="#40000000"/>
</Style>
<Style Selector="Button.close>Grid>Ellipse">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.Close}"/>
</Style>
<Style Selector="Button.minimize>Grid>Ellipse">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.Minimize}"/>
</Style>
<Style Selector="Button.maximize>Grid>Ellipse">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.Maximize}"/>
</Style>
<Style Selector="Button.close:pressed>Grid>Ellipse">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.ClosePressed}"/>
</Style>
<Style Selector="Button.minimize:pressed>Grid>Ellipse">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.MinimizePressed}"/>
</Style>
<Style Selector="Button.maximize:pressed>Grid>Ellipse">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.MaximizePressed}"/>
</Style>
<Style Selector="Button>Grid>Path">
<Setter Property="Stretch" Value="Fill"/>
<Setter Property="Fill" Value="Black"/>
<Setter Property="IsVisible" Value="False"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style Selector="Button.close>Grid>Path">
<Setter Property="Width" Value="6"/>
<Setter Property="Height" Value="6"/>
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.CloseFG}"/>
<Setter Property="Data" Value="{StaticResource Icons.MacOS.Close}"/>
</Style>
<Style Selector="Button.minimize>Grid>Path">
<Setter Property="Width" Value="8"/>
<Setter Property="Height" Value="2"/>
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.MinimizeFG}"/>
<Setter Property="Data" Value="{StaticResource Icons.MacOS.Minimize}"/>
</Style>
<Style Selector="Button.maximize>Grid>Path">
<Setter Property="Width" Value="6"/>
<Setter Property="Height" Value="6"/>
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.MaximizeFG}"/>
<Setter Property="Data" Value="{StaticResource Icons.MacOS.Maximize}"/>
</Style>
<Style Selector="Button.close:pressed>Grid>Path">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.ClosePressedFG}"/>
</Style>
<Style Selector="Button.minimize:pressed>Grid>Path">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.MinimizePressedFG}"/>
</Style>
<Style Selector="Button.maximize:pressed>Grid>Path">
<Setter Property="Fill" Value="{DynamicResource Brush.MacOS.MaximizePressedFG}"/>
</Style>
<Style Selector="Grid.caption_button_box:pointerover>StackPanel>Button>Grid>Path">
<Setter Property="IsVisible" Value="True"/>
</Style>
</UserControl.Styles>
<Grid Classes="caption_button_box">
<StackPanel Orientation="Horizontal">
<Button Classes="caption_button_macos" Click="CloseWindow" Margin="10,0,0,0">
<StackPanel Orientation="Horizontal" Margin="8,0,0,0">
<Button Classes="close" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
<Ellipse/>
<Path/>
</Grid>
</Button>
<Button Classes="caption_button_macos" Click="MinimizeWindow">
<Button Classes="minimize" Click="MinimizeWindow" IsVisible="{Binding !#ThisControl.IsCloseButtonOnly}">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Minimize}"/>
<Path Height="2" Width="8" Stretch="Fill" Fill="#404040" Data="{StaticResource Icons.MacOS.Minimize}"/>
<Ellipse/>
<Path/>
</Grid>
</Button>
<Button Classes="caption_button_macos" Click="MaximizeOrRestoreWindow">
<Button Classes="maximize" Click="MaximizeOrRestoreWindow" IsVisible="{Binding !#ThisControl.IsCloseButtonOnly}">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Maximize}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#404040" Data="{StaticResource Icons.MacOS.Maximize}"/>
<Ellipse/>
<Path/>
</Grid>
</Button>
</StackPanel>

View file

@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
@ -6,6 +7,15 @@ namespace SourceGit.Views
{
public partial class CaptionButtonsMacOS : UserControl
{
public static readonly StyledProperty<bool> IsCloseButtonOnlyProperty =
AvaloniaProperty.Register<CaptionButtonsMacOS, bool>(nameof(IsCloseButtonOnly));
public bool IsCloseButtonOnly
{
get => GetValue(IsCloseButtonOnlyProperty);
set => SetValue(IsCloseButtonOnlyProperty, value);
}
public CaptionButtonsMacOS()
{
InitializeComponent();
@ -32,9 +42,7 @@ namespace SourceGit.Views
private void CloseWindow(object _, RoutedEventArgs e)
{
var window = this.FindAncestorOfType<Window>();
if (window != null)
window.Close();
window?.Close();
e.Handled = true;
}
}

View file

@ -2,6 +2,7 @@
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:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@ -11,17 +12,51 @@
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.CherryPick}"/>
<Grid Margin="0,16,0,0" RowDefinitions="32,32" ColumnDefinitions="100,*">
<Grid Margin="0,16,0,0" ColumnDefinitions="100,*">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="32"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,0,8,0"
Text="{DynamicResource Text.CherryPick.Commit}"/>
<Grid Grid.Row="0" Grid.Column="1" ColumnDefinitions="Auto,Auto,*">
<ListBox Grid.Row="0" Grid.Column="1"
MinHeight="32" MaxHeight="100"
ItemsSource="{Binding Targets}"
Background="{DynamicResource Brush.Contents}"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
Padding="4"
CornerRadius="4"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="4,0"/>
<Setter Property="Height" Value="26"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<Grid ColumnDefinitions="14,Auto,*">
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
<TextBlock Grid.Column="1" Classes="primary" 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"/>
<TextBlock Grid.Column="1" FontFamily="{DynamicResource Fonts.Monospace}" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="6,0,4,0"/>
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox Grid.Row="1" Grid.Column="1"
Content="{DynamicResource Text.CherryPick.CommitChanges}"

View file

@ -1,3 +1,4 @@
using System;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
@ -18,9 +19,16 @@ namespace SourceGit.Views
if (toplevel == null)
return;
try
{
var selected = await toplevel.StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
TxtParentFolder.Text = selected[0].Path.LocalPath;
}
catch (Exception exception)
{
App.RaiseException(string.Empty, $"Failed to select parent folder: {exception.Message}");
}
e.Handled = true;
}

View file

@ -55,20 +55,23 @@
<!-- SHA -->
<TextBlock Grid.Row="0" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.SHA}" />
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
<SelectableTextBlock Classes="primary"
<TextBlock Classes="primary"
Text="{Binding SHA}"
Margin="12,0,4,0"
VerticalAlignment="Center"/>
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnOpenWebLink" IsVisible="{Binding #ThisControl.WebLinks, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Link}" Fill="{DynamicResource Brush.Link}"/>
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnCopyCommitSHA" ToolTip.Tip="{DynamicResource Text.Copy}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Copy}"/>
</Button>
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnOpenContainsIn" IsVisible="{Binding #ThisControl.SupportsContainsIn}" ToolTip.Tip="{DynamicResource Text.CommitDetail.Info.ContainsIn}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Relation}"/>
</Button>
</StackPanel>
<Button Classes="icon_button" Width="24" Cursor="Hand" Click="OnOpenWebLink" IsVisible="{Binding #ThisControl.WebLinks, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}" ToolTip.Tip="{DynamicResource Text.CommitDetail.Info.WebLinks}">
<Path Width="12" Height="12" Data="{StaticResource Icons.Link}" Fill="{DynamicResource Brush.Link}"/>
</Button>
</StackPanel>
<!-- PARENTS -->
<TextBlock Grid.Row="1" Grid.Column="0" Classes="info_label" Text="{DynamicResource Text.CommitDetail.Info.Parents}" IsVisible="{Binding Parents.Count, Converter={x:Static c:IntConverters.IsGreaterThanZero}}"/>
@ -114,6 +117,7 @@
Classes="primary"
Message="{Binding #ThisControl.Message}"
IssueTrackerRules="{Binding #ThisControl.IssueTrackerRules}"
HorizontalAlignment="Stretch"
TextWrapping="Wrap"/>
</Grid>
</StackPanel>

View file

@ -49,6 +49,14 @@ namespace SourceGit.Views
InitializeComponent();
}
private void OnCopyCommitSHA(object sender, RoutedEventArgs e)
{
if (sender is Button { DataContext: Models.Commit commit })
App.CopyText(commit.SHA);
e.Handled = true;
}
private void OnOpenWebLink(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.CommitDetail detail)

View file

@ -89,21 +89,24 @@ namespace SourceGit.Views
matches.Sort((l, r) => l.Start - r.Start);
_matches = matches;
int pos = 0;
var inlines = new List<Inline>();
var pos = 0;
foreach (var match in matches)
{
if (match.Start > pos)
Inlines.Add(new Run(message.Substring(pos, match.Start - pos)));
inlines.Add(new Run(message.Substring(pos, match.Start - pos)));
var link = new Run(message.Substring(match.Start, match.Length));
link.Classes.Add(match.IsCommitSHA ? "commit_link" : "issue_link");
Inlines.Add(link);
inlines.Add(link);
pos = match.Start + match.Length;
}
if (pos < message.Length)
Inlines.Add(new Run(message.Substring(pos)));
inlines.Add(new Run(message.Substring(pos)));
Inlines.AddRange(inlines);
}
}
@ -111,7 +114,23 @@ namespace SourceGit.Views
{
base.OnPointerMoved(e);
if (e.Pointer.Captured == null && _matches != null)
if (e.Pointer.Captured == this)
{
var relativeSelfY = e.GetPosition(this).Y;
if (relativeSelfY <= 0 || relativeSelfY > Bounds.Height)
return;
var scrollViewer = this.FindAncestorOfType<ScrollViewer>();
if (scrollViewer != null)
{
var relativeY = e.GetPosition(scrollViewer).Y;
if (relativeY <= 8)
scrollViewer.LineUp();
else if (relativeY >= scrollViewer.Bounds.Height - 8)
scrollViewer.LineDown();
}
}
else if (_matches != null)
{
var point = e.GetPosition(this) - new Point(Padding.Left, Padding.Top);
var x = Math.Min(Math.Max(point.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0));

View file

@ -172,11 +172,8 @@ namespace SourceGit.Views
switch (decorator.Type)
{
case Models.DecoratorType.CurrentBranchHead:
item.LabelBG = headBG;
geo = this.FindResource("Icons.Check") as StreamGeometry;
break;
case Models.DecoratorType.CurrentCommitHead:
item.LabelBG = branchBG;
item.LabelBG = headBG;
geo = this.FindResource("Icons.Check") as StreamGeometry;
break;
case Models.DecoratorType.RemoteBranchHead:

View file

@ -25,14 +25,10 @@
Data="{StaticResource Icons.Info}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -40,12 +36,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<StackPanel Grid.Row="1" Margin="0,16" Orientation="Vertical">

View file

@ -2,6 +2,7 @@
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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.DeleteMultipleBranches"
@ -17,56 +18,37 @@
BorderBrush="{DynamicResource Brush.Border1}"
CornerRadius="4"
Padding="4">
<DataGrid MaxHeight="200"
Background="Transparent"
<ListBox MaxHeight="200"
BorderThickness="0"
Background="Transparent"
ItemsSource="{Binding Targets}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="26"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Styles>
<Style Selector="DataGridRow">
<Setter Property="CornerRadius" Value="4" />
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="26"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
</ListBox.Styles>
<Style Selector="DataGridRow /template/ Border#RowBorder">
<Setter Property="ClipToBounds" Value="True" />
</Style>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<Style Selector="DataGridRow:pointerover /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource Brush.AccentHovered}" />
</Style>
<Style Selector="DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
<Setter Property="Fill" Value="{DynamicResource Brush.Accent}" />
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn Header="ICON">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Path Width="10" Height="10" Margin="4,0,8,0" Data="{StaticResource Icons.Branch}" />
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Branch">
<Grid Height="26" ColumnDefinitions="22,*">
<Path Grid.Column="0" Width="10" Height="10" Margin="4,0,8,0" Data="{StaticResource Icons.Branch}" />
<TextBlock Grid.Column="1" Text="{Binding FriendlyName}" Classes="primary" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="NAME">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FriendlyName}" ClipToBounds="True" Classes="primary" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
</Border>
<TextBlock Margin="4,8,0,0"

View file

@ -53,7 +53,7 @@
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0"
<ListBox Grid.Column="0"
Background="{DynamicResource Brush.Contents}"
BorderThickness="1"
Margin="8,4,4,8"
@ -61,24 +61,29 @@
ItemsSource="{Binding Commits}"
SelectedItem="{Binding SelectedCommit, Mode=TwoWay}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="50"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="50"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto">
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0" ClipToBounds="True"/>
<TextBlock Grid.Column="2"
Classes="primary"
Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
@ -94,10 +99,8 @@
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<GridSplitter Grid.Column="1"
MinWidth="1"

View file

@ -8,66 +8,117 @@
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Histories"
x:DataType="vm:Histories">
x:DataType="vm:Histories"
x:Name="ThisControl">
<v:LayoutableGrid RowDefinitions="*,3,*" ColumnDefinitions="*,3,*"
UseHorizontal="{Binding Source={x:Static vm:Preference.Instance}, Path=UseTwoColumnsLayoutInHistories}">
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<DataGrid x:Name="CommitDataGrid"
<Grid RowDefinitions="24,*">
<!-- Headers -->
<Border Grid.Row="0"
Background="{DynamicResource Brush.Window}"
BorderThickness="0,0,0,1"
BorderBrush="{DynamicResource Brush.Border0}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="100"/>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="{Binding #ThisControl.AuthorNameColumnWidth, Mode=TwoWay}" MinWidth="80"/>
<ColumnDefinition Width="96" MaxWidth="96" MinWidth="96"/>
<ColumnDefinition Width="156" MaxWidth="156" MinWidth="156"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Classes="table_header" Text="{DynamicResource Text.Histories.Header.GraphAndSubject}" HorizontalAlignment="Center"/>
<GridSplitter Grid.Column="1" Width="1" MinWidth="0.5" Background="{DynamicResource Brush.Border0}" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
<TextBlock Grid.Column="2" Classes="table_header" Text="{DynamicResource Text.Histories.Header.Author}" HorizontalAlignment="Center"/>
<Border Grid.Column="3" BorderThickness="1,0" BorderBrush="{DynamicResource Brush.Border0}" ClipToBounds="True">
<TextBlock Classes="table_header" Text="{DynamicResource Text.Histories.Header.SHA}" HorizontalAlignment="Center"/>
</Border>
<StackPanel Grid.Column="4" Orientation="Horizontal" HorizontalAlignment="Center">
<ToggleButton Classes="time_display_mode"
Width="10" Height="10"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=DisplayTimeAsPeriodInHistories, Mode=TwoWay}"/>
<TextBlock Classes="table_header" Margin="6,0,0,0" Text="{DynamicResource Text.Histories.Header.Time}"/>
</StackPanel>
</Grid>
</Border>
<!-- Commit Lists & Graph -->
<Grid Grid.Row="1">
<ListBox x:Name="CommitListContainer"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding Commits}"
SelectionMode="Extended"
SelectionMode="Multiple"
SelectedItem="{Binding AutoSelectedCommit, Mode=OneWay}"
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="Column"
Focusable="False"
RowHeight="28"
ColumnHeaderHeight="24"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
ClipboardCopyMode="None"
LayoutUpdated="OnCommitDataGridLayoutUpdated"
SelectionChanged="OnCommitDataGridSelectionChanged"
ContextRequested="OnCommitDataGridContextRequested"
DoubleTapped="OnCommitDataGridDoubleTapped"
KeyDown="OnCommitDataGridKeyDown">
<DataGrid.Styles>
<Style Selector="DataGridColumnHeader">
<Setter Property="MinHeight" Value="24"/>
LayoutUpdated="OnCommitListLayoutUpdated"
SelectionChanged="OnCommitListSelectionChanged"
ContextRequested="OnCommitListContextRequested"
DoubleTapped="OnCommitListDoubleTapped"
KeyDown="OnCommitListKeyDown">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="28"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{DynamicResource Brush.Window}"
BorderBrush="{DynamicResource Brush.Border0}"
BorderThickness="0,0,1,1">
<ContentPresenter x:Name="PART_ContentPresenter"
<Grid>
<Border Name="PART_Background"
Background="Transparent"
CornerRadius="{TemplateBinding CornerRadius}"
Opacity="0"/>
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"/>
</Border>
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Stretch" />
</Grid>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover /template/ Border#PART_Background">
<Setter Property="Background" Value="{DynamicResource Brush.AccentHovered}" />
<Setter Property="Opacity" Value=".5"/>
</Style>
</DataGrid.Styles>
<Style Selector="^:selected /template/ Border#PART_Background">
<Setter Property="Background" Value="{DynamicResource Brush.Accent}" />
<Setter Property="Opacity" Value=".65"/>
</Style>
<Style Selector="^:selected:pointerover /template/ Border#PART_Background">
<Setter Property="Background" Value="{DynamicResource Brush.Accent}" />
<Setter Property="Opacity" Value=".8"/>
</Style>
</Style>
</ListBox.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" CanUserResize="True">
<DataGridTemplateColumn.Header>
<TextBlock Classes="table_header" Text="{DynamicResource Text.Histories.Header.GraphAndSubject}"/>
</DataGridTemplateColumn.Header>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Commit}">
<Border Margin="{Binding Margin}">
<StackPanel Orientation="Horizontal" Margin="2,0,0,0">
<v:CommitStatusIndicator CurrentBranch="{Binding $parent[v:Histories].CurrentBranch}"
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<Grid Height="26">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="{Binding #ThisControl.AuthorNameColumnWidth, Mode=OneWay}"/>
<ColumnDefinition Width="96" MaxWidth="96" MinWidth="96"/>
<ColumnDefinition Width="156" MaxWidth="156" MinWidth="156"/>
</Grid.ColumnDefinitions>
<!-- Subject & REFS -->
<Border Grid.Column="0" Padding="{Binding Margin}" ClipToBounds="True">
<Grid ColumnDefinitions="Auto,Auto,*" Margin="2,0,4,0" ClipToBounds="True">
<v:CommitStatusIndicator Grid.Column="0"
CurrentBranch="{Binding $parent[v:Histories].CurrentBranch}"
AheadBrush="{DynamicResource Brush.Accent}"
BehindBrush="{DynamicResource Brush.FG1}"
VerticalAlignment="Center"/>
<v:CommitRefsPresenter IconBackground="{DynamicResource Brush.DecoratorIconBG}"
<v:CommitRefsPresenter Grid.Column="1"
IconBackground="{DynamicResource Brush.DecoratorIconBG}"
IconForeground="{DynamicResource Brush.DecoratorIcon}"
BranchNameBackground="{DynamicResource Brush.DecoratorBranch}"
HeadBranchNameBackground="{DynamicResource Brush.DecoratorHead}"
@ -78,84 +129,57 @@
VerticalAlignment="Center"
Refs="{Binding Decorators}"/>
<v:CommitSubjectPresenter Classes="primary"
<v:CommitSubjectPresenter Grid.Column="2"
Classes="primary"
Subject="{Binding Subject}"
IssueTrackerRules="{Binding $parent[v:Histories].IssueTrackerRules}"
Opacity="{Binding Opacity}"
FontWeight="{Binding FontWeight}"/>
</StackPanel>
FontWeight="{Binding FontWeight}"
Opacity="{Binding Opacity}"/>
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn CanUserResize="True" Width="120">
<DataGridTemplateColumn.Header>
<TextBlock Classes="table_header" Text="{DynamicResource Text.Histories.Header.Author}"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Commit}">
<Grid ColumnDefinitions="Auto,*" Margin="8,0">
<!-- Author -->
<Grid Grid.Column="1" ColumnDefinitions="20,*" IsHitTestVisible="False">
<v:Avatar Grid.Column="0"
Width="16" Height="16"
Margin="4,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsHitTestVisible="False"
User="{Binding Author}"
Opacity="{Binding Opacity}"/>
<TextBlock Grid.Column="1"
Classes="primary"
<Border Grid.Column="1" Padding="8,0,0,0" ClipToBounds="True">
<TextBlock Classes="primary"
Text="{Binding Author.Name}"
Margin="8,0,0,0"
Opacity="{Binding Opacity}"
FontWeight="{Binding FontWeight}"/>
FontWeight="{Binding FontWeight}"
HorizontalAlignment="Left"
Opacity="{Binding Opacity}"/>
</Border>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn CanUserResize="False" MinWidth="96">
<DataGridTemplateColumn.Header>
<TextBlock Classes="table_header" Text="{DynamicResource Text.Histories.Header.SHA}"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Commit}">
<!-- SHA -->
<Border Grid.Column="2" Padding="8,0" IsHitTestVisible="False" ClipToBounds="True">
<TextBlock Classes="primary"
Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
Margin="8,0"
HorizontalAlignment="Center"
Opacity="{Binding Opacity}"
FontWeight="{Binding FontWeight}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn CanUserResize="False" MinWidth="156">
<DataGridTemplateColumn.Header>
<StackPanel Orientation="Horizontal">
<ToggleButton Classes="time_display_mode"
Width="10" Height="10"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=DisplayTimeAsPeriodInHistories, Mode=TwoWay}"/>
<TextBlock Classes="table_header" Margin="6,0,0,0" Text="{DynamicResource Text.Histories.Header.Time}"/>
</StackPanel>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type m:Commit}">
<v:CommitTimeTextBlock Classes="primary"
Margin="8,0"
HorizontalAlignment="Center"
Opacity="{Binding Opacity}"
FontWeight="{Binding FontWeight}"
Opacity="{Binding Opacity}"/>
</Border>
<!-- COMMIT TIME -->
<Border Grid.Column="3" Padding="8,0" ClipToBounds="True" IsHitTestVisible="False">
<v:CommitTimeTextBlock Classes="primary"
HorizontalAlignment="Center"
FontWeight="{Binding FontWeight}"
Opacity="{Binding Opacity}"
Timestamp="{Binding CommitterTime}"
ShowAsDateTime="{Binding Source={x:Static vm:Preference.Instance}, Path=!DisplayTimeAsPeriodInHistories}"/>
</Border>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<v:CommitGraph x:Name="CommitGraph"
Graph="{Binding Graph}"
@ -163,6 +187,8 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
IsHitTestVisible="False"
ClipToBounds="True"/>
</Grid>
</Grid>
<!-- Fix memory leak -->
<v:LoadingIcon Width="48" Height="48" HorizontalAlignment="Center" VerticalAlignment="Center" IsVisible="{Binding IsLoading}"/>

View file

@ -6,7 +6,6 @@ using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
@ -212,23 +211,24 @@ namespace SourceGit.Views
matches.Sort((l, r) => l.Start - r.Start);
_matches = matches;
int pos = 0;
var inlines = new List<Inline>();
var pos = 0;
foreach (var match in matches)
{
if (match.Start > pos)
Inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
var link = new Run(subject.Substring(match.Start, match.Length));
link.Classes.Add("issue_link");
Inlines.Add(link);
inlines.Add(link);
pos = match.Start + match.Length;
}
if (pos < subject.Length)
Inlines.Add(new Run(subject.Substring(pos)));
inlines.Add(new Run(subject.Substring(pos)));
InvalidateTextLayout();
Inlines.AddRange(inlines);
}
}
@ -438,45 +438,32 @@ namespace SourceGit.Views
{
base.Render(context);
var grid = this.FindAncestorOfType<Histories>()?.CommitDataGrid;
if (grid == null)
return;
var graph = Graph;
if (graph == null)
return;
var rowsPresenter = grid.FindDescendantOfType<DataGridRowsPresenter>();
if (rowsPresenter == null)
var histories = this.FindAncestorOfType<Histories>();
if (histories == null)
return;
// Find the content display offset Y of binding DataGrid.
double rowHeight = grid.RowHeight;
double startY = 0;
foreach (var child in rowsPresenter.Children)
var list = histories.CommitListContainer;
if (list == null)
return;
// Calculate drawing area.
double width = Bounds.Width - 156 - 96 - histories.AuthorNameColumnWidth.Value;
double height = Bounds.Height;
double startY = list.Scroll?.Offset.Y ?? 0;
double endY = startY + height + 28;
// Apply scroll offset and clip.
using (context.PushClip(new Rect(0, 0, width, height)))
using (context.PushTransform(Matrix.CreateTranslation(0, -startY)))
{
if (child is DataGridRow { IsVisible: true, Bounds.Top: <= 0 } row && row.Bounds.Top > -rowHeight)
{
var test = rowHeight * row.GetIndex() - row.Bounds.Top;
if (startY < test)
startY = test;
}
}
var headerHeight = grid.ColumnHeaderHeight;
startY -= headerHeight;
// Apply scroll offset.
context.PushClip(new Rect(Bounds.Left, Bounds.Top + headerHeight, grid.Columns[0].ActualWidth, Bounds.Height));
context.PushTransform(Matrix.CreateTranslation(0, -startY));
// Calculate bounds.
var top = startY;
var bottom = startY + grid.Bounds.Height + rowHeight * 2;
// Draw contents
DrawCurves(context, graph, top, bottom);
DrawAnchors(context, graph, top, bottom);
DrawCurves(context, graph, startY, endY);
DrawAnchors(context, graph, startY, endY);
}
}
private void DrawCurves(DrawingContext context, Models.CommitGraph graph, double top, double bottom)
@ -601,6 +588,15 @@ namespace SourceGit.Views
public partial class Histories : UserControl
{
public static readonly StyledProperty<GridLength> AuthorNameColumnWidthProperty =
AvaloniaProperty.Register<Histories, GridLength>(nameof(AuthorNameColumnWidth), new GridLength(120));
public GridLength AuthorNameColumnWidth
{
get => GetValue(AuthorNameColumnWidthProperty);
set => SetValue(AuthorNameColumnWidthProperty, value);
}
public static readonly StyledProperty<Models.Branch> CurrentBranchProperty =
AvaloniaProperty.Register<Histories, Models.Branch>(nameof(CurrentBranch));
@ -636,9 +632,14 @@ namespace SourceGit.Views
return;
// Force scroll selected item (current head) into view. see issue #58
var datagrid = h.CommitDataGrid;
if (datagrid != null && datagrid.SelectedItems.Count == 1)
datagrid.ScrollIntoView(datagrid.SelectedItems[0], null);
var list = h.CommitListContainer;
if (list != null && list.SelectedItems.Count == 1)
list.ScrollIntoView(list.SelectedIndex);
});
AuthorNameColumnWidthProperty.Changed.AddClassHandler<Histories>((h, _) =>
{
h.CommitGraph.InvalidateVisual();
});
}
@ -647,43 +648,47 @@ namespace SourceGit.Views
InitializeComponent();
}
private void OnCommitDataGridLayoutUpdated(object _1, EventArgs _2)
private void OnCommitListLayoutUpdated(object _1, EventArgs _2)
{
var y = CommitListContainer.Scroll?.Offset.Y ?? 0;
if (y != _lastScrollY)
{
_lastScrollY = y;
CommitGraph.InvalidateVisual();
}
}
private void OnCommitDataGridSelectionChanged(object _, SelectionChangedEventArgs e)
private void OnCommitListSelectionChanged(object _, SelectionChangedEventArgs e)
{
if (DataContext is ViewModels.Histories histories)
{
histories.Select(CommitDataGrid.SelectedItems);
histories.Select(CommitListContainer.SelectedItems);
}
e.Handled = true;
}
private void OnCommitDataGridContextRequested(object sender, ContextRequestedEventArgs e)
private void OnCommitListContextRequested(object sender, ContextRequestedEventArgs e)
{
if (DataContext is ViewModels.Histories histories && sender is DataGrid datagrid)
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems: { Count: > 0 } } list)
{
var menu = histories.MakeContextMenu(datagrid);
datagrid.OpenContextMenu(menu);
var menu = histories.MakeContextMenu(list);
list.OpenContextMenu(menu);
}
e.Handled = true;
}
private void OnCommitDataGridDoubleTapped(object sender, TappedEventArgs e)
private void OnCommitListDoubleTapped(object sender, TappedEventArgs e)
{
if (DataContext is ViewModels.Histories histories && sender is DataGrid datagrid && datagrid.SelectedItems is { Count: 1 } selectedItems)
if (DataContext is ViewModels.Histories histories && sender is ListBox { SelectedItems: { Count: 1 } selected })
{
histories.DoubleTapped(selectedItems[0] as Models.Commit);
histories.DoubleTapped(selected[0] as Models.Commit);
}
e.Handled = true;
}
private void OnCommitDataGridKeyDown(object sender, KeyEventArgs e)
private void OnCommitListKeyDown(object sender, KeyEventArgs e)
{
if (sender is DataGrid grid &&
grid.SelectedItems is { Count: > 0 } selected &&
if (sender is ListBox { SelectedItems: { Count: > 0 } selected } &&
e.Key == Key.C &&
e.KeyModifiers.HasFlag(KeyModifiers.Control))
{
@ -698,5 +703,7 @@ namespace SourceGit.Views
e.Handled = true;
}
}
private double _lastScrollY = 0;
}
}

View file

@ -27,14 +27,10 @@
Data="{StaticResource Icons.Hotkeys}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -42,12 +38,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Body -->
@ -85,7 +78,7 @@
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
Margin="0,8"/>
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
<TextBlock Grid.Row="0" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Ctrl+Shift+H, macOS=⌘+⇧+H}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.GoHome}" />
@ -101,17 +94,20 @@
<TextBlock Grid.Row="4" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Ctrl+3, macOS=⌘+3}"/>
<TextBlock Grid.Row="4" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.ViewStashes}" />
<TextBlock Grid.Row="5" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Space, macOS=␣}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Space/Enter, macOS=␣/Enter}"/>
<TextBlock Grid.Row="5" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.StageOrUnstageSelected}" />
<TextBlock Grid.Row="6" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Ctrl+Enter, macOS=⌘+Enter}"/>
<TextBlock Grid.Row="6" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Commit}" />
<TextBlock Grid.Row="6" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Delete/Backspace, macOS=⌫}"/>
<TextBlock Grid.Row="6" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.DiscardSelected}" />
<TextBlock Grid.Row="7" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Ctrl+Shift+Enter, macOS=⌘+⇧+Enter}"/>
<TextBlock Grid.Row="7" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.CommitAndPush}" />
<TextBlock Grid.Row="7" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Ctrl+Enter, macOS=⌘+Enter}"/>
<TextBlock Grid.Row="7" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Commit}" />
<TextBlock Grid.Row="8" Grid.Column="0" Classes="primary bold" Text="F5"/>
<TextBlock Grid.Row="8" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
<TextBlock Grid.Row="8" Grid.Column="0" Classes="primary bold" Text="{OnPlatform Ctrl+Shift+Enter, macOS=⌘+⇧+Enter}"/>
<TextBlock Grid.Row="8" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.CommitAndPush}" />
<TextBlock Grid.Row="9" Grid.Column="0" Classes="primary bold" Text="F5"/>
<TextBlock Grid.Row="9" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
</Grid>
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"

View file

@ -1,5 +1,4 @@
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
@ -14,10 +13,5 @@ namespace SourceGit.Views
{
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Close();
}
}
}

View file

@ -10,7 +10,12 @@
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.Init}"/>
<Grid Margin="0,16,8,0" RowDefinitions="28,28" ColumnDefinitions="120,*">
<Grid Margin="0,16,8,0" ColumnDefinitions="100,*">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="Auto" MinHeight="32"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Init.Path}"
HorizontalAlignment="Right" VerticalAlignment="Center"
@ -18,8 +23,9 @@
<TextBlock Grid.Row="0" Grid.Column="1"
Text="{Binding TargetPath}"/>
<TextBlock Grid.Row="1" Grid.Column="1"
Text="{DynamicResource Text.Init.Tip}"
Foreground="{DynamicResource Brush.FG2}"/>
Foreground="{DynamicResource Brush.FG2}"
Text="{Binding Reason}"
TextWrapping="Wrap"/>
</Grid>
</StackPanel>
</UserControl>

View file

@ -28,14 +28,10 @@
Data="{StaticResource Icons.InteractiveRebase}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -43,12 +39,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Operation Information -->
@ -66,39 +59,41 @@
<!-- Body -->
<Border Grid.Row="2" Margin="8,0,8,8" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}">
<Grid RowDefinitions="*,3,*">
<DataGrid Grid.Row="0"
<ListBox Grid.Row="0"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding Items}"
SelectionMode="Single"
SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="28"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
KeyDown="OnDataGridKeyDown">
<DataGrid.Columns>
<DataGridTemplateColumn Width="16" Header="DragHandler">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<Border Background="Transparent"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
KeyDown="OnItemsListBoxKeyDown">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="28"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:InteractiveRebaseItem">
<Grid ColumnDefinitions="16,110,*,40,100,96,156,32,32">
<!-- Drag & Drop Anchor -->
<Border Grid.Column="0" Background="Transparent"
Margin="4,0,0,0"
Loaded="OnSetupRowHeaderDragDrop"
PointerPressed="OnRowHeaderPointerPressed">
<Path Width="14" Height="14" Data="{StaticResource Icons.Move}" Fill="{DynamicResource Brush.FG2}"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Option">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<Button Opacity="1" Margin="4,0,0,0" Padding="8,2" Background="Transparent">
<!-- Action -->
<Button Grid.Column="1" Opacity="1" Margin="4,0,0,0" Padding="8,2" Background="Transparent">
<Button.Flyout>
<MenuFlyout Placement="BottomEdgeAlignedLeft" VerticalOffset="-4">
<MenuItem InputGesture="P" Command="{Binding SetAction}" CommandParameter="{x:Static m:InteractiveRebaseAction.Pick}">
@ -180,14 +175,9 @@
<TextBlock Classes="primary" Margin="8,0" Text="{Binding Action, Converter={x:Static c:InteractiveRebaseActionConverters.ToName}}"/>
</StackPanel>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" Header="SUBJECT">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<StackPanel Orientation="Horizontal">
<!-- Subject -->
<StackPanel Grid.Column="2" Orientation="Horizontal" ClipToBounds="True">
<Button Classes="icon_button" IsVisible="{Binding Action, Converter={x:Static c:InteractiveRebaseActionConverters.CanEditMessage}}">
<Button.Flyout>
<Flyout Placement="BottomEdgeAlignedLeft">
@ -200,69 +190,41 @@
</Button>
<TextBlock Classes="primary" Text="{Binding Subject}" Margin="8,0,0,0"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="AVATAR">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<v:Avatar Width="16" Height="16"
<!-- Avatar -->
<v:Avatar Grid.Column="3"
Width="16" Height="16"
Margin="16,0,8,0"
VerticalAlignment="Center"
IsHitTestVisible="False"
User="{Binding Commit.Author}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MaxWidth="100" Header="AUTHOR">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<TextBlock Classes="primary" Text="{Binding Commit.Author.Name}" Margin="0,0,8,0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Author -->
<Border Grid.Column="4" ClipToBounds="True">
<TextBlock Classes="primary" Text="{Binding Commit.Author.Name}" HorizontalAlignment="Left"/>
</Border>
<DataGridTemplateColumn Header="SHA">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<TextBlock Classes="primary"
<!-- Commit SHA -->
<TextBlock Grid.Column="5" Classes="primary"
Text="{Binding Commit.SHA, Converter={x:Static c:StringConverters.ToShortSHA}}"
Margin="12,0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="TIME">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<TextBlock Classes="primary" Text="{Binding Commit.CommitterTimeStr}" Margin="8,0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!-- Commit Time -->
<TextBlock Grid.Column="6" Classes="primary" Text="{Binding Commit.CommitterTimeStr}" Margin="8,0"/>
<DataGridTemplateColumn Width="32" Header="MOVE UP">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<Button Classes="icon_button" Click="OnMoveItemUp" ToolTip.Tip="{DynamicResource Text.InteractiveRebase.MoveUp}">
<!-- MoveUp Button -->
<Button Grid.Column="7" Classes="icon_button" Click="OnMoveItemUp" ToolTip.Tip="{DynamicResource Text.InteractiveRebase.MoveUp}">
<Path Width="14" Height="14" Margin="0,4,0,0" Data="{StaticResource Icons.Up}"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="32" Header="MOVE DOWN">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="{x:Type vm:InteractiveRebaseItem}">
<Button Classes="icon_button" Click="OnMoveItemDown" ToolTip.Tip="{DynamicResource Text.InteractiveRebase.MoveDown}">
<!-- MoveDown Button -->
<Button Grid.Column="8" Classes="icon_button" Click="OnMoveItemDown" ToolTip.Tip="{DynamicResource Text.InteractiveRebase.MoveDown}">
<Path Width="14" Height="14" Margin="0,4,0,0" Data="{StaticResource Icons.Down}"/>
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<v:LoadingIcon Grid.Row="0" Width="48" Height="48" HorizontalAlignment="Center" VerticalAlignment="Center" IsVisible="{Binding IsLoading}"/>

View file

@ -43,6 +43,7 @@ namespace SourceGit.Views
private void OnRowHeaderDragOver(object sender, DragEventArgs e)
{
if (DataContext is ViewModels.InteractiveRebase vm &&
e.Data.Contains("InteractiveRebaseItem") &&
e.Data.Get("InteractiveRebaseItem") is ViewModels.InteractiveRebaseItem src &&
sender is Border { DataContext: ViewModels.InteractiveRebaseItem dst } border &&
src != dst)
@ -88,9 +89,9 @@ namespace SourceGit.Views
}
}
private void OnDataGridKeyDown(object sender, KeyEventArgs e)
private void OnItemsListBoxKeyDown(object sender, KeyEventArgs e)
{
var item = (sender as DataGrid)?.SelectedItem as ViewModels.InteractiveRebaseItem;
var item = (sender as ListBox)?.SelectedItem as ViewModels.InteractiveRebaseItem;
if (item == null)
return;

View file

@ -2,6 +2,7 @@
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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@ -26,14 +27,10 @@
Data="{StaticResource Icons.Lock}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -41,72 +38,55 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Locked Files -->
<Grid Grid.Row="1">
<DataGrid Margin="8"
<ListBox Margin="8"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding Locks}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="26"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Path Width="14" Height="14" Margin="8,0,4,0" Data="{StaticResource Icons.File}"/>
<TextBlock Text="{Binding File}" Margin="4,0"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="26"/>
</Style>
</ListBox.Styles>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding User}" Padding="16,0"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Classes="icon_button" Click="OnUnlockButtonClicked" ToolTip.Tip="{DynamicResource Text.GitLFS.Locks.Unlock}">
<ListBox.ItemTemplate>
<DataTemplate DataType="m:LFSLock">
<Grid ColumnDefinitions="26,*,100,32,32">
<Path Grid.Column="0" Width="14" Height="14" Margin="8,0,4,0" Data="{StaticResource Icons.File}"/>
<Border Grid.Column="1" Margin="4,0" ClipToBounds="True">
<TextBlock Text="{Binding File}" HorizontalAlignment="Left"/>
</Border>
<Border Grid.Column="2" Margin="8,0" ClipToBounds="True">
<TextBlock Text="{Binding User}" HorizontalAlignment="Left"/>
</Border>
<Button Grid.Column="3" Classes="icon_button" Click="OnUnlockButtonClicked" ToolTip.Tip="{DynamicResource Text.GitLFS.Locks.Unlock}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Unlock}"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Classes="icon_button" Click="OnForceUnlockButtonClicked" ToolTip.Tip="{DynamicResource Text.GitLFS.Locks.UnlockForce}">
<Button Grid.Column="4" Classes="icon_button" Click="OnForceUnlockButtonClicked" ToolTip.Tip="{DynamicResource Text.GitLFS.Locks.UnlockForce}">
<Path Width="14" Height="14" Fill="Red" Data="{StaticResource Icons.Unlock}"/>
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<!-- Empty -->
<StackPanel Orientation="Vertical"

View file

@ -16,11 +16,6 @@ namespace SourceGit.Views
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Close();
}
private void OnUnlockButtonClicked(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.LFSLocks vm && sender is Button button)

View file

@ -83,6 +83,9 @@ namespace SourceGit.Views
if (vm == null)
return;
// We should clear all unhandled key modifiers.
_unhandledModifiers = KeyModifiers.None;
// Ctrl+Shift+P opens preference dialog (macOS use hotkeys in system menu bar)
if (!OperatingSystem.IsMacOS() && e.KeyModifiers == (KeyModifiers.Control | KeyModifiers.Shift) && e.Key == Key.P)
{

View file

@ -216,7 +216,8 @@ namespace SourceGit.Views
private void DropTab(object sender, DragEventArgs e)
{
if (e.Data.Get("MovedTab") is ViewModels.LauncherPage moved &&
if (e.Data.Contains("MovedTab") &&
e.Data.Get("MovedTab") is ViewModels.LauncherPage moved &&
sender is Border { DataContext: ViewModels.LauncherPage to } &&
to != moved)
{

View file

@ -29,14 +29,10 @@
Margin="10,0,0,0"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -44,9 +40,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2" Classes="caption_button" Click="CloseWindow" IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Body -->

View file

@ -125,12 +125,7 @@ namespace SourceGit.Views
}
}
private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
protected override void OnClosing(WindowClosingEventArgs e)
{
var config = new Commands.Config(null).ListAll();
SetIfChanged(config, "user.name", DefaultUser);
@ -144,7 +139,12 @@ namespace SourceGit.Views
if (!GPGFormat.Value.Equals("ssh", StringComparison.Ordinal))
SetIfChanged(config, $"gpg.{GPGFormat.Value}.program", GPGExecutableFile);
Close();
base.OnClosing(e);
}
private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{
BeginMoveDrag(e);
}
private async void SelectThemeOverrideFile(object _, RoutedEventArgs e)
@ -186,12 +186,19 @@ namespace SourceGit.Views
private async void SelectDefaultCloneDir(object _1, RoutedEventArgs _2)
{
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
try
{
var selected = await StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
{
ViewModels.Preference.Instance.GitDefaultCloneDir = selected[0].Path.LocalPath;
}
}
catch (Exception e)
{
App.RaiseException(string.Empty, $"Failed to select default clone directory: {e.Message}");
}
}
private async void SelectGPGExecutable(object _1, RoutedEventArgs _2)
{

View file

@ -257,7 +257,7 @@
SelectionMode="Single"
ContextRequested="OnSubmoduleContextRequested"
DoubleTapped="OnDoubleTappedSubmodule"
PropertyChanged="OnLeftSidebarDataGridPropertyChanged"
PropertyChanged="OnLeftSidebarListBoxPropertyChanged"
IsVisible="{Binding IsSubmoduleGroupExpanded, Mode=OneWay}">
<ListBox.Styles>
<Style Selector="ListBoxItem">
@ -312,7 +312,7 @@
SelectionMode="Single"
ContextRequested="OnWorktreeContextRequested"
DoubleTapped="OnDoubleTappedWorktree"
PropertyChanged="OnLeftSidebarDataGridPropertyChanged"
PropertyChanged="OnLeftSidebarListBoxPropertyChanged"
IsVisible="{Binding IsWorktreeGroupExpanded, Mode=OneWay}">
<ListBox.Styles>
<Style Selector="ListBoxItem">
@ -445,48 +445,53 @@
</ComboBox>
</Grid>
<DataGrid Grid.Row="2"
<ListBox Grid.Row="2"
ItemsSource="{Binding SearchedCommits}"
SelectionMode="Single"
SelectedItem="{Binding SearchResultSelectedCommit, Mode=OneWay}"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="50"
SelectedItem="{Binding SearchResultSelectedCommit, Mode=TwoWay}"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
Background="{DynamicResource Brush.Contents}"
CornerRadius="4"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"
SelectionChanged="OnSearchResultDataGridSelectionChanged">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="50"/>
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent" />
</Style>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource Brush.AccentHovered}" />
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4">
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4" Background="Transparent">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*,Auto,Auto">
<v:Avatar Width="16" Height="16"
VerticalAlignment="Center"
IsHitTestVisible="False"
User="{Binding Author}"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0"/>
<v:Avatar Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" IsHitTestVisible="False" User="{Binding Author}"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Author.Name}" Margin="8,0,0,0" ClipToBounds="True"/>
<TextBlock Grid.Column="2" Classes="primary" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="8,0,0,0"/>
<TextBlock Grid.Column="3" Classes="primary" Text="{Binding AuthorTimeShortStr}" Foreground="{DynamicResource Brush.FG2}" Margin="8,0,0,0"/>
</Grid>
<TextBlock Grid.Row="1" Text="{Binding Subject}" VerticalAlignment="Bottom"/>
<TextBlock Grid.Row="1" Classes="primary" Text="{Binding Subject}" VerticalAlignment="Bottom"/>
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<Path Grid.Row="2"
HorizontalAlignment="Center" VerticalAlignment="Center"
@ -604,6 +609,7 @@
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Histories">
<v:Histories CurrentBranch="{Binding Repo.CurrentBranch}"
AuthorNameColumnWidth="{Binding Source={x:Static vm:Preference.Instance}, Path=Layout.HistoriesAuthorColumnWidth, Mode=TwoWay}"
IssueTrackerRules="{Binding Repo.Settings.IssueTrackerRules}"
NavigationId="{Binding NavigationId}"/>
</DataTemplate>

View file

@ -154,16 +154,6 @@ namespace SourceGit.Views
}
}
private void OnSearchResultDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is DataGrid { SelectedItem: Models.Commit commit } && DataContext is ViewModels.Repository repo)
{
repo.NavigateToCommit(commit.SHA);
}
e.Handled = true;
}
private void OnBranchTreeRowsChanged(object _, RoutedEventArgs e)
{
UpdateLeftSidebarLayout();
@ -236,7 +226,7 @@ namespace SourceGit.Views
e.Handled = true;
}
private void OnLeftSidebarDataGridPropertyChanged(object _, AvaloniaPropertyChangedEventArgs e)
private void OnLeftSidebarListBoxPropertyChanged(object _, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ListBox.ItemsSourceProperty || e.Property == ListBox.IsVisibleProperty)
UpdateLeftSidebarLayout();

View file

@ -28,14 +28,10 @@
Margin="10,0,0,0"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -43,9 +39,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2" Classes="caption_button" Click="CloseWindow" IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Body -->

View file

@ -1,5 +1,5 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
@ -10,15 +10,15 @@ namespace SourceGit.Views
InitializeComponent();
}
protected override void OnClosing(WindowClosingEventArgs e)
{
(DataContext as ViewModels.RepositoryConfigure)?.Save();
base.OnClosing(e);
}
private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
(DataContext as ViewModels.RepositoryConfigure)?.Save();
Close();
}
}
}

View file

@ -48,10 +48,12 @@
</DataTemplate>
<DataTemplate DataType="m:RevisionSubmodule">
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" Margin="8,8,8,0">
<TextBlock Text="{DynamicResource Text.CommitDetail.Files.Submodule}" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
<v:CommitBaseInfo Margin="0,16,0,0" Content="{Binding Commit}" Message="{Binding FullMessage}"/>
</StackPanel>
<Grid RowDefinitions="Auto,*" Margin="8,0">
<TextBlock Grid.Row="0" Margin="0,8,0,0" Text="{DynamicResource Text.CommitDetail.Files.Submodule}" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Foreground="{DynamicResource Brush.FG2}"/>
<ScrollViewer Grid.Row="1" Margin="0,16,0,0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<v:CommitBaseInfo Content="{Binding Commit}" Message="{Binding FullMessage}"/>
</ScrollViewer>
</Grid>
</DataTemplate>
</UserControl.DataTemplates>
</UserControl>

View file

@ -0,0 +1,25 @@
<UserControl 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:vm="using:SourceGit.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.ScanRepositories"
x:DataType="vm:ScanRepositories">
<StackPanel Orientation="Vertical" Margin="8,0">
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.ScanRepositories}"/>
<Grid Margin="0,16,0,0" RowDefinitions="32" ColumnDefinitions="130,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.ScanRepositories.RootDir}"/>
<Grid Grid.Row="0" Grid.Column="1" ColumnDefinitions="Auto,*">
<Path Grid.Column="0" Width="14" Height="14" Margin="0,4,0,0" Data="{StaticResource Icons.Folder}"/>
<TextBlock Grid.Column="1" VerticalAlignment="Center" Text="{Binding RootDir}" Margin="4,0,0,0" TextTrimming="CharacterEllipsis"/>
</Grid>
</Grid>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,12 @@
using Avalonia.Controls;
namespace SourceGit.Views
{
public partial class ScanRepositories : UserControl
{
public ScanRepositories()
{
InitializeComponent();
}
}
}

View file

@ -29,14 +29,10 @@
Data="{StaticResource Icons.SoftwareUpdate}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -44,12 +40,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- Body -->

View file

@ -26,14 +26,10 @@
Data="{StaticResource Icons.Edit}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -41,12 +37,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<StackPanel Grid.Row="1" Orientation="Vertical" Margin="8">

View file

@ -1,3 +1,4 @@
using System;
using System.IO;
using Avalonia.Input;
@ -33,22 +34,25 @@ namespace SourceGit.Views
}
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
App.Quit(_exitCode);
}
private void BeginMoveWindow(object _, PointerPressedEventArgs e)
{
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
App.Quit(-1);
}
private void SaveAndClose(object _1, RoutedEventArgs _2)
{
File.WriteAllText(_file, Editor.Text);
App.Quit(0);
_exitCode = 0;
Close();
}
private readonly string _file;
private int _exitCode = -1;
}
}

View file

@ -66,23 +66,28 @@
</Border>
<!-- Stash List -->
<DataGrid Grid.Row="2"
<ListBox Grid.Row="2"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding VisibleStashes}"
SelectedItem="{Binding SelectedStash, Mode=TwoWay}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="50"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="50"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Stash">
<Border BorderBrush="{DynamicResource Brush.Border2}" BorderThickness="0,0,0,1" Padding="4" Background="Transparent" ContextRequested="OnStashContextRequested">
<Grid RowDefinitions="Auto,*" >
@ -95,10 +100,8 @@
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
<!-- Changes Bar -->
<Border Grid.Row="3" BorderThickness="0,1" BorderBrush="{DynamicResource Brush.Border0}">
@ -110,38 +113,36 @@
</Border>
<!-- View Changes -->
<DataGrid Grid.Row="4"
<ListBox Grid.Row="4"
Background="{DynamicResource Brush.Contents}"
ItemsSource="{Binding Changes}"
SelectedItem="{Binding SelectedChange, Mode=TwoWay}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
Focusable="False"
RowHeight="26"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTemplateColumn Header="ICON">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<v:ChangeStatusIcon Width="14" Height="14" Change="{Binding}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="26"/>
</Style>
</ListBox.Styles>
<DataGridTemplateColumn Width="*" Header="PATH">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Classes="primary" Text="{Binding Path}" Margin="4,0,0,0"/>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:Change">
<Grid ColumnDefinitions="24,*">
<v:ChangeStatusIcon Grid.Column="0" Width="14" Height="14" Change="{Binding}"/>
<TextBlock Grid.Column="1" Classes="primary" Text="{Binding Path}" Margin="4,0,0,0"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<GridSplitter Grid.Column="1"

View file

@ -10,7 +10,7 @@
x:DataType="vm:Statistics"
x:Name="ThisControl"
Title="{DynamicResource Text.Statistics}"
Width="800" Height="450"
Width="860" Height="500"
WindowStartupLocation="CenterOwner"
CanResize="False">
<Grid RowDefinitions="Auto,Auto,*">
@ -27,14 +27,10 @@
Data="{StaticResource Icons.Statistics}"
IsVisible="{OnPlatform True, macOS=False}"/>
<Grid Grid.Column="0" Classes="caption_button_box" Margin="2,4,0,0" IsVisible="{OnPlatform False, macOS=True}">
<Button Classes="caption_button_macos" Click="CloseWindow">
<Grid>
<Ellipse Fill="{DynamicResource Brush.MacOS.Close}"/>
<Path Height="6" Width="6" Stretch="Fill" Fill="#505050" Data="{StaticResource Icons.MacOS.Close}"/>
</Grid>
</Button>
</Grid>
<v:CaptionButtonsMacOS Grid.Column="0"
Margin="0,2,0,0"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform False, macOS=True}"/>
<TextBlock Grid.Column="0" Grid.ColumnSpan="3"
Classes="bold"
@ -42,12 +38,9 @@
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
<Button Grid.Column="2"
Classes="caption_button"
Click="CloseWindow"
IsVisible="{OnPlatform True, macOS=False}">
<Path Data="{StaticResource Icons.Window.Close}"/>
</Button>
<v:CaptionButtons Grid.Column="2"
IsCloseButtonOnly="True"
IsVisible="{OnPlatform True, macOS=False}"/>
</Grid>
<!-- View mode switcher -->
@ -110,7 +103,7 @@
<ListBoxItem>
<Border Classes="switcher_bg">
<TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.ThisYear}"/>
<TextBlock Classes="view_mode_switcher" Text="{DynamicResource Text.Statistics.MostRecentYear}"/>
</Border>
</ListBoxItem>
@ -134,53 +127,50 @@
<Grid ColumnDefinitions="256,*" Margin="8,8,8,16">
<Grid Grid.Column="0" RowDefinitions="*,16">
<!-- Table By Committer -->
<DataGrid Grid.Row="0"
ItemsSource="{Binding ByCommitter}"
<ListBox Grid.Column="0"
ItemsSource="{Binding ByAuthor}"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserResizeColumns="False"
CanUserSortColumns="False"
HeadersVisibility="Column"
GridLinesVisibility="All"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
Background="{DynamicResource Brush.Contents}"
HorizontalGridLinesBrush="{DynamicResource Brush.Border2}"
VerticalGridLinesBrush="{DynamicResource Brush.Border2}"
IsReadOnly="True"
RowHeight="26"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<DataGrid.Styles>
<Style Selector="DataGridColumnHeader">
<Setter Property="Background" Value="{DynamicResource Brush.Window}"/>
<Setter Property="Padding" Value="8,0,0,0"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border2}"/>
<Setter Property="SeparatorBrush" Value="{DynamicResource Brush.Border2}" />
<Style Selector="^:pointerover /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource Brush.Window}"/>
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="26"/>
</Style>
</ListBox.Styles>
<Style Selector="^:pressed /template/ Grid#PART_ColumnHeaderRoot">
<Setter Property="Background" Value="{DynamicResource Brush.Window}"/>
</Style>
</Style>
</DataGrid.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<DataGrid.Columns>
<DataGridTextColumn Width="150" Header="{DynamicResource Text.Statistics.Committer}" Binding="{Binding Name}"/>
<DataGridTextColumn Width="*" Header="{DynamicResource Text.Statistics.CommitAmount}" Binding="{Binding Count}"/>
</DataGrid.Columns>
</DataGrid>
<ListBox.ItemTemplate>
<DataTemplate DataType="m:StatisticsSample">
<Border BorderThickness="0,0,0,1" BorderBrush="{DynamicResource Brush.Border2}">
<Grid ColumnDefinitions="*,100">
<Border Grid.Column="0" Padding="8,0" ClipToBounds="True">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left"/>
</Border>
<Border Grid.Column="1" Padding="8,0" ClipToBounds="True">
<TextBlock Text="{Binding Count}" HorizontalAlignment="Right"/>
</Border>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- Summary -->
<Grid Grid.Row="1" ColumnDefinitions="*,*">
<!-- Total Committers -->
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock Classes="primary" Text="{DynamicResource Text.Statistics.TotalCommitters}" FontSize="11" Foreground="{DynamicResource Brush.FG2}"/>
<TextBlock Classes="primary" Text="{Binding ByCommitter.Count}" FontSize="11" Margin="4,0,0,0"/>
<TextBlock Classes="primary" Text="{DynamicResource Text.Statistics.TotalAuthors}" FontSize="11" Foreground="{DynamicResource Brush.FG2}"/>
<TextBlock Classes="primary" Text="{Binding ByAuthor.Count}" FontSize="11" Margin="4,0,0,0"/>
</StackPanel>
<!-- Total Commits -->
@ -193,7 +183,7 @@
<!-- Graph -->
<v:Chart Grid.Column="1"
Margin="16,0,0,0"
Margin="16"
LabelBrush="{DynamicResource Brush.FG1}"
LineBrush="{DynamicResource Brush.Border2}"
ShapeBrush="{DynamicResource Brush.Accent}"

View file

@ -5,7 +5,6 @@ using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
namespace SourceGit.Views
@ -86,21 +85,18 @@ namespace SourceGit.Views
else
maxV = (int)Math.Ceiling(maxV / 500.0) * 500;
var fontFamily = this.FindResource("Fonts.Monospace") as FontFamily;
var typeface = new Typeface(fontFamily);
var typeface = new Typeface("fonts:SourceGit#JetBrains Mono");
var pen = new Pen(LineBrush);
var width = Bounds.Width;
var height = Bounds.Height;
// Transparent background to block mouse move events.
context.DrawRectangle(Brushes.Transparent, null, new Rect(0, 0, width, height));
// Draw coordinate
var maxLabel = new FormattedText($"{maxV}", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 12.0, LabelBrush);
var horizonStart = maxLabel.Width + 8;
var labelHeight = maxLabel.Height;
var bg = this.FindResource("Brush.Contents") as IBrush;
context.DrawText(maxLabel, new Point(0, -maxLabel.Height * 0.5));
context.DrawRectangle(pen, new Rect(horizonStart, 0, width - horizonStart, height - labelHeight));
context.DrawRectangle(bg, pen, new Rect(horizonStart, 0, width - horizonStart, height - labelHeight));
if (samples.Count == 0)
return;
@ -158,16 +154,13 @@ namespace SourceGit.Views
context.DrawRectangle(ShapeBrush, null, rect);
if (stepX < 32)
var test = (stepX - 4) / hLabel.Width;
if (test < 1.0)
{
var matrix = Matrix.CreateTranslation(hLabel.Width * 0.5, -hLabel.Height * 0.5) // Center of label
* Matrix.CreateRotation(Math.PI * 0.25) // Rotate
* Matrix.CreateTranslation(xLabel, yLabel); // Move
var matrix = Matrix.CreateRotation(Math.Acos(test)) * Matrix.CreateTranslation(xLabel + hLabel.Width * 0.5, yLabel);
using (context.PushTransform(matrix))
{
context.DrawText(hLabel, new Point(0, 0));
}
}
else
{
context.DrawText(hLabel, new Point(xLabel, yLabel));
@ -233,10 +226,5 @@ namespace SourceGit.Views
{
BeginMoveDrag(e);
}
private void CloseWindow(object _1, RoutedEventArgs _2)
{
Close();
}
}
}

View file

@ -73,7 +73,7 @@ namespace SourceGit.Views
}
}
private void OnTreeViewKeyDown(object sender, KeyEventArgs e)
private void OnTreeViewKeyDown(object _, KeyEventArgs e)
{
if (TreeContainer.SelectedItem is ViewModels.RepositoryNode node && e.Key == Key.Enter)
{
@ -163,7 +163,7 @@ namespace SourceGit.Views
private void DropOnTreeView(object sender, DragEventArgs e)
{
if (e.Data.Get("MovedRepositoryTreeNode") is ViewModels.RepositoryNode moved)
if (e.Data.Contains("MovedRepositoryTreeNode") && e.Data.Get("MovedRepositoryTreeNode") is ViewModels.RepositoryNode moved)
{
e.Handled = true;
ViewModels.Welcome.Instance.MoveNode(moved, null);
@ -224,7 +224,8 @@ namespace SourceGit.Views
return;
}
if (e.Data.Get("MovedRepositoryTreeNode") is ViewModels.RepositoryNode moved)
if (e.Data.Contains("MovedRepositoryTreeNode") &&
e.Data.Get("MovedRepositoryTreeNode") is ViewModels.RepositoryNode moved)
{
e.Handled = true;
@ -279,14 +280,14 @@ namespace SourceGit.Views
return;
}
var root = new Commands.QueryRepositoryRootPath(path).Result();
if (string.IsNullOrEmpty(root))
var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd();
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
ViewModels.Welcome.Instance.InitRepository(path, parent);
ViewModels.Welcome.Instance.InitRepository(path, parent, test.StdErr);
return;
}
var normalizedPath = root.Replace("\\", "/");
var normalizedPath = test.StdOut.Trim().Replace("\\", "/");
var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true);
ViewModels.Welcome.Instance.Refresh();

View file

@ -21,9 +21,15 @@
</Button>
</StackPanel>
<Button Grid.Column="2" Classes="icon_button" Width="32" Command="{Binding AddRootNode}" ToolTip.Tip="{DynamicResource Text.Welcome.AddRootFolder}">
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Classes="icon_button" Width="32" Command="{Binding AddRootNode}" ToolTip.Tip="{DynamicResource Text.Welcome.AddRootFolder}">
<Path Width="14" Height="14" Margin="0,2,0,0" Data="{StaticResource Icons.Folder.Add}"/>
</Button>
<Button Classes="icon_button" Width="32" Command="{Binding ScanDefaultCloneDir}" ToolTip.Tip="{DynamicResource Text.Welcome.ScanDefaultCloneDir}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Scan}"/>
</Button>
</StackPanel>
</Grid>
</UserControl>

View file

@ -1,3 +1,4 @@
using System;
using System.IO;
using Avalonia.Controls;
@ -30,9 +31,16 @@ namespace SourceGit.Views
options.SuggestedStartLocation = folder;
}
try
{
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
OpenOrInitRepository(selected[0].Path.LocalPath);
}
catch (Exception exception)
{
App.RaiseException(string.Empty, $"Failed to open repository: {exception.Message}");
}
e.Handled = true;
}
@ -47,14 +55,14 @@ namespace SourceGit.Views
return;
}
var root = new Commands.QueryRepositoryRootPath(path).Result();
if (string.IsNullOrEmpty(root))
var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd();
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
ViewModels.Welcome.Instance.InitRepository(path, parent);
ViewModels.Welcome.Instance.InitRepository(path, parent, test.StdErr);
return;
}
var normalizedPath = root.Replace("\\", "/");
var normalizedPath = test.StdOut.Trim().Replace("\\", "/");
var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(normalizedPath, parent, false);
ViewModels.Welcome.Instance.Refresh();

View file

@ -46,7 +46,7 @@
<ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.WorkingCopy.Unstaged.Stage}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Space, macOS=␣}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Space/Enter, macOS=␣/Enter}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="14" Height="14" Margin="0,6,0,0" Data="{StaticResource Icons.Down}"/>
@ -85,7 +85,7 @@
<ToolTip.Tip>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource Text.WorkingCopy.Staged.Unstage}" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Space, macOS=␣}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
<TextBlock Margin="16,0,0,0" Text="{OnPlatform Space/Enter, macOS=␣/Enter}" Opacity=".6" FontSize="11" VerticalAlignment="Center"/>
</StackPanel>
</ToolTip.Tip>
<Path Width="14" Height="14" Margin="0,6,0,0" Data="{StaticResource Icons.Up}"/>

View file

@ -62,16 +62,27 @@ namespace SourceGit.Views
private void OnUnstagedKeyDown(object _, KeyEventArgs e)
{
if (DataContext is ViewModels.WorkingCopy vm && e.Key == Key.Space)
if (DataContext is ViewModels.WorkingCopy vm)
{
if (e.Key is Key.Space or Key.Enter)
{
vm.StageSelected();
e.Handled = true;
return;
}
if (e.Key is Key.Delete or Key.Back && vm.SelectedUnstaged is { Count: > 0 } selected)
{
vm.Discard(selected);
e.Handled = true;
return;
}
}
}
private void OnStagedKeyDown(object _, KeyEventArgs e)
{
if (DataContext is ViewModels.WorkingCopy vm && e.Key == Key.Space)
if (DataContext is ViewModels.WorkingCopy vm && e.Key is Key.Space or Key.Enter)
{
vm.UnstageSelected();
e.Handled = true;