code_style: remove all IDE warnings

This commit is contained in:
leo 2024-07-15 00:30:31 +08:00
parent 24ca3eaf8c
commit f4eca45754
No known key found for this signature in database
79 changed files with 1462 additions and 1378 deletions

View file

@ -89,20 +89,32 @@ namespace SourceGit
public static readonly SimpleCommand OpenPreferenceCommand = new SimpleCommand(() => public static readonly SimpleCommand OpenPreferenceCommand = new SimpleCommand(() =>
{ {
var toplevel = GetTopLevel() as Window;
if (toplevel == null)
return;
var dialog = new Views.Preference(); var dialog = new Views.Preference();
dialog.ShowDialog(GetTopLevel() as Window); dialog.ShowDialog(toplevel);
}); });
public static readonly SimpleCommand OpenHotkeysCommand = new SimpleCommand(() => public static readonly SimpleCommand OpenHotkeysCommand = new SimpleCommand(() =>
{ {
var toplevel = GetTopLevel() as Window;
if (toplevel == null)
return;
var dialog = new Views.Hotkeys(); var dialog = new Views.Hotkeys();
dialog.ShowDialog(GetTopLevel() as Window); dialog.ShowDialog(toplevel);
}); });
public static readonly SimpleCommand OpenAboutCommand = new SimpleCommand(() => public static readonly SimpleCommand OpenAboutCommand = new SimpleCommand(() =>
{ {
var toplevel = GetTopLevel() as Window;
if (toplevel == null)
return;
var dialog = new Views.About(); var dialog = new Views.About();
dialog.ShowDialog(GetTopLevel() as Window); dialog.ShowDialog(toplevel);
}); });
public static readonly SimpleCommand CheckForUpdateCommand = new SimpleCommand(() => public static readonly SimpleCommand CheckForUpdateCommand = new SimpleCommand(() =>
@ -127,7 +139,7 @@ namespace SourceGit
public static void SetLocale(string localeKey) public static void SetLocale(string localeKey)
{ {
var app = Current as App; var app = Current as App;
var targetLocale = app.Resources[localeKey] as ResourceDictionary; var targetLocale = app?.Resources[localeKey] as ResourceDictionary;
if (targetLocale == null || targetLocale == app._activeLocale) if (targetLocale == null || targetLocale == app._activeLocale)
return; return;
@ -141,6 +153,8 @@ namespace SourceGit
public static void SetTheme(string theme, string themeOverridesFile) public static void SetTheme(string theme, string themeOverridesFile)
{ {
var app = Current as App; var app = Current as App;
if (app == null)
return;
if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase)) if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase))
app.RequestedThemeVariant = ThemeVariant.Light; app.RequestedThemeVariant = ThemeVariant.Light;
@ -179,6 +193,7 @@ namespace SourceGit
} }
catch catch
{ {
// ignore
} }
} }
else else
@ -189,18 +204,18 @@ namespace SourceGit
public static async void CopyText(string data) public static async void CopyText(string data)
{ {
if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
if (desktop.MainWindow.Clipboard is { } clipbord) if (desktop.MainWindow?.Clipboard is { } clipbord)
await clipbord.SetTextAsync(data); await clipbord.SetTextAsync(data);
} }
} }
public static async Task<string> GetClipboardTextAsync() public static async Task<string> GetClipboardTextAsync()
{ {
if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
if (desktop.MainWindow.Clipboard is { } clipboard) if (desktop.MainWindow?.Clipboard is { } clipboard)
{ {
return await clipboard.GetTextAsync(); return await clipboard.GetTextAsync();
} }
@ -210,7 +225,7 @@ namespace SourceGit
public static string Text(string key, params object[] args) public static string Text(string key, params object[] args)
{ {
var fmt = Current.FindResource($"Text.{key}") as string; var fmt = Current?.FindResource($"Text.{key}") as string;
if (string.IsNullOrWhiteSpace(fmt)) if (string.IsNullOrWhiteSpace(fmt))
return $"Text.{key}"; return $"Text.{key}";
@ -226,16 +241,21 @@ namespace SourceGit
icon.Width = 12; icon.Width = 12;
icon.Height = 12; icon.Height = 12;
icon.Stretch = Stretch.Uniform; icon.Stretch = Stretch.Uniform;
icon.Data = Current.FindResource(key) as StreamGeometry;
var geo = Current?.FindResource(key) as StreamGeometry;
if (geo != null)
icon.Data = geo;
return icon; return icon;
} }
public static TopLevel GetTopLevel() public static TopLevel GetTopLevel()
{ {
if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
return desktop.MainWindow; return desktop.MainWindow;
} }
return null; return null;
} }
@ -297,9 +317,9 @@ namespace SourceGit
public static void Quit() public static void Quit()
{ {
if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
desktop.MainWindow.Close(); desktop.MainWindow?.Close();
desktop.Shutdown(); desktop.Shutdown();
} }
} }
@ -360,7 +380,7 @@ namespace SourceGit
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
if (Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: not null } desktop)
{ {
var dialog = new Views.SelfUpdate() var dialog = new Views.SelfUpdate()
{ {
@ -384,11 +404,11 @@ namespace SourceGit
if (!filename.Equals("git-rebase-todo", StringComparison.OrdinalIgnoreCase)) if (!filename.Equals("git-rebase-todo", StringComparison.OrdinalIgnoreCase))
return true; return true;
var dirInfo = new DirectoryInfo(Path.GetDirectoryName(file)); var dirInfo = new DirectoryInfo(Path.GetDirectoryName(file)!);
if (!dirInfo.Exists || !dirInfo.Name.Equals("rebase-merge", StringComparison.Ordinal)) if (!dirInfo.Exists || !dirInfo.Name.Equals("rebase-merge", StringComparison.Ordinal))
return true; return true;
var jobsFile = Path.Combine(dirInfo.Parent.FullName, "sourcegit_rebase_jobs.json"); var jobsFile = Path.Combine(dirInfo.Parent!.FullName, "sourcegit_rebase_jobs.json");
if (!File.Exists(jobsFile)) if (!File.Exists(jobsFile))
return true; return true;
@ -437,16 +457,16 @@ namespace SourceGit
if (!filename.Equals("COMMIT_EDITMSG", StringComparison.OrdinalIgnoreCase)) if (!filename.Equals("COMMIT_EDITMSG", StringComparison.OrdinalIgnoreCase))
return true; return true;
var jobsFile = Path.Combine(Path.GetDirectoryName(file), "sourcegit_rebase_jobs.json"); var jobsFile = Path.Combine(Path.GetDirectoryName(file)!, "sourcegit_rebase_jobs.json");
if (!File.Exists(jobsFile)) if (!File.Exists(jobsFile))
return true; return true;
var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection); var collection = JsonSerializer.Deserialize(File.ReadAllText(jobsFile), JsonCodeGen.Default.InteractiveRebaseJobCollection);
var doneFile = Path.Combine(Path.GetDirectoryName(file), "rebase-merge", "done"); var doneFile = Path.Combine(Path.GetDirectoryName(file)!, "rebase-merge", "done");
if (!File.Exists(doneFile)) if (!File.Exists(doneFile))
return true; return true;
var done = File.ReadAllText(doneFile).Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var done = File.ReadAllText(doneFile).Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
if (done.Length > collection.Jobs.Count) if (done.Length > collection.Jobs.Count)
return true; return true;
@ -460,7 +480,7 @@ namespace SourceGit
private bool TryLaunchedAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop) private bool TryLaunchedAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
{ {
var args = desktop.Args; var args = desktop.Args;
if (args.Length <= 1 || !args[0].Equals("--core-editor", StringComparison.Ordinal)) if (args == null || args.Length <= 1 || !args[0].Equals("--core-editor", StringComparison.Ordinal))
return false; return false;
var file = args[1]; var file = args[1];
@ -474,7 +494,7 @@ namespace SourceGit
private bool TryLaunchedAsAskpass(IClassicDesktopStyleApplicationLifetime desktop) private bool TryLaunchedAsAskpass(IClassicDesktopStyleApplicationLifetime desktop)
{ {
var args = desktop.Args; var args = desktop.Args;
if (args.Length != 1 || !args[0].StartsWith("Enter passphrase", StringComparison.Ordinal)) if (args == null || args.Length != 1 || !args[0].StartsWith("Enter passphrase", StringComparison.Ordinal))
return false; return false;
desktop.MainWindow = new Views.Askpass(args[0]); desktop.MainWindow = new Views.Askpass(args[0]);
@ -485,7 +505,10 @@ namespace SourceGit
{ {
Native.OS.SetupEnternalTools(); Native.OS.SetupEnternalTools();
var startupRepo = desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0]) ? desktop.Args[0] : null; string startupRepo = null;
if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0]))
startupRepo = desktop.Args[0];
_launcher = new ViewModels.Launcher(startupRepo); _launcher = new ViewModels.Launcher(startupRepo);
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher }; desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };

View file

@ -19,7 +19,6 @@ namespace SourceGit.Commands
{ {
public bool IsSuccess { get; set; } public bool IsSuccess { get; set; }
public string StdOut { get; set; } public string StdOut { get; set; }
public string StdErr { get; set; }
} }
public enum EditorType public enum EditorType
@ -51,7 +50,7 @@ namespace SourceGit.Commands
start.StandardErrorEncoding = Encoding.UTF8; start.StandardErrorEncoding = Encoding.UTF8;
// Force using this app as SSH askpass program // Force using this app as SSH askpass program
var selfExecFile = Process.GetCurrentProcess().MainModule.FileName; var selfExecFile = Process.GetCurrentProcess().MainModule!.FileName;
if (!OperatingSystem.IsLinux()) if (!OperatingSystem.IsLinux())
start.Environment.Add("DISPLAY", "required"); start.Environment.Add("DISPLAY", "required");
start.Environment.Add("SSH_ASKPASS", selfExecFile); // Can not use parameter here, because it invoked by SSH with `exec` start.Environment.Add("SSH_ASKPASS", selfExecFile); // Can not use parameter here, because it invoked by SSH with `exec`
@ -199,20 +198,18 @@ namespace SourceGit.Commands
{ {
proc.Start(); proc.Start();
} }
catch (Exception e) catch
{ {
return new ReadToEndResult() return new ReadToEndResult()
{ {
IsSuccess = false, IsSuccess = false,
StdOut = string.Empty, StdOut = string.Empty,
StdErr = e.Message,
}; };
} }
var rs = new ReadToEndResult() var rs = new ReadToEndResult()
{ {
StdOut = proc.StandardOutput.ReadToEnd(), StdOut = proc.StandardOutput.ReadToEnd(),
StdErr = proc.StandardError.ReadToEnd(),
}; };
proc.WaitForExit(); proc.WaitForExit();
@ -226,8 +223,5 @@ namespace SourceGit.Commands
[GeneratedRegex(@"\d+%")] [GeneratedRegex(@"\d+%")]
private static partial Regex REG_PROGRESS(); private static partial Regex REG_PROGRESS();
[GeneratedRegex(@"Enter\s+passphrase\s*for\s*key\s*['""]([^'""]+)['""]\:\s*", RegexOptions.IgnoreCase)]
private static partial Regex REG_ASKPASS();
} }
} }

View file

@ -23,7 +23,7 @@ namespace SourceGit.Commands
var rs = new Dictionary<string, string>(); var rs = new Dictionary<string, string>();
if (output.IsSuccess) if (output.IsSuccess)
{ {
var lines = output.StdOut.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var lines = output.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines) foreach (var line in lines)
{ {
var idx = line.IndexOf('=', StringComparison.Ordinal); var idx = line.IndexOf('=', StringComparison.Ordinal);
@ -31,14 +31,7 @@ namespace SourceGit.Commands
{ {
var key = line.Substring(0, idx).Trim(); var key = line.Substring(0, idx).Trim();
var val = line.Substring(idx + 1).Trim(); var val = line.Substring(idx + 1).Trim();
if (rs.ContainsKey(key)) rs[key] = val;
{
rs[key] = val;
}
else
{
rs.Add(key, val);
}
} }
} }
} }

View file

@ -125,14 +125,7 @@ namespace SourceGit.Commands
lock (_lock) lock (_lock)
{ {
if (_jobs.ContainsKey(repo)) _jobs[repo] = job;
{
_jobs[repo] = job;
}
else
{
_jobs.Add(repo, job);
}
} }
} }

View file

@ -64,7 +64,7 @@ namespace SourceGit.Commands
return init.Exec(); return init.Exec();
} }
public static string Prefix(string repo, string type) public static string GetPrefix(string repo, string type)
{ {
return new Config(repo).Get($"gitflow.prefix.{type}"); return new Config(repo).Get($"gitflow.prefix.{type}");
} }

View file

@ -82,7 +82,7 @@ namespace SourceGit.Commands
var rs = cmd.ReadToEnd(); var rs = cmd.ReadToEnd();
if (rs.IsSuccess) if (rs.IsSuccess)
{ {
var lines = rs.StdOut.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var lines = rs.StdOut.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines) foreach (var line in lines)
{ {
var match = REG_LOCK().Match(line); var match = REG_LOCK().Match(line);

View file

@ -53,8 +53,6 @@ namespace SourceGit.Commands
_current.Subject = line; _current.Subject = line;
nextPartIdx = -1; nextPartIdx = -1;
break; break;
default:
break;
} }
nextPartIdx++; nextPartIdx++;
@ -97,6 +95,9 @@ namespace SourceGit.Commands
foreach (var sub in subs) foreach (var sub in subs)
{ {
var d = sub.Trim(); var d = sub.Trim();
if (d.EndsWith("/HEAD", StringComparison.Ordinal))
continue;
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal)) if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
{ {
_current.Decorators.Add(new Models.Decorator() _current.Decorators.Add(new Models.Decorator()
@ -105,10 +106,6 @@ namespace SourceGit.Commands
Name = d.Substring(15), Name = d.Substring(15),
}); });
} }
else if (d.EndsWith("/HEAD", StringComparison.Ordinal))
{
continue;
}
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal)) else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
{ {
_current.IsMerged = true; _current.IsMerged = true;
@ -159,10 +156,10 @@ namespace SourceGit.Commands
private void MarkFirstMerged() private void MarkFirstMerged()
{ {
Args = $"log --since=\"{_commits[_commits.Count - 1].CommitterTimeStr}\" --format=\"%H\""; Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";
var rs = ReadToEnd(); var rs = ReadToEnd();
var shas = rs.StdOut.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); var shas = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
if (shas.Length == 0) if (shas.Length == 0)
return; return;

View file

@ -52,7 +52,7 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.None, Models.ChangeState.Copied); change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
break; break;
case "M": case "M":
change.Set(Models.ChangeState.Modified, Models.ChangeState.None); change.Set(Models.ChangeState.Modified);
break; break;
case "MM": case "MM":
change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified); change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
@ -61,7 +61,7 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted); change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
break; break;
case "A": case "A":
change.Set(Models.ChangeState.Added, Models.ChangeState.None); change.Set(Models.ChangeState.Added);
break; break;
case "AM": case "AM":
change.Set(Models.ChangeState.Added, Models.ChangeState.Modified); change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
@ -70,10 +70,10 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted); change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
break; break;
case "D": case "D":
change.Set(Models.ChangeState.Deleted, Models.ChangeState.None); change.Set(Models.ChangeState.Deleted);
break; break;
case "R": case "R":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.None); change.Set(Models.ChangeState.Renamed);
break; break;
case "RM": case "RM":
change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified); change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
@ -82,7 +82,7 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted); change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
break; break;
case "C": case "C":
change.Set(Models.ChangeState.Copied, Models.ChangeState.None); change.Set(Models.ChangeState.Copied);
break; break;
case "CM": case "CM":
change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified); change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);

View file

@ -47,6 +47,9 @@ namespace SourceGit.Commands
foreach (var sub in subs) foreach (var sub in subs)
{ {
var d = sub.Trim(); var d = sub.Trim();
if (d.EndsWith("/HEAD", StringComparison.Ordinal))
continue;
if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal)) if (d.StartsWith("tag: refs/tags/", StringComparison.Ordinal))
{ {
decorators.Add(new Models.Decorator() decorators.Add(new Models.Decorator()
@ -55,10 +58,6 @@ namespace SourceGit.Commands
Name = d.Substring(15), Name = d.Substring(15),
}); });
} }
else if (d.EndsWith("/HEAD", StringComparison.Ordinal))
{
continue;
}
else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal)) else if (d.StartsWith("HEAD -> refs/heads/", StringComparison.Ordinal))
{ {
isHeadOfCurrent = true; isHeadOfCurrent = true;

View file

@ -20,7 +20,7 @@ namespace SourceGit.Commands
protected override void OnReadline(string line) protected override void OnReadline(string line)
{ {
var subs = line.Split(new char[] { '$' }, StringSplitOptions.RemoveEmptyEntries); var subs = line.Split('$', StringSplitOptions.RemoveEmptyEntries);
if (subs.Length == 2) if (subs.Length == 2)
{ {
_loaded.Add(new Models.Tag() _loaded.Add(new Models.Tag()

View file

@ -27,11 +27,8 @@ namespace SourceGit.Commands
return; return;
var dateStr = line.Substring(0, dateEndIdx); var dateStr = line.Substring(0, dateEndIdx);
var date = 0.0; if (double.TryParse(dateStr, out var date))
if (!double.TryParse(dateStr, out date)) _statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
return;
_statistics.AddCommit(line.Substring(dateEndIdx + 1), date);
} }
private readonly Models.Statistics _statistics = null; private readonly Models.Statistics _statistics = null;

View file

@ -1,14 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands namespace SourceGit.Commands
{ {
public partial class Worktree : Command public class Worktree : Command
{ {
[GeneratedRegex(@"^(\w)\s(\d+)$")]
private static partial Regex REG_AHEAD_BEHIND();
public Worktree(string repo) public Worktree(string repo)
{ {
WorkingDirectory = repo; WorkingDirectory = repo;
@ -24,7 +20,7 @@ namespace SourceGit.Commands
var last = null as Models.Worktree; var last = null as Models.Worktree;
if (rs.IsSuccess) if (rs.IsSuccess)
{ {
var lines = rs.StdOut.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var lines = rs.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines) foreach (var line in lines)
{ {
if (line.StartsWith("worktree ", StringComparison.Ordinal)) if (line.StartsWith("worktree ", StringComparison.Ordinal))
@ -34,27 +30,23 @@ namespace SourceGit.Commands
} }
else if (line.StartsWith("bare", StringComparison.Ordinal)) else if (line.StartsWith("bare", StringComparison.Ordinal))
{ {
last.IsBare = true; last!.IsBare = true;
} }
else if (line.StartsWith("HEAD ", StringComparison.Ordinal)) else if (line.StartsWith("HEAD ", StringComparison.Ordinal))
{ {
last.Head = line.Substring(5).Trim(); last!.Head = line.Substring(5).Trim();
} }
else if (line.StartsWith("branch ", StringComparison.Ordinal)) else if (line.StartsWith("branch ", StringComparison.Ordinal))
{ {
last.Branch = line.Substring(7).Trim(); last!.Branch = line.Substring(7).Trim();
} }
else if (line.StartsWith("detached", StringComparison.Ordinal)) else if (line.StartsWith("detached", StringComparison.Ordinal))
{ {
last.IsDetached = true; last!.IsDetached = true;
} }
else if (line.StartsWith("locked", StringComparison.Ordinal)) else if (line.StartsWith("locked", StringComparison.Ordinal))
{ {
last.IsLocked = true; last!.IsLocked = true;
}
else if (line.StartsWith("prunable", StringComparison.Ordinal))
{
last.IsPrunable = true;
} }
} }
} }

View file

@ -1,4 +1,5 @@
using Avalonia.Controls; using Avalonia;
using Avalonia.Controls;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.Media; using Avalonia.Media;
@ -12,11 +13,11 @@ namespace SourceGit.Converters
switch (v) switch (v)
{ {
case Models.ChangeViewMode.List: case Models.ChangeViewMode.List:
return App.Current?.FindResource("Icons.List") as StreamGeometry; return Application.Current?.FindResource("Icons.List") as StreamGeometry;
case Models.ChangeViewMode.Grid: case Models.ChangeViewMode.Grid:
return App.Current?.FindResource("Icons.Grid") as StreamGeometry; return Application.Current?.FindResource("Icons.Grid") as StreamGeometry;
default: default:
return App.Current?.FindResource("Icons.Tree") as StreamGeometry; return Application.Current?.FindResource("Icons.Tree") as StreamGeometry;
} }
}); });
} }

View file

@ -18,7 +18,7 @@ namespace SourceGit.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{ {
return (value as Models.Locale).Key; return (value as Models.Locale)?.Key;
} }
} }
@ -29,18 +29,21 @@ namespace SourceGit.Converters
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
var theme = (string)value; var theme = (string)value;
if (string.IsNullOrEmpty(theme))
return ThemeVariant.Default;
if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase)) if (theme.Equals("Light", StringComparison.OrdinalIgnoreCase))
return ThemeVariant.Light; return ThemeVariant.Light;
else if (theme.Equals("Dark", StringComparison.OrdinalIgnoreCase))
if (theme.Equals("Dark", StringComparison.OrdinalIgnoreCase))
return ThemeVariant.Dark; return ThemeVariant.Dark;
else
return ThemeVariant.Default; return ThemeVariant.Default;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{ {
var theme = (ThemeVariant)value; return (value as ThemeVariant)?.Key;
return theme.Key;
} }
} }

View file

@ -75,7 +75,10 @@ namespace SourceGit.Models
} }
} }
} }
catch { } catch
{
// ignored
}
lock (_synclock) lock (_synclock)
{ {
@ -84,10 +87,7 @@ namespace SourceGit.Models
Dispatcher.UIThread.InvokeAsync(() => Dispatcher.UIThread.InvokeAsync(() =>
{ {
if (_resources.ContainsKey(md5)) _resources[md5] = img;
_resources[md5] = img;
else
_resources.Add(md5, img);
NotifyResourceChanged(md5); NotifyResourceChanged(md5);
}); });
} }
@ -134,7 +134,10 @@ namespace SourceGit.Models
return img; return img;
} }
} }
catch { } catch
{
// ignore
}
} }
} }
@ -156,7 +159,7 @@ namespace SourceGit.Models
} }
private static readonly object _synclock = new object(); private static readonly object _synclock = new object();
private static readonly string _storePath = string.Empty; private static readonly string _storePath;
private static readonly List<IAvatarHost> _avatars = new List<IAvatarHost>(); private static readonly List<IAvatarHost> _avatars = new List<IAvatarHost>();
private static readonly Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>(); private static readonly Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>();
private static readonly HashSet<string> _requesting = new HashSet<string>(); private static readonly HashSet<string> _requesting = new HashSet<string>();

View file

@ -22,9 +22,8 @@ namespace SourceGit.Models
public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"); public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss");
public string CommitterTimeStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"); public string CommitterTimeStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss");
public string AuthorTimeShortStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString("yyyy/MM/dd"); public string AuthorTimeShortStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString("yyyy/MM/dd");
public string CommitterTimeShortStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToString("yyyy/MM/dd");
public bool IsCommitterVisible => Author != Committer || AuthorTime != CommitterTime; public bool IsCommitterVisible => !Author.Equals(Committer) || AuthorTime != CommitterTime;
public bool IsCurrentHead => Decorators.Find(x => x.Type is DecoratorType.CurrentBranchHead or DecoratorType.CurrentCommitHead) != null; public bool IsCurrentHead => Decorators.Find(x => x.Type is DecoratorType.CurrentBranchHead or DecoratorType.CurrentCommitHead) != null;
} }
} }

View file

@ -268,8 +268,9 @@ namespace SourceGit.Models
var path = unsolved[i]; var path = unsolved[i];
var endY = (commits.Count - 0.5) * UNIT_HEIGHT; var endY = (commits.Count - 0.5) * UNIT_HEIGHT;
if (path.Path.Points.Count == 1 && path.Path.Points[0].Y == endY) if (path.Path.Points.Count == 1 && Math.Abs(path.Path.Points[0].Y - endY) < 0.0001)
continue; continue;
path.Add((i + 0.5) * UNIT_WIDTH, endY + HALF_HEIGHT, HALF_HEIGHT, true); path.Add((i + 0.5) * UNIT_WIDTH, endY + HALF_HEIGHT, HALF_HEIGHT, true);
} }
unsolved.Clear(); unsolved.Clear();

View file

@ -108,8 +108,8 @@ namespace SourceGit.Models
private readonly Change _workingCopyChange = null; private readonly Change _workingCopyChange = null;
private readonly bool _isUnstaged = false; private readonly bool _isUnstaged = false;
private readonly string _path;
private readonly string _orgPath = string.Empty; private readonly string _orgPath = string.Empty;
private readonly string _path = string.Empty;
private readonly string _extra = string.Empty; private readonly string _extra = string.Empty;
private readonly List<string> _revisions = new List<string>(); private readonly List<string> _revisions = new List<string>();
} }

View file

@ -12,9 +12,9 @@ namespace SourceGit.Models
{ {
public class ExternalTool public class ExternalTool
{ {
public string Name { get; private set; } = string.Empty; public string Name { get; private set; }
public string Executable { get; private set; } = string.Empty; public string Executable { get; private set; }
public string OpenCmdArgs { get; private set; } = string.Empty; public string OpenCmdArgs { get; private set; }
public Bitmap IconImage { get; private set; } = null; public Bitmap IconImage { get; private set; } = null;
public ExternalTool(string name, string icon, string executable, string openCmdArgs) public ExternalTool(string name, string icon, string executable, string openCmdArgs)
@ -25,10 +25,14 @@ namespace SourceGit.Models
try try
{ {
var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/ExternalToolIcons/{icon}.png", UriKind.RelativeOrAbsolute)); var asset = AssetLoader.Open(new Uri($"avares://SourceGit/Resources/ExternalToolIcons/{icon}.png",
UriKind.RelativeOrAbsolute));
IconImage = new Bitmap(asset); IconImage = new Bitmap(asset);
} }
catch { } catch
{
// ignore
}
} }
public void Open(string repo) public void Open(string repo)

View file

@ -14,7 +14,6 @@ namespace SourceGit.Models
public class RevisionTextFile public class RevisionTextFile
{ {
public string FileName { get; set; }
public string Content { get; set; } public string Content { get; set; }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using Avalonia;
using Avalonia.Styling; using Avalonia.Styling;
using AvaloniaEdit; using AvaloniaEdit;
@ -14,14 +15,10 @@ namespace SourceGit.Models
{ {
public static TextMate.Installation CreateForEditor(TextEditor editor) public static TextMate.Installation CreateForEditor(TextEditor editor)
{ {
if (App.Current?.ActualThemeVariant == ThemeVariant.Dark) if (Application.Current?.ActualThemeVariant == ThemeVariant.Dark)
{
return editor.InstallTextMate(new RegistryOptions(ThemeName.DarkPlus)); return editor.InstallTextMate(new RegistryOptions(ThemeName.DarkPlus));
}
else return editor.InstallTextMate(new RegistryOptions(ThemeName.LightPlus));
{
return editor.InstallTextMate(new RegistryOptions(ThemeName.LightPlus));
}
} }
public static void SetThemeByApp(TextMate.Installation installation) public static void SetThemeByApp(TextMate.Installation installation)
@ -29,35 +26,28 @@ namespace SourceGit.Models
if (installation == null) if (installation == null)
return; return;
var reg = installation.RegistryOptions as RegistryOptions; if (installation.RegistryOptions is RegistryOptions reg)
if (App.Current?.ActualThemeVariant == ThemeVariant.Dark)
{ {
installation.SetTheme(reg.LoadTheme(ThemeName.DarkPlus)); if (Application.Current?.ActualThemeVariant == ThemeVariant.Dark)
} installation.SetTheme(reg.LoadTheme(ThemeName.DarkPlus));
else else
{ installation.SetTheme(reg.LoadTheme(ThemeName.LightPlus));
installation.SetTheme(reg.LoadTheme(ThemeName.LightPlus));
} }
} }
public static void SetGrammarByFileName(TextMate.Installation installation, string filePath) public static void SetGrammarByFileName(TextMate.Installation installation, string filePath)
{ {
if (installation == null) if (installation is { RegistryOptions: RegistryOptions reg })
return;
var ext = Path.GetExtension(filePath);
if (ext == ".h")
{ {
ext = ".cpp"; var ext = Path.GetExtension(filePath);
} if (ext == ".h")
else if (ext == ".resx" || ext == ".plist") ext = ".cpp";
{ else if (ext == ".resx" || ext == ".plist")
ext = ".xml"; ext = ".xml";
}
var reg = installation.RegistryOptions as RegistryOptions; installation.SetGrammar(reg.GetScopeByExtension(ext));
installation.SetGrammar(reg.GetScopeByExtension(ext)); GC.Collect();
GC.Collect(); }
} }
} }
} }

View file

@ -10,6 +10,20 @@ namespace SourceGit.Models
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty; public string Email { get; set; } = string.Empty;
public User()
{
// Only used by User.Invalid
}
public User(string data)
{
var nameEndIdx = data.IndexOf('±', StringComparison.Ordinal);
Name = nameEndIdx > 0 ? data.Substring(0, nameEndIdx) : string.Empty;
Email = data.Substring(nameEndIdx + 1);
_hash = data.GetHashCode();
}
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
if (obj == null || !(obj is User)) if (obj == null || !(obj is User))
@ -21,21 +35,15 @@ namespace SourceGit.Models
public override int GetHashCode() public override int GetHashCode()
{ {
return base.GetHashCode(); return _hash;
} }
public static User FindOrAdd(string data) public static User FindOrAdd(string data)
{ {
return _caches.GetOrAdd(data, key => return _caches.GetOrAdd(data, key => new User(key));
{
var nameEndIdx = key.IndexOf('±', StringComparison.Ordinal);
var name = nameEndIdx > 0 ? key.Substring(0, nameEndIdx) : string.Empty;
var email = key.Substring(nameEndIdx + 1);
return new User() { Name = name, Email = email };
});
} }
private static ConcurrentDictionary<string, User> _caches = new ConcurrentDictionary<string, User>(); private static ConcurrentDictionary<string, User> _caches = new ConcurrentDictionary<string, User>();
private readonly int _hash;
} }
} }

View file

@ -28,7 +28,7 @@ namespace SourceGit.Models
var major = int.Parse(match.Groups[1].Value); var major = int.Parse(match.Groups[1].Value);
var minor = int.Parse(match.Groups[2].Value); var minor = int.Parse(match.Groups[2].Value);
var ver = Assembly.GetExecutingAssembly().GetName().Version; var ver = Assembly.GetExecutingAssembly().GetName().Version!;
return ver.Major < major || (ver.Major == major && ver.Minor < minor); return ver.Major < major || (ver.Major == major && ver.Minor < minor);
} }
} }

View file

@ -38,7 +38,7 @@ namespace SourceGit.Models
// If this repository is a worktree repository, just watch the main repository's gitdir. // If this repository is a worktree repository, just watch the main repository's gitdir.
var gitDirNormalized = _repo.GitDir.Replace("\\", "/"); var gitDirNormalized = _repo.GitDir.Replace("\\", "/");
var worktreeIdx = gitDirNormalized.IndexOf(".git/worktrees/"); var worktreeIdx = gitDirNormalized.IndexOf(".git/worktrees/", StringComparison.Ordinal);
var repoWatchDir = _repo.GitDir; var repoWatchDir = _repo.GitDir;
if (worktreeIdx > 0) if (worktreeIdx > 0)
repoWatchDir = _repo.GitDir.Substring(0, worktreeIdx + 4); repoWatchDir = _repo.GitDir.Substring(0, worktreeIdx + 4);

View file

@ -9,7 +9,6 @@ namespace SourceGit.Models
public string Head { get; set; } = string.Empty; public string Head { get; set; } = string.Empty;
public bool IsBare { get; set; } = false; public bool IsBare { get; set; } = false;
public bool IsDetached { get; set; } = false; public bool IsDetached { get; set; } = false;
public bool IsPrunable { get; set; } = false;
public bool IsLocked public bool IsLocked
{ {

View file

@ -15,8 +15,8 @@ namespace SourceGit.Native
{ {
class Terminal class Terminal
{ {
public string FilePath { get; set; } = string.Empty; public string FilePath { get; set; }
public string OpenArgFormat { get; set; } = string.Empty; public string OpenArgFormat { get; set; }
public Terminal(string exec, string fmt) public Terminal(string exec, string fmt)
{ {
@ -115,12 +115,15 @@ namespace SourceGit.Native
} }
var proc = Process.Start(_xdgOpenPath, $"\"{file}\""); var proc = Process.Start(_xdgOpenPath, $"\"{file}\"");
proc.WaitForExit(); if (proc != null)
{
proc.WaitForExit();
if (proc.ExitCode != 0) if (proc.ExitCode != 0)
App.RaiseException("", $"Failed to open \"{file}\""); App.RaiseException("", $"Failed to open \"{file}\"");
proc.Close(); proc.Close();
}
} }
private string FindExecutable(string filename) private string FindExecutable(string filename)
@ -177,7 +180,7 @@ namespace SourceGit.Native
return File.Exists(path) ? path : FindExecutable("fleet"); return File.Exists(path) ? path : FindExecutable("fleet");
} }
private string _xdgOpenPath = string.Empty; private string _xdgOpenPath = null;
private Terminal _terminal = null; private Terminal _terminal = null;
} }
} }

View file

@ -78,7 +78,10 @@ namespace SourceGit.Native
File.WriteAllText(tmp, builder.ToString()); File.WriteAllText(tmp, builder.ToString());
var proc = Process.Start("osascript", $"\"{tmp}\""); var proc = Process.Start("osascript", $"\"{tmp}\"");
proc.Exited += (o, e) => File.Delete(tmp); if (proc != null)
proc.Exited += (_, _) => File.Delete(tmp);
else
File.Delete(tmp);
} }
public void OpenWithDefaultEditor(string file) public void OpenWithDefaultEditor(string file)

View file

@ -48,20 +48,16 @@ namespace SourceGit.Native
public static Models.Shell GetShell() public static Models.Shell GetShell()
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ return (_backend as Windows)!.Shell;
return (_backend as Windows).Shell;
} return Models.Shell.Default;
else
{
return Models.Shell.Default;
}
} }
public static bool SetShell(Models.Shell shell) public static bool SetShell(Models.Shell shell)
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
var windows = _backend as Windows; var windows = (_backend as Windows)!;
if (windows.Shell != shell) if (windows.Shell != shell)
{ {
windows.Shell = shell; windows.Shell = shell;

View file

@ -73,8 +73,8 @@ namespace SourceGit.Native
v.dwOSVersionInfoSize = (uint)Marshal.SizeOf<RTL_OSVERSIONINFOEX>(); v.dwOSVersionInfoSize = (uint)Marshal.SizeOf<RTL_OSVERSIONINFOEX>();
if (RtlGetVersion(ref v) == 0 && (v.dwMajorVersion < 10 || v.dwBuildNumber < 22000)) if (RtlGetVersion(ref v) == 0 && (v.dwMajorVersion < 10 || v.dwBuildNumber < 22000))
{ {
Window.WindowStateProperty.Changed.AddClassHandler<Window>((w, e) => ExtendWindowFrame(w)); Window.WindowStateProperty.Changed.AddClassHandler<Window>((w, _) => ExtendWindowFrame(w));
Window.LoadedEvent.AddClassHandler<Window>((w, e) => ExtendWindowFrame(w)); Control.LoadedEvent.AddClassHandler<Window>((w, _) => ExtendWindowFrame(w));
} }
} }
@ -85,9 +85,9 @@ namespace SourceGit.Native
Microsoft.Win32.RegistryView.Registry64); Microsoft.Win32.RegistryView.Registry64);
var git = reg.OpenSubKey("SOFTWARE\\GitForWindows"); var git = reg.OpenSubKey("SOFTWARE\\GitForWindows");
if (git != null) if (git != null && git.GetValue("InstallPath") is string installPath)
{ {
return Path.Combine(git.GetValue("InstallPath") as string, "bin", "git.exe"); return Path.Combine(installPath, "bin", "git.exe");
} }
var builder = new StringBuilder("git.exe", 259); var builder = new StringBuilder("git.exe", 259);
@ -137,7 +137,13 @@ namespace SourceGit.Native
switch (Shell) switch (Shell)
{ {
case Models.Shell.Default: case Models.Shell.Default:
var binDir = Path.GetDirectoryName(OS.GitExecutable); if (string.IsNullOrEmpty(OS.GitExecutable))
{
App.RaiseException(workdir, $"Can NOT found bash.exe");
return;
}
var binDir = Path.GetDirectoryName(OS.GitExecutable)!;
var bash = Path.Combine(binDir, "bash.exe"); var bash = Path.Combine(binDir, "bash.exe");
if (!File.Exists(bash)) if (!File.Exists(bash))
{ {
@ -175,28 +181,23 @@ namespace SourceGit.Native
public void OpenInFileManager(string path, bool select) public void OpenInFileManager(string path, bool select)
{ {
var fullpath = string.Empty; string fullpath;
if (File.Exists(path)) if (File.Exists(path))
{ {
fullpath = new FileInfo(path).FullName; fullpath = new FileInfo(path).FullName;
// For security reason, we never execute a file.
// Instead, we open the folder and select it.
select = true; select = true;
} }
else else
{ {
fullpath = new DirectoryInfo(path).FullName; fullpath = new DirectoryInfo(path!).FullName;
} }
if (select) if (select)
{ {
// The fullpath here may be a file or a folder.
OpenFolderAndSelectFile(fullpath); OpenFolderAndSelectFile(fullpath);
} }
else else
{ {
// The fullpath here is always a folder.
Process.Start(new ProcessStartInfo(fullpath) Process.Start(new ProcessStartInfo(fullpath)
{ {
UseShellExecute = true, UseShellExecute = true,
@ -362,7 +363,7 @@ namespace SourceGit.Native
if (sublime != null) if (sublime != null)
{ {
var icon = sublime.GetValue("DisplayIcon") as string; var icon = sublime.GetValue("DisplayIcon") as string;
return Path.Combine(Path.GetDirectoryName(icon), "subl.exe"); return Path.Combine(Path.GetDirectoryName(icon)!, "subl.exe");
} }
// Sublime Text 3 // Sublime Text 3
@ -370,7 +371,7 @@ namespace SourceGit.Native
if (sublime3 != null) if (sublime3 != null)
{ {
var icon = sublime3.GetValue("DisplayIcon") as string; var icon = sublime3.GetValue("DisplayIcon") as string;
return Path.Combine(Path.GetDirectoryName(icon), "subl.exe"); return Path.Combine(Path.GetDirectoryName(icon)!, "subl.exe");
} }
return string.Empty; return string.Empty;

View file

@ -88,6 +88,9 @@ namespace SourceGit.ViewModels
if (creator == null) if (creator == null)
return new ValidationResult("Missing runtime context to create branch!"); return new ValidationResult("Missing runtime context to create branch!");
if (string.IsNullOrEmpty(path))
return new ValidationResult("Worktree path is required!");
var fullPath = System.IO.Path.IsPathRooted(path) ? path : System.IO.Path.Combine(creator._repo.FullPath, path); var fullPath = System.IO.Path.IsPathRooted(path) ? path : System.IO.Path.Combine(creator._repo.FullPath, path);
var info = new DirectoryInfo(fullPath); var info = new DirectoryInfo(fullPath);
if (info.Exists) if (info.Exists)

View file

@ -6,7 +6,6 @@ namespace SourceGit.ViewModels
{ {
public class Archive : Popup public class Archive : Popup
{ {
[Required(ErrorMessage = "Output file name is required")] [Required(ErrorMessage = "Output file name is required")]
public string SaveFile public string SaveFile
{ {
@ -67,7 +66,7 @@ namespace SourceGit.ViewModels
} }
private readonly Repository _repo = null; private readonly Repository _repo = null;
private string _saveFile = string.Empty; private string _saveFile;
private readonly string _revision = string.Empty; private readonly string _revision;
} }
} }

View file

@ -14,12 +14,6 @@ namespace SourceGit.ViewModels
private set; private set;
} }
public string SelectedSHA
{
get => _selectedSHA;
private set => SetProperty(ref _selectedSHA, value);
}
public bool IsBinary public bool IsBinary
{ {
get => _data != null && _data.IsBinary; get => _data != null && _data.IsBinary;
@ -53,8 +47,7 @@ namespace SourceGit.ViewModels
repo?.NavigateToCommit(commitSHA); repo?.NavigateToCommit(commitSHA);
} }
private readonly string _repo = string.Empty; private readonly string _repo;
private string _selectedSHA = string.Empty;
private Models.BlameData _data = null; private Models.BlameData _data = null;
} }
} }

View file

@ -201,7 +201,7 @@ namespace SourceGit.ViewModels
} }
} }
private string _repo = string.Empty; private string _repo;
private Models.Commit _baseHead = null; private Models.Commit _baseHead = null;
private Models.Commit _toHead = null; private Models.Commit _toHead = null;
private List<Models.Change> _changes = null; private List<Models.Change> _changes = null;

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
using Avalonia.Collections;
namespace SourceGit.ViewModels
{
public class ChangeCollectionAsTree
{
public List<ChangeTreeNode> Tree { get; set; } = new List<ChangeTreeNode>();
public AvaloniaList<ChangeTreeNode> Rows { get; set; } = new AvaloniaList<ChangeTreeNode>();
}
public class ChangeCollectionAsGrid
{
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
}
public class ChangeCollectionAsList
{
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
}
}

View file

@ -1,15 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
{ {
public class ChangeTreeNode : ObservableObject public class ChangeTreeNode : ObservableObject
{ {
public string FullPath { get; set; } = string.Empty; public string FullPath { get; set; }
public int Depth { get; private set; } = 0; public int Depth { get; private set; } = 0;
public Models.Change Change { get; set; } = null; public Models.Change Change { get; set; } = null;
public List<ChangeTreeNode> Children { get; set; } = new List<ChangeTreeNode>(); public List<ChangeTreeNode> Children { get; set; } = new List<ChangeTreeNode>();
@ -55,8 +53,7 @@ namespace SourceGit.ViewModels
else else
{ {
ChangeTreeNode lastFolder = null; ChangeTreeNode lastFolder = null;
var start = 0; int depth = 0;
var depth = 0;
while (sepIdx != -1) while (sepIdx != -1)
{ {
@ -79,12 +76,11 @@ namespace SourceGit.ViewModels
lastFolder = cur; lastFolder = cur;
} }
start = sepIdx + 1;
depth++; depth++;
sepIdx = c.Path.IndexOf('/', start); sepIdx = c.Path.IndexOf('/', sepIdx + 1);
} }
lastFolder.Children.Add(new ChangeTreeNode(c, depth)); lastFolder?.Children.Add(new ChangeTreeNode(c, depth));
} }
} }
@ -126,20 +122,4 @@ namespace SourceGit.ViewModels
private bool _isExpanded = true; private bool _isExpanded = true;
} }
public class ChangeCollectionAsTree
{
public List<ChangeTreeNode> Tree { get; set; } = new List<ChangeTreeNode>();
public AvaloniaList<ChangeTreeNode> Rows { get; set; } = new AvaloniaList<ChangeTreeNode>();
}
public class ChangeCollectionAsGrid
{
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
}
public class ChangeCollectionAsList
{
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
}
} }

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System;
using System.ComponentModel.DataAnnotations;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -105,8 +106,8 @@ namespace SourceGit.ViewModels
} }
else else
{ {
var name = Path.GetFileName(_remote); var name = Path.GetFileName(_remote)!;
if (name.EndsWith(".git")) if (name.EndsWith(".git", StringComparison.Ordinal))
name = name.Substring(0, name.Length - 4); name = name.Substring(0, name.Length - 4);
path = Path.GetFullPath(Path.Combine(path, name)); path = Path.GetFullPath(Path.Combine(path, name));
} }

View file

@ -176,14 +176,8 @@ namespace SourceGit.ViewModels
} }
else else
{ {
Dispatcher.UIThread.Invoke(() => var txt = new Models.RevisionTextFile() { Content = content };
{ Dispatcher.UIThread.Invoke(() => ViewRevisionFileContent = txt);
ViewRevisionFileContent = new Models.RevisionTextFile()
{
FileName = file.Path,
Content = content
};
});
} }
}); });
break; break;
@ -256,7 +250,7 @@ namespace SourceGit.ViewModels
var blame = new MenuItem(); var blame = new MenuItem();
blame.Header = App.Text("Blame"); blame.Header = App.Text("Blame");
blame.Icon = App.CreateMenuIcon("Icons.Blame"); blame.Icon = App.CreateMenuIcon("Icons.Blame");
blame.Click += (o, ev) => blame.Click += (_, ev) =>
{ {
var window = new Views.Blame() { DataContext = new Blame(_repo, change.Path, _commit.SHA) }; var window = new Views.Blame() { DataContext = new Blame(_repo, change.Path, _commit.SHA) };
window.Show(); window.Show();
@ -320,7 +314,7 @@ namespace SourceGit.ViewModels
blame.Header = App.Text("Blame"); blame.Header = App.Text("Blame");
blame.Icon = App.CreateMenuIcon("Icons.Blame"); blame.Icon = App.CreateMenuIcon("Icons.Blame");
blame.IsEnabled = file.Type == Models.ObjectType.Blob; blame.IsEnabled = file.Type == Models.ObjectType.Blob;
blame.Click += (o, ev) => blame.Click += (_, ev) =>
{ {
var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) }; var window = new Views.Blame() { DataContext = new Blame(_repo, file.Path, _commit.SHA) };
window.Show(); window.Show();
@ -461,7 +455,7 @@ namespace SourceGit.ViewModels
".ico", ".bmp", ".jpg", ".png", ".jpeg" ".ico", ".bmp", ".jpg", ".png", ".jpeg"
}; };
private string _repo = string.Empty; private string _repo;
private int _activePageIndex = 0; private int _activePageIndex = 0;
private Models.Commit _commit = null; private Models.Commit _commit = null;
private string _fullMessage = string.Empty; private string _fullMessage = string.Empty;

View file

@ -81,7 +81,7 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var succ = false; bool succ;
if (_annotated) if (_annotated)
succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag); succ = Commands.Tag.Add(_repo.FullPath, _tagName, _basedOn, Message, SignTag);
else else
@ -104,6 +104,6 @@ namespace SourceGit.ViewModels
private readonly Repository _repo = null; private readonly Repository _repo = null;
private string _tagName = string.Empty; private string _tagName = string.Empty;
private bool _annotated = true; private bool _annotated = true;
private readonly string _basedOn = string.Empty; private readonly string _basedOn;
} }
} }

View file

@ -30,7 +30,6 @@ namespace SourceGit.ViewModels
public string Title public string Title
{ {
get => _title; get => _title;
private set => SetProperty(ref _title, value);
} }
public string FileModeChange public string FileModeChange
@ -237,9 +236,9 @@ namespace SourceGit.ViewModels
".ico", ".bmp", ".jpg", ".png", ".jpeg" ".ico", ".bmp", ".jpg", ".png", ".jpeg"
}; };
private readonly string _repo = string.Empty; private readonly string _repo;
private readonly Models.DiffOption _option = null; private readonly Models.DiffOption _option = null;
private string _title = string.Empty; private string _title;
private string _fileModeChange = string.Empty; private string _fileModeChange = string.Empty;
private bool _isLoading = true; private bool _isLoading = true;
private bool _isTextDiff = false; private bool _isTextDiff = false;

View file

@ -9,7 +9,6 @@ namespace SourceGit.ViewModels
public class Discard : Popup public class Discard : Popup
{ {
public object Mode public object Mode
{ {
get; get;

View file

@ -67,7 +67,7 @@ namespace SourceGit.ViewModels
foreach (var remote in edit._repo.Remotes) foreach (var remote in edit._repo.Remotes)
{ {
if (remote != edit._remote && name == remote.Name) if (remote != edit._remote && name == remote.Name)
new ValidationResult("A remote with given name already exists!!!"); return new ValidationResult("A remote with given name already exists!!!");
} }
} }
@ -84,7 +84,7 @@ namespace SourceGit.ViewModels
foreach (var remote in edit._repo.Remotes) foreach (var remote in edit._repo.Remotes)
{ {
if (remote != edit._remote && url == remote.URL) if (remote != edit._remote && url == remote.URL)
new ValidationResult("A remote with the same url already exists!!!"); return new ValidationResult("A remote with the same url already exists!!!");
} }
} }
@ -136,8 +136,8 @@ namespace SourceGit.ViewModels
private readonly Repository _repo = null; private readonly Repository _repo = null;
private readonly Models.Remote _remote = null; private readonly Models.Remote _remote = null;
private string _name = string.Empty; private string _name = null;
private string _url = string.Empty; private string _url = null;
private bool _useSSH = false; private bool _useSSH = false;
private string _sshkey = string.Empty; private string _sshkey = string.Empty;
} }

View file

@ -5,12 +5,6 @@ namespace SourceGit.ViewModels
{ {
public class EditRepositoryNode : Popup public class EditRepositoryNode : Popup
{ {
public RepositoryNode Node
{
get => _node;
set => SetProperty(ref _node, value);
}
public string Id public string Id
{ {
get => _id; get => _id;
@ -60,8 +54,8 @@ namespace SourceGit.ViewModels
} }
private RepositoryNode _node = null; private RepositoryNode _node = null;
private string _id = string.Empty; private string _id = null;
private string _name = string.Empty; private string _name = null;
private bool _isRepository = false; private bool _isRepository = false;
private int _bookmark = 0; private int _bookmark = 0;
} }

View file

@ -68,6 +68,6 @@ namespace SourceGit.ViewModels
} }
private readonly Repository _repo = null; private readonly Repository _repo = null;
private bool _fetchAllRemotes = true; private bool _fetchAllRemotes;
} }
} }

View file

@ -73,8 +73,8 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly string _repo = string.Empty; private readonly string _repo = null;
private readonly string _file = string.Empty; private readonly string _file = null;
private bool _isLoading = true; private bool _isLoading = true;
private List<Models.Commit> _commits = null; private List<Models.Commit> _commits = null;
private Models.Commit _selectedCommit = null; private Models.Commit _selectedCommit = null;

View file

@ -43,8 +43,8 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private readonly string _type = "feature"; private readonly string _type;
private readonly string _prefix = string.Empty; private readonly string _prefix;
} }
} }

View file

@ -27,7 +27,7 @@ namespace SourceGit.ViewModels
{ {
_repo = repo; _repo = repo;
_type = type; _type = type;
_prefix = Commands.GitFlow.Prefix(repo.FullPath, type); _prefix = Commands.GitFlow.GetPrefix(repo.FullPath, type);
View = new Views.GitFlowStart() { DataContext = this }; View = new Views.GitFlowStart() { DataContext = this };
} }
@ -59,9 +59,9 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private readonly string _type = "feature"; private readonly string _type;
private readonly string _prefix = string.Empty; private readonly string _prefix;
private string _name = null; private string _name = null;
} }
} }

View file

@ -4,7 +4,7 @@ using System.Collections.Generic;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels namespace SourceGit.ViewModels
@ -156,7 +156,7 @@ namespace SourceGit.ViewModels
if (current == null) if (current == null)
return null; return null;
var commit = datagrid.SelectedItem as Models.Commit; var commit = (datagrid.SelectedItem as Models.Commit)!;
var menu = new ContextMenu(); var menu = new ContextMenu();
var tags = new List<Models.Tag>(); var tags = new List<Models.Tag>();
@ -202,7 +202,7 @@ namespace SourceGit.ViewModels
var reset = new MenuItem(); var reset = new MenuItem();
reset.Header = new Views.NameHighlightedTextBlock("CommitCM.Reset", current.Name); reset.Header = new Views.NameHighlightedTextBlock("CommitCM.Reset", current.Name);
reset.Icon = App.CreateMenuIcon("Icons.Reset"); reset.Icon = App.CreateMenuIcon("Icons.Reset");
reset.Click += (o, e) => reset.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Reset(_repo, current, commit)); PopupHost.ShowPopup(new Reset(_repo, current, commit));
@ -215,7 +215,7 @@ namespace SourceGit.ViewModels
var reword = new MenuItem(); var reword = new MenuItem();
reword.Header = App.Text("CommitCM.Reword"); reword.Header = App.Text("CommitCM.Reword");
reword.Icon = App.CreateMenuIcon("Icons.Edit"); reword.Icon = App.CreateMenuIcon("Icons.Edit");
reword.Click += (o, e) => reword.Click += (_, e) =>
{ {
if (_repo.WorkingCopyChangesCount > 0) if (_repo.WorkingCopyChangesCount > 0)
{ {
@ -233,7 +233,7 @@ namespace SourceGit.ViewModels
squash.Header = App.Text("CommitCM.Squash"); squash.Header = App.Text("CommitCM.Squash");
squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent"); squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent");
squash.IsEnabled = commit.Parents.Count == 1; squash.IsEnabled = commit.Parents.Count == 1;
squash.Click += (o, e) => squash.Click += (_, e) =>
{ {
if (_repo.WorkingCopyChangesCount > 0) if (_repo.WorkingCopyChangesCount > 0)
{ {
@ -258,7 +258,7 @@ namespace SourceGit.ViewModels
var rebase = new MenuItem(); var rebase = new MenuItem();
rebase.Header = new Views.NameHighlightedTextBlock("CommitCM.Rebase", current.Name); rebase.Header = new Views.NameHighlightedTextBlock("CommitCM.Rebase", current.Name);
rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Icon = App.CreateMenuIcon("Icons.Rebase");
rebase.Click += (o, e) => rebase.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Rebase(_repo, current, commit)); PopupHost.ShowPopup(new Rebase(_repo, current, commit));
@ -269,7 +269,7 @@ namespace SourceGit.ViewModels
var cherryPick = new MenuItem(); var cherryPick = new MenuItem();
cherryPick.Header = App.Text("CommitCM.CherryPick"); cherryPick.Header = App.Text("CommitCM.CherryPick");
cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick"); cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick");
cherryPick.Click += (o, e) => cherryPick.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CherryPick(_repo, commit)); PopupHost.ShowPopup(new CherryPick(_repo, commit));
@ -282,7 +282,7 @@ namespace SourceGit.ViewModels
var revert = new MenuItem(); var revert = new MenuItem();
revert.Header = App.Text("CommitCM.Revert"); revert.Header = App.Text("CommitCM.Revert");
revert.Icon = App.CreateMenuIcon("Icons.Undo"); revert.Icon = App.CreateMenuIcon("Icons.Undo");
revert.Click += (o, e) => revert.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Revert(_repo, commit)); PopupHost.ShowPopup(new Revert(_repo, commit));
@ -294,7 +294,7 @@ namespace SourceGit.ViewModels
interactiveRebase.Header = new Views.NameHighlightedTextBlock("CommitCM.InteractiveRebase", current.Name); interactiveRebase.Header = new Views.NameHighlightedTextBlock("CommitCM.InteractiveRebase", current.Name);
interactiveRebase.Icon = App.CreateMenuIcon("Icons.InteractiveRebase"); interactiveRebase.Icon = App.CreateMenuIcon("Icons.InteractiveRebase");
interactiveRebase.IsVisible = current.Head != commit.SHA; interactiveRebase.IsVisible = current.Head != commit.SHA;
interactiveRebase.Click += (o, e) => interactiveRebase.Click += (_, e) =>
{ {
if (_repo.WorkingCopyChangesCount > 0) if (_repo.WorkingCopyChangesCount > 0)
{ {
@ -302,8 +302,12 @@ namespace SourceGit.ViewModels
return; return;
} }
var toplevel = datagrid.FindAncestorOfType<Views.Launcher>();
if (toplevel == null)
return;
var dialog = new Views.InteractiveRebase() { DataContext = new InteractiveRebase(_repo, current, commit) }; var dialog = new Views.InteractiveRebase() { DataContext = new InteractiveRebase(_repo, current, commit) };
dialog.ShowDialog(App.GetTopLevel() as Window); dialog.ShowDialog(toplevel);
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(interactiveRebase); menu.Items.Add(interactiveRebase);
@ -314,7 +318,7 @@ namespace SourceGit.ViewModels
var checkoutCommit = new MenuItem(); var checkoutCommit = new MenuItem();
checkoutCommit.Header = App.Text("CommitCM.Checkout"); checkoutCommit.Header = App.Text("CommitCM.Checkout");
checkoutCommit.Icon = App.CreateMenuIcon("Icons.Detached"); checkoutCommit.Icon = App.CreateMenuIcon("Icons.Detached");
checkoutCommit.Click += (o, e) => checkoutCommit.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CheckoutCommit(_repo, commit)); PopupHost.ShowPopup(new CheckoutCommit(_repo, commit));
@ -330,7 +334,7 @@ namespace SourceGit.ViewModels
var compareWithHead = new MenuItem(); var compareWithHead = new MenuItem();
compareWithHead.Header = App.Text("CommitCM.CompareWithHead"); compareWithHead.Header = App.Text("CommitCM.CompareWithHead");
compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare"); compareWithHead.Icon = App.CreateMenuIcon("Icons.Compare");
compareWithHead.Click += (o, e) => compareWithHead.Click += (_, e) =>
{ {
var head = _commits.Find(x => x.SHA == current.Head); var head = _commits.Find(x => x.SHA == current.Head);
if (head == null) if (head == null)
@ -354,7 +358,7 @@ namespace SourceGit.ViewModels
var compareWithWorktree = new MenuItem(); var compareWithWorktree = new MenuItem();
compareWithWorktree.Header = App.Text("CommitCM.CompareWithWorktree"); compareWithWorktree.Header = App.Text("CommitCM.CompareWithWorktree");
compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare"); compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare");
compareWithWorktree.Click += (o, e) => compareWithWorktree.Click += (_, e) =>
{ {
DetailContext = new RevisionCompare(_repo.FullPath, commit, null); DetailContext = new RevisionCompare(_repo.FullPath, commit, null);
e.Handled = true; e.Handled = true;
@ -368,7 +372,7 @@ namespace SourceGit.ViewModels
var createBranch = new MenuItem(); var createBranch = new MenuItem();
createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add");
createBranch.Header = App.Text("CreateBranch"); createBranch.Header = App.Text("CreateBranch");
createBranch.Click += (o, e) => createBranch.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateBranch(_repo, commit)); PopupHost.ShowPopup(new CreateBranch(_repo, commit));
@ -379,7 +383,7 @@ namespace SourceGit.ViewModels
var createTag = new MenuItem(); var createTag = new MenuItem();
createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add");
createTag.Header = App.Text("CreateTag"); createTag.Header = App.Text("CreateTag");
createTag.Click += (o, e) => createTag.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateTag(_repo, commit)); PopupHost.ShowPopup(new CreateTag(_repo, commit));
@ -413,7 +417,7 @@ namespace SourceGit.ViewModels
var archive = new MenuItem(); var archive = new MenuItem();
archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Icon = App.CreateMenuIcon("Icons.Archive");
archive.Header = App.Text("Archive"); archive.Header = App.Text("Archive");
archive.Click += (o, e) => archive.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Archive(_repo, commit)); PopupHost.ShowPopup(new Archive(_repo, commit));
@ -425,7 +429,7 @@ namespace SourceGit.ViewModels
var copySHA = new MenuItem(); var copySHA = new MenuItem();
copySHA.Header = App.Text("CommitCM.CopySHA"); copySHA.Header = App.Text("CommitCM.CopySHA");
copySHA.Icon = App.CreateMenuIcon("Icons.Copy"); copySHA.Icon = App.CreateMenuIcon("Icons.Copy");
copySHA.Click += (o, e) => copySHA.Click += (_, e) =>
{ {
App.CopyText(commit.SHA); App.CopyText(commit.SHA);
e.Handled = true; e.Handled = true;
@ -448,7 +452,7 @@ namespace SourceGit.ViewModels
fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream);
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = !string.IsNullOrEmpty(current.UpstreamTrackStatus) && current.UpstreamTrackStatus.IndexOf('↑') < 0; fastForward.IsEnabled = !string.IsNullOrEmpty(current.UpstreamTrackStatus) && current.UpstreamTrackStatus.IndexOf('↑') < 0;
fastForward.Click += (o, e) => fastForward.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new Merge(_repo, upstream, current.Name)); PopupHost.ShowAndStartPopup(new Merge(_repo, upstream, current.Name));
@ -459,7 +463,7 @@ namespace SourceGit.ViewModels
var pull = new MenuItem(); var pull = new MenuItem();
pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream); pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream);
pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.Icon = App.CreateMenuIcon("Icons.Pull");
pull.Click += (o, e) => pull.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Pull(_repo, null)); PopupHost.ShowPopup(new Pull(_repo, null));
@ -472,7 +476,7 @@ namespace SourceGit.ViewModels
push.Header = new Views.NameHighlightedTextBlock("BranchCM.Push", current.Name); push.Header = new Views.NameHighlightedTextBlock("BranchCM.Push", current.Name);
push.Icon = App.CreateMenuIcon("Icons.Push"); push.Icon = App.CreateMenuIcon("Icons.Push");
push.IsEnabled = _repo.Remotes.Count > 0; push.IsEnabled = _repo.Remotes.Count > 0;
push.Click += (o, e) => push.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Push(_repo, current)); PopupHost.ShowPopup(new Push(_repo, current));
@ -487,7 +491,7 @@ namespace SourceGit.ViewModels
var finish = new MenuItem(); var finish = new MenuItem();
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name);
finish.Icon = App.CreateMenuIcon("Icons.GitFlow"); finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
finish.Click += (o, e) => finish.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix)); PopupHost.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix));
@ -500,7 +504,7 @@ namespace SourceGit.ViewModels
var rename = new MenuItem(); var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", current.Name); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", current.Name);
rename.Icon = App.CreateMenuIcon("Icons.Rename"); rename.Icon = App.CreateMenuIcon("Icons.Rename");
rename.Click += (o, e) => rename.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new RenameBranch(_repo, current)); PopupHost.ShowPopup(new RenameBranch(_repo, current));
@ -520,7 +524,7 @@ namespace SourceGit.ViewModels
var checkout = new MenuItem(); var checkout = new MenuItem();
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => checkout.Click += (_, e) =>
{ {
_repo.CheckoutBranch(branch); _repo.CheckoutBranch(branch);
e.Handled = true; e.Handled = true;
@ -531,7 +535,7 @@ namespace SourceGit.ViewModels
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.IsEnabled = !merged; merge.IsEnabled = !merged;
merge.Click += (o, e) => merge.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Merge(_repo, branch.Name, current.Name)); PopupHost.ShowPopup(new Merge(_repo, branch.Name, current.Name));
@ -546,7 +550,7 @@ namespace SourceGit.ViewModels
var finish = new MenuItem(); var finish = new MenuItem();
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
finish.Icon = App.CreateMenuIcon("Icons.GitFlow"); finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
finish.Click += (o, e) => finish.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix)); PopupHost.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix));
@ -559,7 +563,7 @@ namespace SourceGit.ViewModels
var rename = new MenuItem(); var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name);
rename.Icon = App.CreateMenuIcon("Icons.Rename"); rename.Icon = App.CreateMenuIcon("Icons.Rename");
rename.Click += (o, e) => rename.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new RenameBranch(_repo, branch)); PopupHost.ShowPopup(new RenameBranch(_repo, branch));
@ -570,7 +574,7 @@ namespace SourceGit.ViewModels
var delete = new MenuItem(); var delete = new MenuItem();
delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", branch.Name); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", branch.Name);
delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Icon = App.CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => delete.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteBranch(_repo, branch)); PopupHost.ShowPopup(new DeleteBranch(_repo, branch));
@ -592,7 +596,7 @@ namespace SourceGit.ViewModels
var checkout = new MenuItem(); var checkout = new MenuItem();
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", name); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", name);
checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => checkout.Click += (_, e) =>
{ {
_repo.CheckoutBranch(branch); _repo.CheckoutBranch(branch);
e.Handled = true; e.Handled = true;
@ -603,7 +607,7 @@ namespace SourceGit.ViewModels
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", name, current.Name); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", name, current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.IsEnabled = !merged; merge.IsEnabled = !merged;
merge.Click += (o, e) => merge.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Merge(_repo, name, current.Name)); PopupHost.ShowPopup(new Merge(_repo, name, current.Name));
@ -616,7 +620,7 @@ namespace SourceGit.ViewModels
var delete = new MenuItem(); var delete = new MenuItem();
delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", name); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", name);
delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Icon = App.CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => delete.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteBranch(_repo, branch)); PopupHost.ShowPopup(new DeleteBranch(_repo, branch));
@ -638,7 +642,7 @@ namespace SourceGit.ViewModels
push.Header = new Views.NameHighlightedTextBlock("TagCM.Push", tag.Name); push.Header = new Views.NameHighlightedTextBlock("TagCM.Push", tag.Name);
push.Icon = App.CreateMenuIcon("Icons.Push"); push.Icon = App.CreateMenuIcon("Icons.Push");
push.IsEnabled = _repo.Remotes.Count > 0; push.IsEnabled = _repo.Remotes.Count > 0;
push.Click += (o, e) => push.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new PushTag(_repo, tag)); PopupHost.ShowPopup(new PushTag(_repo, tag));
@ -649,7 +653,7 @@ namespace SourceGit.ViewModels
var delete = new MenuItem(); var delete = new MenuItem();
delete.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name); delete.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name);
delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Icon = App.CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => delete.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteTag(_repo, tag)); PopupHost.ShowPopup(new DeleteTag(_repo, tag));

View file

@ -38,7 +38,7 @@ namespace SourceGit.ViewModels
}); });
} }
private string _targetPath = string.Empty; private string _targetPath = null;
private RepositoryNode _parentNode = null; private RepositoryNode _parentNode = null;
} }
} }

View file

@ -114,8 +114,8 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private string _master = "master"; private string _master;
private string _develop = "develop"; private string _develop = "develop";
private string _featurePrefix = "feature/"; private string _featurePrefix = "feature/";
private string _releasePrefix = "release/"; private string _releasePrefix = "release/";

View file

@ -62,8 +62,8 @@ namespace SourceGit.ViewModels
} }
private Models.InteractiveRebaseAction _action = Models.InteractiveRebaseAction.Pick; private Models.InteractiveRebaseAction _action = Models.InteractiveRebaseAction.Pick;
private string _subject = string.Empty; private string _subject;
private string _fullMessage = string.Empty; private string _fullMessage;
} }
public class InteractiveRebase : ObservableObject public class InteractiveRebase : ObservableObject

View file

@ -67,8 +67,8 @@ namespace SourceGit.ViewModels
}); });
} }
private string _repo = string.Empty; private string _repo;
private string _remote = string.Empty; private string _remote;
private bool _isLoading = true; private bool _isLoading = true;
private bool _isEmpty = false; private bool _isEmpty = false;
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using Avalonia;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
@ -292,12 +293,6 @@ namespace SourceGit.ViewModels
_activePage.Notifications.Add(notification); _activePage.Notifications.Add(notification);
} }
public void DismissNotification(Notification notice)
{
if (notice != null)
ActivePage?.Notifications.Remove(notice);
}
public ContextMenu CreateContextForPageTab(LauncherPage page) public ContextMenu CreateContextForPageTab(LauncherPage page)
{ {
if (page == null) if (page == null)
@ -307,7 +302,7 @@ namespace SourceGit.ViewModels
var close = new MenuItem(); var close = new MenuItem();
close.Header = App.Text("PageTabBar.Tab.Close"); close.Header = App.Text("PageTabBar.Tab.Close");
close.InputGesture = KeyGesture.Parse(OperatingSystem.IsMacOS() ? "⌘+W" : "Ctrl+W"); close.InputGesture = KeyGesture.Parse(OperatingSystem.IsMacOS() ? "⌘+W" : "Ctrl+W");
close.Click += (o, e) => close.Click += (_, e) =>
{ {
CloseTab(page); CloseTab(page);
e.Handled = true; e.Handled = true;
@ -316,7 +311,7 @@ namespace SourceGit.ViewModels
var closeOthers = new MenuItem(); var closeOthers = new MenuItem();
closeOthers.Header = App.Text("PageTabBar.Tab.CloseOther"); closeOthers.Header = App.Text("PageTabBar.Tab.CloseOther");
closeOthers.Click += (o, e) => closeOthers.Click += (_, e) =>
{ {
CloseOtherTabs(); CloseOtherTabs();
e.Handled = true; e.Handled = true;
@ -325,7 +320,7 @@ namespace SourceGit.ViewModels
var closeRight = new MenuItem(); var closeRight = new MenuItem();
closeRight.Header = App.Text("PageTabBar.Tab.CloseRight"); closeRight.Header = App.Text("PageTabBar.Tab.CloseRight");
closeRight.Click += (o, e) => closeRight.Click += (_, e) =>
{ {
CloseRightTabs(); CloseRightTabs();
e.Handled = true; e.Handled = true;
@ -342,13 +337,13 @@ namespace SourceGit.ViewModels
{ {
var icon = App.CreateMenuIcon("Icons.Bookmark"); var icon = App.CreateMenuIcon("Icons.Bookmark");
icon.Fill = Models.Bookmarks.Brushes[i]; icon.Fill = Models.Bookmarks.Brushes[i];
icon.Stroke = App.Current.FindResource("Brush.FG1") as Brush; icon.Stroke = Application.Current?.FindResource("Brush.FG1") as Brush;
icon.StrokeThickness = i == 0 ? 1.0 : 0; icon.StrokeThickness = i == 0 ? 1.0 : 0;
var dupIdx = i; var dupIdx = i;
var setter = new MenuItem(); var setter = new MenuItem();
setter.Header = icon; setter.Header = icon;
setter.Click += (o, e) => setter.Click += (_, e) =>
{ {
page.Node.Bookmark = dupIdx; page.Node.Bookmark = dupIdx;
e.Handled = true; e.Handled = true;
@ -361,7 +356,7 @@ namespace SourceGit.ViewModels
var copyPath = new MenuItem(); var copyPath = new MenuItem();
copyPath.Header = App.Text("PageTabBar.Tab.CopyPath"); copyPath.Header = App.Text("PageTabBar.Tab.CopyPath");
copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
copyPath.Click += (o, e) => copyPath.Click += (_, e) =>
{ {
page.CopyPath(); page.CopyPath();
e.Handled = true; e.Handled = true;

View file

@ -1,8 +1,4 @@
using System; using Avalonia.Controls;
using System.Text.Json;
using System.Text.Json.Serialization;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;

View file

@ -112,7 +112,7 @@ namespace SourceGit.ViewModels
if (Models.AvatarManager.SelectedServer != value) if (Models.AvatarManager.SelectedServer != value)
{ {
Models.AvatarManager.SelectedServer = value; Models.AvatarManager.SelectedServer = value;
OnPropertyChanged(nameof(AvatarServer)); OnPropertyChanged();
} }
} }
} }
@ -221,7 +221,7 @@ namespace SourceGit.ViewModels
if (Native.OS.GitExecutable != value) if (Native.OS.GitExecutable != value)
{ {
Native.OS.GitExecutable = value; Native.OS.GitExecutable = value;
OnPropertyChanged(nameof(GitInstallPath)); OnPropertyChanged();
} }
} }
} }
@ -233,7 +233,7 @@ namespace SourceGit.ViewModels
{ {
if (Native.OS.SetShell(value)) if (Native.OS.SetShell(value))
{ {
OnPropertyChanged(nameof(GitShell)); OnPropertyChanged();
} }
} }
} }
@ -252,7 +252,7 @@ namespace SourceGit.ViewModels
if (Commands.AutoFetch.IsEnabled != value) if (Commands.AutoFetch.IsEnabled != value)
{ {
Commands.AutoFetch.IsEnabled = value; Commands.AutoFetch.IsEnabled = value;
OnPropertyChanged(nameof(GitAutoFetch)); OnPropertyChanged();
} }
} }
} }
@ -268,7 +268,7 @@ namespace SourceGit.ViewModels
if (Commands.AutoFetch.Interval != value) if (Commands.AutoFetch.Interval != value)
{ {
Commands.AutoFetch.Interval = (int)value; Commands.AutoFetch.Interval = (int)value;
OnPropertyChanged(nameof(GitAutoFetchInterval)); OnPropertyChanged();
} }
} }
} }

View file

@ -114,7 +114,7 @@ namespace SourceGit.ViewModels
} }
// Find preferred remote if selected local branch has upstream. // Find preferred remote if selected local branch has upstream.
if (!string.IsNullOrEmpty(_selectedLocalBranch.Upstream)) if (!string.IsNullOrEmpty(_selectedLocalBranch?.Upstream))
{ {
foreach (var branch in repo.Branches) foreach (var branch in repo.Branches)
{ {

View file

@ -55,7 +55,7 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private readonly string _revision = string.Empty; private readonly string _revision;
} }
} }

View file

@ -60,7 +60,7 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private string _name = string.Empty; private string _name;
} }
} }

View file

@ -129,7 +129,6 @@ namespace SourceGit.ViewModels
public RepositorySettings Settings public RepositorySettings Settings
{ {
get => _settings; get => _settings;
private set => SetProperty(ref _settings, value);
} }
public int SelectedViewIndex public int SelectedViewIndex
@ -436,7 +435,7 @@ namespace SourceGit.ViewModels
var item = new MenuItem(); var item = new MenuItem();
item.Header = App.Text("Repository.OpenIn", dupTool.Name); item.Header = App.Text("Repository.OpenIn", dupTool.Name);
item.Icon = new Image { Width = 16, Height = 16, Source = dupTool.IconImage }; item.Icon = new Image { Width = 16, Height = 16, Source = dupTool.IconImage };
item.Click += (o, e) => item.Click += (_, e) =>
{ {
dupTool.Open(_fullpath); dupTool.Open(_fullpath);
e.Handled = true; e.Handled = true;
@ -1013,7 +1012,7 @@ namespace SourceGit.ViewModels
var startFeature = new MenuItem(); var startFeature = new MenuItem();
startFeature.Header = App.Text("GitFlow.StartFeature"); startFeature.Header = App.Text("GitFlow.StartFeature");
startFeature.Icon = App.CreateMenuIcon("Icons.GitFlow.Feature"); startFeature.Icon = App.CreateMenuIcon("Icons.GitFlow.Feature");
startFeature.Click += (o, e) => startFeature.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowStart(this, "feature")); PopupHost.ShowPopup(new GitFlowStart(this, "feature"));
@ -1023,7 +1022,7 @@ namespace SourceGit.ViewModels
var startRelease = new MenuItem(); var startRelease = new MenuItem();
startRelease.Header = App.Text("GitFlow.StartRelease"); startRelease.Header = App.Text("GitFlow.StartRelease");
startRelease.Icon = App.CreateMenuIcon("Icons.GitFlow.Release"); startRelease.Icon = App.CreateMenuIcon("Icons.GitFlow.Release");
startRelease.Click += (o, e) => startRelease.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowStart(this, "release")); PopupHost.ShowPopup(new GitFlowStart(this, "release"));
@ -1033,7 +1032,7 @@ namespace SourceGit.ViewModels
var startHotfix = new MenuItem(); var startHotfix = new MenuItem();
startHotfix.Header = App.Text("GitFlow.StartHotfix"); startHotfix.Header = App.Text("GitFlow.StartHotfix");
startHotfix.Icon = App.CreateMenuIcon("Icons.GitFlow.Hotfix"); startHotfix.Icon = App.CreateMenuIcon("Icons.GitFlow.Hotfix");
startHotfix.Click += (o, e) => startHotfix.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowStart(this, "hotfix")); PopupHost.ShowPopup(new GitFlowStart(this, "hotfix"));
@ -1049,7 +1048,7 @@ namespace SourceGit.ViewModels
var init = new MenuItem(); var init = new MenuItem();
init.Header = App.Text("GitFlow.Init"); init.Header = App.Text("GitFlow.Init");
init.Icon = App.CreateMenuIcon("Icons.Init"); init.Icon = App.CreateMenuIcon("Icons.Init");
init.Click += (o, e) => init.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new InitGitFlow(this)); PopupHost.ShowPopup(new InitGitFlow(this));
@ -1071,7 +1070,7 @@ namespace SourceGit.ViewModels
var addPattern = new MenuItem(); var addPattern = new MenuItem();
addPattern.Header = App.Text("GitLFS.AddTrackPattern"); addPattern.Header = App.Text("GitLFS.AddTrackPattern");
addPattern.Icon = App.CreateMenuIcon("Icons.File.Add"); addPattern.Icon = App.CreateMenuIcon("Icons.File.Add");
addPattern.Click += (o, e) => addPattern.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new LFSTrackCustomPattern(this)); PopupHost.ShowPopup(new LFSTrackCustomPattern(this));
@ -1085,7 +1084,7 @@ namespace SourceGit.ViewModels
fetch.Header = App.Text("GitLFS.Fetch"); fetch.Header = App.Text("GitLFS.Fetch");
fetch.Icon = App.CreateMenuIcon("Icons.Fetch"); fetch.Icon = App.CreateMenuIcon("Icons.Fetch");
fetch.IsEnabled = Remotes.Count > 0; fetch.IsEnabled = Remotes.Count > 0;
fetch.Click += (o, e) => fetch.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
{ {
@ -1103,7 +1102,7 @@ namespace SourceGit.ViewModels
pull.Header = App.Text("GitLFS.Pull"); pull.Header = App.Text("GitLFS.Pull");
pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.Icon = App.CreateMenuIcon("Icons.Pull");
pull.IsEnabled = Remotes.Count > 0; pull.IsEnabled = Remotes.Count > 0;
pull.Click += (o, e) => pull.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
{ {
@ -1121,7 +1120,7 @@ namespace SourceGit.ViewModels
push.Header = App.Text("GitLFS.Push"); push.Header = App.Text("GitLFS.Push");
push.Icon = App.CreateMenuIcon("Icons.Push"); push.Icon = App.CreateMenuIcon("Icons.Push");
push.IsEnabled = Remotes.Count > 0; push.IsEnabled = Remotes.Count > 0;
push.Click += (o, e) => push.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
{ {
@ -1138,7 +1137,7 @@ namespace SourceGit.ViewModels
var prune = new MenuItem(); var prune = new MenuItem();
prune.Header = App.Text("GitLFS.Prune"); prune.Header = App.Text("GitLFS.Prune");
prune.Icon = App.CreateMenuIcon("Icons.Clean"); prune.Icon = App.CreateMenuIcon("Icons.Clean");
prune.Click += (o, e) => prune.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new LFSPrune(this)); PopupHost.ShowAndStartPopup(new LFSPrune(this));
@ -1154,10 +1153,14 @@ namespace SourceGit.ViewModels
locks.IsEnabled = Remotes.Count > 0; locks.IsEnabled = Remotes.Count > 0;
if (Remotes.Count == 1) if (Remotes.Count == 1)
{ {
locks.Click += (o, e) => locks.Click += (_, e) =>
{ {
var topLevel = App.GetTopLevel() as Window;
if (topLevel == null)
return;
var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(_fullpath, Remotes[0].Name) }; var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(_fullpath, Remotes[0].Name) };
dialog.Show(App.GetTopLevel() as Window); dialog.Show(topLevel);
e.Handled = true; e.Handled = true;
}; };
} }
@ -1168,10 +1171,14 @@ namespace SourceGit.ViewModels
var remoteName = remote.Name; var remoteName = remote.Name;
var lockRemote = new MenuItem(); var lockRemote = new MenuItem();
lockRemote.Header = remoteName; lockRemote.Header = remoteName;
lockRemote.Click += (o, e) => lockRemote.Click += (_, e) =>
{ {
var topLevel = App.GetTopLevel() as Window;
if (topLevel == null)
return;
var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(_fullpath, remoteName) }; var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(_fullpath, remoteName) };
dialog.Show(App.GetTopLevel() as Window); dialog.Show(topLevel);
e.Handled = true; e.Handled = true;
}; };
locks.Items.Add(lockRemote); locks.Items.Add(lockRemote);
@ -1186,7 +1193,7 @@ namespace SourceGit.ViewModels
var install = new MenuItem(); var install = new MenuItem();
install.Header = App.Text("GitLFS.Install"); install.Header = App.Text("GitLFS.Install");
install.Icon = App.CreateMenuIcon("Icons.Init"); install.Icon = App.CreateMenuIcon("Icons.Init");
install.Click += (o, e) => install.Click += (_, e) =>
{ {
var succ = new Commands.LFS(_fullpath).Install(); var succ = new Commands.LFS(_fullpath).Install();
if (succ) if (succ)
@ -1221,7 +1228,7 @@ namespace SourceGit.ViewModels
discard.Header = App.Text("BranchCM.DiscardAll"); discard.Header = App.Text("BranchCM.DiscardAll");
discard.Icon = App.CreateMenuIcon("Icons.Undo"); discard.Icon = App.CreateMenuIcon("Icons.Undo");
discard.IsEnabled = _workingCopy.Count > 0; discard.IsEnabled = _workingCopy.Count > 0;
discard.Click += (o, e) => discard.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Discard(this)); PopupHost.ShowPopup(new Discard(this));
@ -1238,7 +1245,7 @@ namespace SourceGit.ViewModels
fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream);
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0; fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0;
fastForward.Click += (o, e) => fastForward.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new Merge(this, upstream, branch.Name)); PopupHost.ShowAndStartPopup(new Merge(this, upstream, branch.Name));
@ -1248,7 +1255,7 @@ namespace SourceGit.ViewModels
var pull = new MenuItem(); var pull = new MenuItem();
pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream); pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream);
pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.Icon = App.CreateMenuIcon("Icons.Pull");
pull.Click += (o, e) => pull.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Pull(this, null)); PopupHost.ShowPopup(new Pull(this, null));
@ -1275,7 +1282,7 @@ namespace SourceGit.ViewModels
var checkout = new MenuItem(); var checkout = new MenuItem();
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => checkout.Click += (_, e) =>
{ {
CheckoutBranch(branch); CheckoutBranch(branch);
e.Handled = true; e.Handled = true;
@ -1289,7 +1296,7 @@ namespace SourceGit.ViewModels
fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream.FriendlyName); fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream.FriendlyName);
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward"); fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0; fastForward.IsEnabled = !string.IsNullOrEmpty(branch.UpstreamTrackStatus) && branch.UpstreamTrackStatus.IndexOf('↑') < 0;
fastForward.Click += (o, e) => fastForward.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new FastForwardWithoutCheckout(this, branch, upstream)); PopupHost.ShowAndStartPopup(new FastForwardWithoutCheckout(this, branch, upstream));
@ -1306,7 +1313,7 @@ namespace SourceGit.ViewModels
var merge = new MenuItem(); var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.Click += (o, e) => merge.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Merge(this, branch.Name, current.Name)); PopupHost.ShowPopup(new Merge(this, branch.Name, current.Name));
@ -1316,7 +1323,7 @@ namespace SourceGit.ViewModels
var rebase = new MenuItem(); var rebase = new MenuItem();
rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", current.Name, branch.Name); rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", current.Name, branch.Name);
rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Icon = App.CreateMenuIcon("Icons.Rebase");
rebase.Click += (o, e) => rebase.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Rebase(this, current, branch)); PopupHost.ShowPopup(new Rebase(this, current, branch));
@ -1331,7 +1338,7 @@ namespace SourceGit.ViewModels
var compareWithWorktree = new MenuItem(); var compareWithWorktree = new MenuItem();
compareWithWorktree.Header = App.Text("BranchCM.CompareWithWorktree"); compareWithWorktree.Header = App.Text("BranchCM.CompareWithWorktree");
compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare"); compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare");
compareWithWorktree.Click += (o, e) => compareWithWorktree.Click += (_, _) =>
{ {
SearchResultSelectedCommit = null; SearchResultSelectedCommit = null;
@ -1362,7 +1369,7 @@ namespace SourceGit.ViewModels
var finish = new MenuItem(); var finish = new MenuItem();
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
finish.Icon = App.CreateMenuIcon("Icons.GitFlow"); finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
finish.Click += (o, e) => finish.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix)); PopupHost.ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix));
@ -1375,7 +1382,7 @@ namespace SourceGit.ViewModels
var rename = new MenuItem(); var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name);
rename.Icon = App.CreateMenuIcon("Icons.Rename"); rename.Icon = App.CreateMenuIcon("Icons.Rename");
rename.Click += (o, e) => rename.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new RenameBranch(this, branch)); PopupHost.ShowPopup(new RenameBranch(this, branch));
@ -1386,7 +1393,7 @@ namespace SourceGit.ViewModels
delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", branch.Name); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", branch.Name);
delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Icon = App.CreateMenuIcon("Icons.Clear");
delete.IsEnabled = !branch.IsCurrent; delete.IsEnabled = !branch.IsCurrent;
delete.Click += (o, e) => delete.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteBranch(this, branch)); PopupHost.ShowPopup(new DeleteBranch(this, branch));
@ -1396,7 +1403,7 @@ namespace SourceGit.ViewModels
var createBranch = new MenuItem(); var createBranch = new MenuItem();
createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add");
createBranch.Header = App.Text("CreateBranch"); createBranch.Header = App.Text("CreateBranch");
createBranch.Click += (o, e) => createBranch.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateBranch(this, branch)); PopupHost.ShowPopup(new CreateBranch(this, branch));
@ -1406,7 +1413,7 @@ namespace SourceGit.ViewModels
var createTag = new MenuItem(); var createTag = new MenuItem();
createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add");
createTag.Header = App.Text("CreateTag"); createTag.Header = App.Text("CreateTag");
createTag.Click += (o, e) => createTag.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateTag(this, branch)); PopupHost.ShowPopup(new CreateTag(this, branch));
@ -1442,7 +1449,7 @@ namespace SourceGit.ViewModels
if (branch.Upstream == b.FullName) if (branch.Upstream == b.FullName)
target.Icon = App.CreateMenuIcon("Icons.Check"); target.Icon = App.CreateMenuIcon("Icons.Check");
target.Click += (o, e) => target.Click += (_, e) =>
{ {
if (Commands.Branch.SetUpstream(_fullpath, branch.Name, upstream)) if (Commands.Branch.SetUpstream(_fullpath, branch.Name, upstream))
Task.Run(RefreshBranches); Task.Run(RefreshBranches);
@ -1471,7 +1478,7 @@ namespace SourceGit.ViewModels
var archive = new MenuItem(); var archive = new MenuItem();
archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Icon = App.CreateMenuIcon("Icons.Archive");
archive.Header = App.Text("Archive"); archive.Header = App.Text("Archive");
archive.Click += (o, e) => archive.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Archive(this, branch)); PopupHost.ShowPopup(new Archive(this, branch));
@ -1483,7 +1490,7 @@ namespace SourceGit.ViewModels
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("BranchCM.CopyName"); copy.Header = App.Text("BranchCM.CopyName");
copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, e) => copy.Click += (_, e) =>
{ {
App.CopyText(branch.Name); App.CopyText(branch.Name);
e.Handled = true; e.Handled = true;
@ -1502,7 +1509,7 @@ namespace SourceGit.ViewModels
var visit = new MenuItem(); var visit = new MenuItem();
visit.Header = App.Text("RemoteCM.OpenInBrowser"); visit.Header = App.Text("RemoteCM.OpenInBrowser");
visit.Icon = App.CreateMenuIcon("Icons.OpenWith"); visit.Icon = App.CreateMenuIcon("Icons.OpenWith");
visit.Click += (o, e) => visit.Click += (_, e) =>
{ {
Native.OS.OpenBrowser(visitURL); Native.OS.OpenBrowser(visitURL);
e.Handled = true; e.Handled = true;
@ -1515,7 +1522,7 @@ namespace SourceGit.ViewModels
var fetch = new MenuItem(); var fetch = new MenuItem();
fetch.Header = App.Text("RemoteCM.Fetch"); fetch.Header = App.Text("RemoteCM.Fetch");
fetch.Icon = App.CreateMenuIcon("Icons.Fetch"); fetch.Icon = App.CreateMenuIcon("Icons.Fetch");
fetch.Click += (o, e) => fetch.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new Fetch(this, remote)); PopupHost.ShowAndStartPopup(new Fetch(this, remote));
@ -1525,7 +1532,7 @@ namespace SourceGit.ViewModels
var prune = new MenuItem(); var prune = new MenuItem();
prune.Header = App.Text("RemoteCM.Prune"); prune.Header = App.Text("RemoteCM.Prune");
prune.Icon = App.CreateMenuIcon("Icons.Clean"); prune.Icon = App.CreateMenuIcon("Icons.Clean");
prune.Click += (o, e) => prune.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new PruneRemote(this, remote)); PopupHost.ShowAndStartPopup(new PruneRemote(this, remote));
@ -1535,7 +1542,7 @@ namespace SourceGit.ViewModels
var edit = new MenuItem(); var edit = new MenuItem();
edit.Header = App.Text("RemoteCM.Edit"); edit.Header = App.Text("RemoteCM.Edit");
edit.Icon = App.CreateMenuIcon("Icons.Edit"); edit.Icon = App.CreateMenuIcon("Icons.Edit");
edit.Click += (o, e) => edit.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new EditRemote(this, remote)); PopupHost.ShowPopup(new EditRemote(this, remote));
@ -1545,7 +1552,7 @@ namespace SourceGit.ViewModels
var delete = new MenuItem(); var delete = new MenuItem();
delete.Header = App.Text("RemoteCM.Delete"); delete.Header = App.Text("RemoteCM.Delete");
delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Icon = App.CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => delete.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteRemote(this, remote)); PopupHost.ShowPopup(new DeleteRemote(this, remote));
@ -1555,7 +1562,7 @@ namespace SourceGit.ViewModels
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("RemoteCM.CopyURL"); copy.Header = App.Text("RemoteCM.CopyURL");
copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, e) => copy.Click += (_, e) =>
{ {
App.CopyText(remote.URL); App.CopyText(remote.URL);
e.Handled = true; e.Handled = true;
@ -1580,7 +1587,7 @@ namespace SourceGit.ViewModels
var checkout = new MenuItem(); var checkout = new MenuItem();
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", name); checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", name);
checkout.Icon = App.CreateMenuIcon("Icons.Check"); checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (o, e) => checkout.Click += (_, e) =>
{ {
CheckoutBranch(branch); CheckoutBranch(branch);
e.Handled = true; e.Handled = true;
@ -1593,7 +1600,7 @@ namespace SourceGit.ViewModels
var pull = new MenuItem(); var pull = new MenuItem();
pull.Header = new Views.NameHighlightedTextBlock("BranchCM.PullInto", name, current.Name); pull.Header = new Views.NameHighlightedTextBlock("BranchCM.PullInto", name, current.Name);
pull.Icon = App.CreateMenuIcon("Icons.Pull"); pull.Icon = App.CreateMenuIcon("Icons.Pull");
pull.Click += (o, e) => pull.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Pull(this, branch)); PopupHost.ShowPopup(new Pull(this, branch));
@ -1603,7 +1610,7 @@ namespace SourceGit.ViewModels
var merge = new MenuItem(); var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", name, current.Name); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", name, current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.Click += (o, e) => merge.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Merge(this, name, current.Name)); PopupHost.ShowPopup(new Merge(this, name, current.Name));
@ -1613,7 +1620,7 @@ namespace SourceGit.ViewModels
var rebase = new MenuItem(); var rebase = new MenuItem();
rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", current.Name, name); rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", current.Name, name);
rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Icon = App.CreateMenuIcon("Icons.Rebase");
rebase.Click += (o, e) => rebase.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Rebase(this, current, branch)); PopupHost.ShowPopup(new Rebase(this, current, branch));
@ -1632,7 +1639,7 @@ namespace SourceGit.ViewModels
var compareWithWorktree = new MenuItem(); var compareWithWorktree = new MenuItem();
compareWithWorktree.Header = App.Text("BranchCM.CompareWithWorktree"); compareWithWorktree.Header = App.Text("BranchCM.CompareWithWorktree");
compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare"); compareWithWorktree.Icon = App.CreateMenuIcon("Icons.Compare");
compareWithWorktree.Click += (o, e) => compareWithWorktree.Click += (_, _) =>
{ {
SearchResultSelectedCommit = null; SearchResultSelectedCommit = null;
@ -1660,7 +1667,7 @@ namespace SourceGit.ViewModels
var delete = new MenuItem(); var delete = new MenuItem();
delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", name); delete.Header = new Views.NameHighlightedTextBlock("BranchCM.Delete", name);
delete.Icon = App.CreateMenuIcon("Icons.Clear"); delete.Icon = App.CreateMenuIcon("Icons.Clear");
delete.Click += (o, e) => delete.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteBranch(this, branch)); PopupHost.ShowPopup(new DeleteBranch(this, branch));
@ -1670,7 +1677,7 @@ namespace SourceGit.ViewModels
var createBranch = new MenuItem(); var createBranch = new MenuItem();
createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add");
createBranch.Header = App.Text("CreateBranch"); createBranch.Header = App.Text("CreateBranch");
createBranch.Click += (o, e) => createBranch.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateBranch(this, branch)); PopupHost.ShowPopup(new CreateBranch(this, branch));
@ -1680,7 +1687,7 @@ namespace SourceGit.ViewModels
var createTag = new MenuItem(); var createTag = new MenuItem();
createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add"); createTag.Icon = App.CreateMenuIcon("Icons.Tag.Add");
createTag.Header = App.Text("CreateTag"); createTag.Header = App.Text("CreateTag");
createTag.Click += (o, e) => createTag.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateTag(this, branch)); PopupHost.ShowPopup(new CreateTag(this, branch));
@ -1690,7 +1697,7 @@ namespace SourceGit.ViewModels
var archive = new MenuItem(); var archive = new MenuItem();
archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Icon = App.CreateMenuIcon("Icons.Archive");
archive.Header = App.Text("Archive"); archive.Header = App.Text("Archive");
archive.Click += (o, e) => archive.Click += (_, e) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Archive(this, branch)); PopupHost.ShowPopup(new Archive(this, branch));
@ -1700,7 +1707,7 @@ namespace SourceGit.ViewModels
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("BranchCM.CopyName"); copy.Header = App.Text("BranchCM.CopyName");
copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, e) => copy.Click += (_, e) =>
{ {
App.CopyText(name); App.CopyText(name);
e.Handled = true; e.Handled = true;
@ -1722,7 +1729,7 @@ namespace SourceGit.ViewModels
var createBranch = new MenuItem(); var createBranch = new MenuItem();
createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add"); createBranch.Icon = App.CreateMenuIcon("Icons.Branch.Add");
createBranch.Header = App.Text("CreateBranch"); createBranch.Header = App.Text("CreateBranch");
createBranch.Click += (o, ev) => createBranch.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new CreateBranch(this, tag)); PopupHost.ShowPopup(new CreateBranch(this, tag));
@ -1733,7 +1740,7 @@ namespace SourceGit.ViewModels
pushTag.Header = new Views.NameHighlightedTextBlock("TagCM.Push", tag.Name); pushTag.Header = new Views.NameHighlightedTextBlock("TagCM.Push", tag.Name);
pushTag.Icon = App.CreateMenuIcon("Icons.Push"); pushTag.Icon = App.CreateMenuIcon("Icons.Push");
pushTag.IsEnabled = Remotes.Count > 0; pushTag.IsEnabled = Remotes.Count > 0;
pushTag.Click += (o, ev) => pushTag.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new PushTag(this, tag)); PopupHost.ShowPopup(new PushTag(this, tag));
@ -1743,7 +1750,7 @@ namespace SourceGit.ViewModels
var deleteTag = new MenuItem(); var deleteTag = new MenuItem();
deleteTag.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name); deleteTag.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name);
deleteTag.Icon = App.CreateMenuIcon("Icons.Clear"); deleteTag.Icon = App.CreateMenuIcon("Icons.Clear");
deleteTag.Click += (o, ev) => deleteTag.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteTag(this, tag)); PopupHost.ShowPopup(new DeleteTag(this, tag));
@ -1753,7 +1760,7 @@ namespace SourceGit.ViewModels
var archive = new MenuItem(); var archive = new MenuItem();
archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Icon = App.CreateMenuIcon("Icons.Archive");
archive.Header = App.Text("Archive"); archive.Header = App.Text("Archive");
archive.Click += (o, ev) => archive.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new Archive(this, tag)); PopupHost.ShowPopup(new Archive(this, tag));
@ -1763,7 +1770,7 @@ namespace SourceGit.ViewModels
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("TagCM.Copy"); copy.Header = App.Text("TagCM.Copy");
copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, ev) => copy.Click += (_, ev) =>
{ {
App.CopyText(tag.Name); App.CopyText(tag.Name);
ev.Handled = true; ev.Handled = true;
@ -1786,7 +1793,7 @@ namespace SourceGit.ViewModels
var open = new MenuItem(); var open = new MenuItem();
open.Header = App.Text("Submodule.Open"); open.Header = App.Text("Submodule.Open");
open.Icon = App.CreateMenuIcon("Icons.Folder.Open"); open.Icon = App.CreateMenuIcon("Icons.Folder.Open");
open.Click += (o, ev) => open.Click += (_, ev) =>
{ {
OpenSubmodule(submodule); OpenSubmodule(submodule);
ev.Handled = true; ev.Handled = true;
@ -1795,7 +1802,7 @@ namespace SourceGit.ViewModels
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("Submodule.CopyPath"); copy.Header = App.Text("Submodule.CopyPath");
copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, ev) => copy.Click += (_, ev) =>
{ {
App.CopyText(submodule); App.CopyText(submodule);
ev.Handled = true; ev.Handled = true;
@ -1804,7 +1811,7 @@ namespace SourceGit.ViewModels
var rm = new MenuItem(); var rm = new MenuItem();
rm.Header = App.Text("Submodule.Remove"); rm.Header = App.Text("Submodule.Remove");
rm.Icon = App.CreateMenuIcon("Icons.Clear"); rm.Icon = App.CreateMenuIcon("Icons.Clear");
rm.Click += (o, ev) => rm.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DeleteSubmodule(this, submodule)); PopupHost.ShowPopup(new DeleteSubmodule(this, submodule));
@ -1827,7 +1834,7 @@ namespace SourceGit.ViewModels
var unlock = new MenuItem(); var unlock = new MenuItem();
unlock.Header = App.Text("Worktree.Unlock"); unlock.Header = App.Text("Worktree.Unlock");
unlock.Icon = App.CreateMenuIcon("Icons.Unlock"); unlock.Icon = App.CreateMenuIcon("Icons.Unlock");
unlock.Click += (o, ev) => unlock.Click += (_, ev) =>
{ {
SetWatcherEnabled(false); SetWatcherEnabled(false);
var succ = new Commands.Worktree(_fullpath).Unlock(worktree.FullPath); var succ = new Commands.Worktree(_fullpath).Unlock(worktree.FullPath);
@ -1843,7 +1850,7 @@ namespace SourceGit.ViewModels
var loc = new MenuItem(); var loc = new MenuItem();
loc.Header = App.Text("Worktree.Lock"); loc.Header = App.Text("Worktree.Lock");
loc.Icon = App.CreateMenuIcon("Icons.Lock"); loc.Icon = App.CreateMenuIcon("Icons.Lock");
loc.Click += (o, ev) => loc.Click += (_, ev) =>
{ {
SetWatcherEnabled(false); SetWatcherEnabled(false);
var succ = new Commands.Worktree(_fullpath).Lock(worktree.FullPath); var succ = new Commands.Worktree(_fullpath).Lock(worktree.FullPath);
@ -1858,7 +1865,7 @@ namespace SourceGit.ViewModels
var remove = new MenuItem(); var remove = new MenuItem();
remove.Header = App.Text("Worktree.Remove"); remove.Header = App.Text("Worktree.Remove");
remove.Icon = App.CreateMenuIcon("Icons.Clear"); remove.Icon = App.CreateMenuIcon("Icons.Clear");
remove.Click += (o, ev) => remove.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new RemoveWorktree(this, worktree)); PopupHost.ShowPopup(new RemoveWorktree(this, worktree));
@ -1869,7 +1876,7 @@ namespace SourceGit.ViewModels
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("Worktree.CopyPath"); copy.Header = App.Text("Worktree.CopyPath");
copy.Icon = App.CreateMenuIcon("Icons.Copy"); copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, e) => copy.Click += (_, e) =>
{ {
App.CopyText(worktree.FullPath); App.CopyText(worktree.FullPath);
e.Handled = true; e.Handled = true;
@ -1899,12 +1906,16 @@ namespace SourceGit.ViewModels
target.Icon = App.CreateMenuIcon(b.IsCurrent ? "Icons.Check" : "Icons.Branch"); target.Icon = App.CreateMenuIcon(b.IsCurrent ? "Icons.Check" : "Icons.Branch");
target.Click += (_, e) => target.Click += (_, e) =>
{ {
var topLevel = App.GetTopLevel() as Window;
if (topLevel == null)
return;
var wnd = new Views.BranchCompare() var wnd = new Views.BranchCompare()
{ {
DataContext = new BranchCompare(FullPath, branch, dup) DataContext = new BranchCompare(FullPath, branch, dup)
}; };
wnd.Show(App.GetTopLevel() as Window); wnd.Show(topLevel);
e.Handled = true; e.Handled = true;
}; };

View file

@ -209,8 +209,8 @@ namespace SourceGit.ViewModels
} }
} }
private string _repo = string.Empty; private string _repo;
private string _endPoint = string.Empty; private string _endPoint;
private List<Models.Change> _changes = null; private List<Models.Change> _changes = null;
private List<Models.Change> _visibleChanges = null; private List<Models.Change> _visibleChanges = null;
private List<Models.Change> _selectedChanges = null; private List<Models.Change> _selectedChanges = null;

View file

@ -45,8 +45,8 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private string _message = string.Empty; private string _message;
private string _oldMessage = string.Empty; private string _oldMessage;
} }
} }

View file

@ -49,7 +49,7 @@ namespace SourceGit.ViewModels
}); });
} }
private readonly Repository _repo = null; private readonly Repository _repo;
private string _message = string.Empty; private string _message;
} }
} }

View file

@ -5,7 +5,6 @@ namespace SourceGit.ViewModels
{ {
public class StashChanges : Popup public class StashChanges : Popup
{ {
public string Message public string Message
{ {
get; get;

View file

@ -119,7 +119,7 @@ namespace SourceGit.ViewModels
var apply = new MenuItem(); var apply = new MenuItem();
apply.Header = App.Text("StashCM.Apply"); apply.Header = App.Text("StashCM.Apply");
apply.Click += (o, ev) => apply.Click += (_, ev) =>
{ {
Task.Run(() => new Commands.Stash(_repo.FullPath).Apply(stash.Name)); Task.Run(() => new Commands.Stash(_repo.FullPath).Apply(stash.Name));
ev.Handled = true; ev.Handled = true;
@ -127,7 +127,7 @@ namespace SourceGit.ViewModels
var pop = new MenuItem(); var pop = new MenuItem();
pop.Header = App.Text("StashCM.Pop"); pop.Header = App.Text("StashCM.Pop");
pop.Click += (o, ev) => pop.Click += (_, ev) =>
{ {
Task.Run(() => new Commands.Stash(_repo.FullPath).Pop(stash.Name)); Task.Run(() => new Commands.Stash(_repo.FullPath).Pop(stash.Name));
ev.Handled = true; ev.Handled = true;
@ -135,7 +135,7 @@ namespace SourceGit.ViewModels
var drop = new MenuItem(); var drop = new MenuItem();
drop.Header = App.Text("StashCM.Drop"); drop.Header = App.Text("StashCM.Drop");
drop.Click += (o, ev) => drop.Click += (_, ev) =>
{ {
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new DropStash(_repo.FullPath, stash)); PopupHost.ShowPopup(new DropStash(_repo.FullPath, stash));

View file

@ -32,11 +32,9 @@ namespace SourceGit.ViewModels
public Statistics(string repo) public Statistics(string repo)
{ {
_repo = repo;
Task.Run(() => Task.Run(() =>
{ {
var result = new Commands.Statistics(_repo).Result(); var result = new Commands.Statistics(repo).Result();
Dispatcher.UIThread.Invoke(() => Dispatcher.UIThread.Invoke(() =>
{ {
_data = result; _data = result;
@ -65,7 +63,6 @@ namespace SourceGit.ViewModels
} }
} }
private readonly string _repo = string.Empty;
private bool _isLoading = true; private bool _isLoading = true;
private Models.Statistics _data = null; private Models.Statistics _data = null;
private Models.StatisticsReport _selectedReport = null; private Models.StatisticsReport _selectedReport = null;

View file

@ -6,7 +6,7 @@ namespace SourceGit.ViewModels
{ {
public class TwoSideTextDiff : ObservableObject public class TwoSideTextDiff : ObservableObject
{ {
public string File { get; set; } = string.Empty; public string File { get; set; }
public List<Models.TextDiffLine> Old { get; set; } = new List<Models.TextDiffLine>(); public List<Models.TextDiffLine> Old { get; set; } = new List<Models.TextDiffLine>();
public List<Models.TextDiffLine> New { get; set; } = new List<Models.TextDiffLine>(); public List<Models.TextDiffLine> New { get; set; } = new List<Models.TextDiffLine>();
public int MaxLineNumber = 0; public int MaxLineNumber = 0;

View file

@ -1,5 +1,5 @@
using System; using System;
using Avalonia;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@ -49,13 +49,10 @@ namespace SourceGit.ViewModels
return; return;
} }
if (PopupHost.CanCreatePopup()) if (PopupHost.CanCreatePopup() &&
Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { DataContext: Launcher launcher } })
{ {
if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) PopupHost.ShowPopup(new Clone(launcher));
{
var launcher = desktop.MainWindow.DataContext as Launcher;
PopupHost.ShowPopup(new Clone(launcher));
}
} }
} }
@ -98,9 +95,9 @@ namespace SourceGit.ViewModels
openAll.Icon = App.CreateMenuIcon("Icons.Folder.Open"); openAll.Icon = App.CreateMenuIcon("Icons.Folder.Open");
openAll.Click += (_, e) => openAll.Click += (_, e) =>
{ {
if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (PopupHost.CanCreatePopup() &&
Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { DataContext: Launcher launcher } })
{ {
var launcher = desktop.MainWindow.DataContext as Launcher;
OpenAllInNode(launcher, node); OpenAllInNode(launcher, node);
} }

View file

@ -44,7 +44,7 @@ namespace SourceGit.ViewModels
if (_repo.IncludeUntracked != value) if (_repo.IncludeUntracked != value)
{ {
_repo.IncludeUntracked = value; _repo.IncludeUntracked = value;
OnPropertyChanged(nameof(IncludeUntracked)); OnPropertyChanged();
} }
} }
} }
@ -286,12 +286,16 @@ namespace SourceGit.ViewModels
public void OpenAssumeUnchanged() public void OpenAssumeUnchanged()
{ {
var toplevel = App.GetTopLevel() as Window;
if (toplevel == null)
return;
var dialog = new Views.AssumeUnchangedManager() var dialog = new Views.AssumeUnchangedManager()
{ {
DataContext = new AssumeUnchangedManager(_repo.FullPath) DataContext = new AssumeUnchangedManager(_repo.FullPath)
}; };
dialog.ShowDialog(App.GetTopLevel() as Window); dialog.ShowDialog(toplevel);
} }
public void StageSelected() public void StageSelected()
@ -634,7 +638,7 @@ namespace SourceGit.ViewModels
lfsTrackByExtension.Header = App.Text("GitLFS.TrackByExtension", extension); lfsTrackByExtension.Header = App.Text("GitLFS.TrackByExtension", extension);
lfsTrackByExtension.Click += async (_, e) => lfsTrackByExtension.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track("*" + extension, false)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Track("*" + extension));
if (succ) if (succ)
App.SendNotification(_repo.FullPath, $"Tracking all *{extension} files successfully!"); App.SendNotification(_repo.FullPath, $"Tracking all *{extension} files successfully!");
@ -652,7 +656,7 @@ namespace SourceGit.ViewModels
lfsLock.IsEnabled = _repo.Remotes.Count > 0; lfsLock.IsEnabled = _repo.Remotes.Count > 0;
if (_repo.Remotes.Count == 1) if (_repo.Remotes.Count == 1)
{ {
lfsLock.Click += async (o, e) => lfsLock.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, change.Path)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, change.Path));
if (succ) if (succ)
@ -668,7 +672,7 @@ namespace SourceGit.ViewModels
var remoteName = remote.Name; var remoteName = remote.Name;
var lockRemote = new MenuItem(); var lockRemote = new MenuItem();
lockRemote.Header = remoteName; lockRemote.Header = remoteName;
lockRemote.Click += async (o, e) => lockRemote.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, change.Path)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, change.Path));
if (succ) if (succ)
@ -687,7 +691,7 @@ namespace SourceGit.ViewModels
lfsUnlock.IsEnabled = _repo.Remotes.Count > 0; lfsUnlock.IsEnabled = _repo.Remotes.Count > 0;
if (_repo.Remotes.Count == 1) if (_repo.Remotes.Count == 1)
{ {
lfsUnlock.Click += async (o, e) => lfsUnlock.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, change.Path, false)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, change.Path, false));
if (succ) if (succ)
@ -703,7 +707,7 @@ namespace SourceGit.ViewModels
var remoteName = remote.Name; var remoteName = remote.Name;
var unlockRemote = new MenuItem(); var unlockRemote = new MenuItem();
unlockRemote.Header = remoteName; unlockRemote.Header = remoteName;
unlockRemote.Click += async (o, e) => unlockRemote.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, change.Path, false)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, change.Path, false));
if (succ) if (succ)
@ -823,7 +827,7 @@ namespace SourceGit.ViewModels
var patch = new MenuItem(); var patch = new MenuItem();
patch.Header = App.Text("FileCM.SaveAsPatch"); patch.Header = App.Text("FileCM.SaveAsPatch");
patch.Icon = App.CreateMenuIcon("Icons.Diff"); patch.Icon = App.CreateMenuIcon("Icons.Diff");
patch.Click += async (o, e) => patch.Click += async (_, e) =>
{ {
var topLevel = App.GetTopLevel(); var topLevel = App.GetTopLevel();
if (topLevel == null) if (topLevel == null)
@ -869,7 +873,7 @@ namespace SourceGit.ViewModels
explore.IsEnabled = File.Exists(path) || Directory.Exists(path); explore.IsEnabled = File.Exists(path) || Directory.Exists(path);
explore.Header = App.Text("RevealFile"); explore.Header = App.Text("RevealFile");
explore.Icon = App.CreateMenuIcon("Icons.Folder.Open"); explore.Icon = App.CreateMenuIcon("Icons.Folder.Open");
explore.Click += (o, e) => explore.Click += (_, e) =>
{ {
Native.OS.OpenInFileManager(path, true); Native.OS.OpenInFileManager(path, true);
e.Handled = true; e.Handled = true;
@ -888,7 +892,7 @@ namespace SourceGit.ViewModels
var unstage = new MenuItem(); var unstage = new MenuItem();
unstage.Header = App.Text("FileCM.Unstage"); unstage.Header = App.Text("FileCM.Unstage");
unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
unstage.Click += (o, e) => unstage.Click += (_, e) =>
{ {
UnstageChanges(_selectedStaged); UnstageChanges(_selectedStaged);
e.Handled = true; e.Handled = true;
@ -917,7 +921,7 @@ namespace SourceGit.ViewModels
var patch = new MenuItem(); var patch = new MenuItem();
patch.Header = App.Text("FileCM.SaveAsPatch"); patch.Header = App.Text("FileCM.SaveAsPatch");
patch.Icon = App.CreateMenuIcon("Icons.Diff"); patch.Icon = App.CreateMenuIcon("Icons.Diff");
patch.Click += async (o, e) => patch.Click += async (_, e) =>
{ {
var topLevel = App.GetTopLevel(); var topLevel = App.GetTopLevel();
if (topLevel == null) if (topLevel == null)
@ -942,7 +946,7 @@ namespace SourceGit.ViewModels
var copyPath = new MenuItem(); var copyPath = new MenuItem();
copyPath.Header = App.Text("CopyPath"); copyPath.Header = App.Text("CopyPath");
copyPath.Icon = App.CreateMenuIcon("Icons.Copy"); copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
copyPath.Click += (o, e) => copyPath.Click += (_, e) =>
{ {
App.CopyText(change.Path); App.CopyText(change.Path);
e.Handled = true; e.Handled = true;
@ -979,7 +983,7 @@ namespace SourceGit.ViewModels
lfsLock.IsEnabled = _repo.Remotes.Count > 0; lfsLock.IsEnabled = _repo.Remotes.Count > 0;
if (_repo.Remotes.Count == 1) if (_repo.Remotes.Count == 1)
{ {
lfsLock.Click += async (o, e) => lfsLock.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, change.Path)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(_repo.Remotes[0].Name, change.Path));
if (succ) if (succ)
@ -995,7 +999,7 @@ namespace SourceGit.ViewModels
var remoteName = remote.Name; var remoteName = remote.Name;
var lockRemote = new MenuItem(); var lockRemote = new MenuItem();
lockRemote.Header = remoteName; lockRemote.Header = remoteName;
lockRemote.Click += async (o, e) => lockRemote.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, change.Path)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Lock(remoteName, change.Path));
if (succ) if (succ)
@ -1014,7 +1018,7 @@ namespace SourceGit.ViewModels
lfsUnlock.IsEnabled = _repo.Remotes.Count > 0; lfsUnlock.IsEnabled = _repo.Remotes.Count > 0;
if (_repo.Remotes.Count == 1) if (_repo.Remotes.Count == 1)
{ {
lfsUnlock.Click += async (o, e) => lfsUnlock.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, change.Path, false)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(_repo.Remotes[0].Name, change.Path, false));
if (succ) if (succ)
@ -1030,7 +1034,7 @@ namespace SourceGit.ViewModels
var remoteName = remote.Name; var remoteName = remote.Name;
var unlockRemote = new MenuItem(); var unlockRemote = new MenuItem();
unlockRemote.Header = remoteName; unlockRemote.Header = remoteName;
unlockRemote.Click += async (o, e) => unlockRemote.Click += async (_, e) =>
{ {
var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, change.Path, false)); var succ = await Task.Run(() => new Commands.LFS(_repo.FullPath).Unlock(remoteName, change.Path, false));
if (succ) if (succ)
@ -1055,7 +1059,7 @@ namespace SourceGit.ViewModels
var unstage = new MenuItem(); var unstage = new MenuItem();
unstage.Header = App.Text("FileCM.UnstageMulti", _selectedStaged.Count); unstage.Header = App.Text("FileCM.UnstageMulti", _selectedStaged.Count);
unstage.Icon = App.CreateMenuIcon("Icons.File.Remove"); unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
unstage.Click += (o, e) => unstage.Click += (_, e) =>
{ {
UnstageChanges(_selectedStaged); UnstageChanges(_selectedStaged);
e.Handled = true; e.Handled = true;
@ -1140,7 +1144,7 @@ namespace SourceGit.ViewModels
var item = new MenuItem(); var item = new MenuItem();
item.Header = dump; item.Header = dump;
item.Click += (o, e) => item.Click += (_, e) =>
{ {
CommitMessage = dump; CommitMessage = dump;
e.Handled = true; e.Handled = true;

View file

@ -4,8 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="using:SourceGit" xmlns:s="using:SourceGit"
xmlns:vm="using:SourceGit.ViewModels" xmlns:vm="using:SourceGit.ViewModels"
xmlns:m="using:SourceGit.Models"
xmlns:c="using:SourceGit.Converters"
xmlns:v="using:SourceGit.Views" xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Launcher" x:Class="SourceGit.Views.Launcher"
@ -76,109 +74,13 @@
</Border> </Border>
</Grid> </Grid>
<!-- Page body --> <!-- Page -->
<ContentControl Grid.Row="1" Background="{DynamicResource Brush.ToolBar}" Content="{Binding ActivePage.Data}"> <ContentControl Grid.Row="1" Content="{Binding ActivePage}">
<ContentControl.DataTemplates> <ContentControl.DataTemplates>
<DataTemplate DataType="vm:Welcome"> <DataTemplate DataType="vm:LauncherPage">
<v:Welcome/> <v:LauncherPage/>
</DataTemplate>
<DataTemplate DataType="vm:Repository">
<v:Repository/>
</DataTemplate> </DataTemplate>
</ContentControl.DataTemplates> </ContentControl.DataTemplates>
</ContentControl> </ContentControl>
<!-- Popup container -->
<Grid Grid.Row="1" Margin="0,36,0,0" IsVisible="{Binding ActivePage.Popup, Converter={x:Static ObjectConverters.IsNotNull}}" ClipToBounds="True">
<Border Background="Transparent" PointerPressed="OnPopupCancelByClickMask"/>
<Border Width="500" HorizontalAlignment="Center" VerticalAlignment="Top" Effect="drop-shadow(0 0 8 #8F000000)" CornerRadius="0,0,8,8" ClipToBounds="True">
<ContentControl Content="{Binding ActivePage.Popup}" Background="{DynamicResource Brush.Popup}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Popup">
<StackPanel Orientation="Vertical" Background="{DynamicResource Brush.Popup}">
<!-- Popup Widget -->
<ContentPresenter Margin="8,16,8,8"
Content="{Binding View}"
IsHitTestVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}"/>
<!-- Options -->
<StackPanel Margin="8,4,8,8"
Height="32"
Orientation="Horizontal"
HorizontalAlignment="Right"
IsVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}">
<Button Classes="flat primary"
Width="80"
Content="{DynamicResource Text.Sure}"
Click="OnPopupSure"
HotKey="Enter"/>
<Button Classes="flat"
Width="80"
Margin="8,0,0,0"
Content="{DynamicResource Text.Cancel}"
Click="OnPopupCancel"/>
</StackPanel>
<!-- Running -->
<v:PopupRunningStatus Margin="12,8"
Description="{Binding ProgressDescription}"
IsVisible="{Binding InProgress}"/>
</StackPanel>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Border>
</Grid>
<!-- Notification container -->
<Grid Grid.Row="1" Width="360" Margin="0,36,0,0" HorizontalAlignment="Right" VerticalAlignment="Top">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding ActivePage.Notifications}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:Notification">
<Border Margin="10,6" HorizontalAlignment="Stretch" VerticalAlignment="Top" Effect="drop-shadow(0 0 12 #A0000000)">
<Border Padding="8" CornerRadius="6" Background="{DynamicResource Brush.Popup}">
<Grid RowDefinitions="26,Auto,32">
<StackPanel Grid.Row="0" Margin="8,0,0,0" Orientation="Horizontal" IsVisible="{Binding IsError}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Error}" Fill="Red"/>
<TextBlock Margin="8,0,0,0" FontWeight="Bold" FontSize="14" Text="{DynamicResource Text.Launcher.Error}"/>
</StackPanel>
<StackPanel Grid.Row="0" Margin="8,0,0,0" Orientation="Horizontal" IsVisible="{Binding !IsError}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Info}" Fill="Green"/>
<TextBlock Margin="8,0,0,0" FontWeight="Bold" FontSize="14" Text="{DynamicResource Text.Launcher.Info}"/>
</StackPanel>
<TextBox Grid.Row="1"
Classes="no_background no_border"
IsReadOnly="True"
TextWrapping="Wrap"
ScrollViewer.VerticalScrollBarVisibility="Auto"
MaxHeight="100"
Margin="8" Padding="0"
VerticalContentAlignment="Top"
Text="{Binding Message}"/>
<StackPanel Grid.Row="2" Margin="0,4,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Classes="flat"
Margin="0,0,8,0"
Command="{Binding CopyMessage}"
Content="{DynamicResource Text.CopyMessage}"
IsVisible="{Binding IsError}"/>
<Button Classes="flat primary"
Margin="0,0"
Content="{DynamicResource Text.Close}"
Click="OnDismissNotification"/>
</StackPanel>
</Grid>
</Border>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid> </Grid>
</v:ChromelessWindow> </v:ChromelessWindow>

View file

@ -3,7 +3,6 @@ using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views namespace SourceGit.Views
{ {
@ -199,35 +198,6 @@ namespace SourceGit.Views
_pressedTitleBar = false; _pressedTitleBar = false;
} }
private void OnPopupSure(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.Launcher vm)
vm.ActivePage.ProcessPopup();
e.Handled = true;
}
private void OnPopupCancel(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.Launcher vm)
vm.ActivePage.CancelPopup();
e.Handled = true;
}
private void OnPopupCancelByClickMask(object sender, PointerPressedEventArgs e)
{
OnPopupCancel(sender, e);
}
private void OnDismissNotification(object sender, RoutedEventArgs e)
{
if (sender is Button btn && DataContext is ViewModels.Launcher vm)
vm.DismissNotification(btn.DataContext as ViewModels.Notification);
e.Handled = true;
}
private bool _pressedTitleBar = false; private bool _pressedTitleBar = false;
} }
} }

View file

@ -0,0 +1,133 @@
<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:v="using:SourceGit.Views"
xmlns:vm="using:SourceGit.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.LauncherPage"
x:DataType="vm:LauncherPage">
<Grid RowDefinitions="36,*">
<!-- ToolBar -->
<Border Grid.Row="0" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" Background="{DynamicResource Brush.ToolBar}">
<ContentControl Content="{Binding Data}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Welcome">
<v:WelcomeToolbar/>
</DataTemplate>
<DataTemplate DataType="vm:Repository">
<v:RepositoryToolbar/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Border>
<!-- Body -->
<Border Grid.Row="1" Background="{DynamicResource Brush.Window}">
<ContentControl Content="{Binding Data}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Welcome">
<v:Welcome/>
</DataTemplate>
<DataTemplate DataType="vm:Repository">
<v:Repository/>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Border>
<!-- Popup -->
<Grid Grid.Row="1" IsVisible="{Binding Popup, Converter={x:Static ObjectConverters.IsNotNull}}" ClipToBounds="True">
<Border Background="Transparent" PointerPressed="OnPopupCancelByClickMask"/>
<Border Width="500" HorizontalAlignment="Center" VerticalAlignment="Top" Effect="drop-shadow(0 0 8 #8F000000)" CornerRadius="0,0,8,8" ClipToBounds="True">
<ContentControl Content="{Binding Popup}" Background="{DynamicResource Brush.Popup}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:Popup">
<StackPanel Orientation="Vertical" Background="{DynamicResource Brush.Popup}">
<!-- Popup Widget -->
<ContentPresenter Margin="8,16,8,8"
Content="{Binding View}"
IsHitTestVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}"/>
<!-- Options -->
<StackPanel Margin="8,4,8,8"
Height="32"
Orientation="Horizontal"
HorizontalAlignment="Right"
IsVisible="{Binding InProgress, Converter={x:Static BoolConverters.Not}}">
<Button Classes="flat primary"
Width="80"
Content="{DynamicResource Text.Sure}"
Click="OnPopupSure"
HotKey="Enter"/>
<Button Classes="flat"
Width="80"
Margin="8,0,0,0"
Content="{DynamicResource Text.Cancel}"
Click="OnPopupCancel"/>
</StackPanel>
<!-- Running -->
<v:PopupRunningStatus Margin="12,8"
Description="{Binding ProgressDescription}"
IsVisible="{Binding InProgress}"/>
</StackPanel>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Border>
</Grid>
<!-- Notification -->
<Grid Grid.Row="1" Width="360" HorizontalAlignment="Right" VerticalAlignment="Top">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Notifications}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:Notification">
<Border Margin="10,6" HorizontalAlignment="Stretch" VerticalAlignment="Top" Effect="drop-shadow(0 0 12 #A0000000)">
<Border Padding="8" CornerRadius="6" Background="{DynamicResource Brush.Popup}">
<Grid RowDefinitions="26,Auto,32">
<StackPanel Grid.Row="0" Margin="8,0,0,0" Orientation="Horizontal" IsVisible="{Binding IsError}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Error}" Fill="Red"/>
<TextBlock Margin="8,0,0,0" FontWeight="Bold" FontSize="14" Text="{DynamicResource Text.Launcher.Error}"/>
</StackPanel>
<StackPanel Grid.Row="0" Margin="8,0,0,0" Orientation="Horizontal" IsVisible="{Binding !IsError}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Info}" Fill="Green"/>
<TextBlock Margin="8,0,0,0" FontWeight="Bold" FontSize="14" Text="{DynamicResource Text.Launcher.Info}"/>
</StackPanel>
<TextBox Grid.Row="1"
Classes="no_background no_border"
IsReadOnly="True"
TextWrapping="Wrap"
ScrollViewer.VerticalScrollBarVisibility="Auto"
MaxHeight="100"
Margin="8" Padding="0"
VerticalContentAlignment="Top"
Text="{Binding Message}"/>
<StackPanel Grid.Row="2" Margin="0,4,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Classes="flat"
Margin="0,0,8,0"
Command="{Binding CopyMessage}"
Content="{DynamicResource Text.CopyMessage}"
IsVisible="{Binding IsError}"/>
<Button Classes="flat primary"
Margin="0,0"
Content="{DynamicResource Text.Close}"
Click="OnDismissNotification"/>
</StackPanel>
</Grid>
</Border>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
</UserControl>

View file

@ -0,0 +1,44 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
public partial class LauncherPage : UserControl
{
public LauncherPage()
{
InitializeComponent();
}
private void OnPopupSure(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.LauncherPage page)
page.ProcessPopup();
e.Handled = true;
}
private void OnPopupCancel(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.LauncherPage page)
page.CancelPopup();
e.Handled = true;
}
private void OnPopupCancelByClickMask(object sender, PointerPressedEventArgs e)
{
OnPopupCancel(sender, e);
}
private void OnDismissNotification(object sender, RoutedEventArgs e)
{
if (sender is Button { DataContext: ViewModels.Notification notice } &&
DataContext is ViewModels.LauncherPage page)
page.Notifications.Remove(notice);
e.Handled = true;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -21,48 +21,6 @@ namespace SourceGit.Views
UpdateLeftSidebarLayout(); UpdateLeftSidebarLayout();
} }
private void OpenWithExternalTools(object sender, RoutedEventArgs e)
{
if (sender is Button button && DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForExternalTools();
button.OpenContextMenu(menu);
e.Handled = true;
}
}
private void OpenGitFlowMenu(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForGitFlow();
(sender as Control)?.OpenContextMenu(menu);
}
e.Handled = true;
}
private void OpenGitLFSMenu(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForGitLFS();
(sender as Control)?.OpenContextMenu(menu);
}
e.Handled = true;
}
private async void OpenStatistics(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo && TopLevel.GetTopLevel(this) is Window owner)
{
var dialog = new Statistics() { DataContext = new ViewModels.Statistics(repo.FullPath) };
await dialog.ShowDialog(owner);
e.Handled = true;
}
}
private void OnSearchCommitPanelPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) private void OnSearchCommitPanelPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
{ {
if (e.Property == IsVisibleProperty && sender is Grid { IsVisible: true }) if (e.Property == IsVisibleProperty && sender is Grid { IsVisible: true })

View file

@ -0,0 +1,78 @@
<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.RepositoryToolbar"
x:DataType="vm:Repository">
<Grid ColumnDefinitions="*,Auto,*">
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="4,0,0,0">
<Button Classes="icon_button" Width="32" Command="{Binding OpenInFileManager}" ToolTip.Tip="{DynamicResource Text.Repository.Explore}">
<Path Width="15" Height="13" Data="{StaticResource Icons.Folder.Open}" Margin="0,1,0,0"/>
</Button>
<Button Classes="icon_button" Width="32" Command="{Binding OpenInTerminal}" ToolTip.Tip="{DynamicResource Text.Repository.Terminal}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Terminal}"/>
</Button>
<Button Classes="icon_button" Width="32" Click="OpenWithExternalTools" ToolTip.Tip="{DynamicResource Text.Repository.OpenWithExternalTools}">
<Path Width="13" Height="13" Data="{StaticResource Icons.OpenWith}"/>
</Button>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button Classes="icon_button" Width="32" Command="{Binding Fetch}" ToolTip.Tip="{DynamicResource Text.Fetch}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Fetch}"/>
</Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding Pull}" ToolTip.Tip="{DynamicResource Text.Pull}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Pull}"/>
</Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding Push}" ToolTip.Tip="{DynamicResource Text.Push}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Push}"/>
</Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding StashAll}" ToolTip.Tip="{DynamicResource Text.Stash}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Stashes}"/>
</Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding ApplyPatch}" ToolTip.Tip="{DynamicResource Text.Apply}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Diff}"/>
</Button>
<Rectangle Width="1" Height="16"
Margin="16,0,0,0"
VerticalAlignment="Center"
Fill="{DynamicResource Brush.Border2}"/>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding CreateNewBranch}" ToolTip.Tip="{DynamicResource Text.Repository.NewBranch}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch.Add}"/>
</Button>
<Button Classes="icon_button" Width="32" Margin="8,0,0,0" Click="OpenGitFlowMenu" ToolTip.Tip="{DynamicResource Text.GitFlow}">
<Path Width="14" Height="14" Data="{StaticResource Icons.GitFlow}"/>
</Button>
<Button Classes="icon_button" Width="32" Margin="8,0,0,0" Click="OpenGitLFSMenu" ToolTip.Tip="{DynamicResource Text.GitLFS}">
<Path Width="14" Height="14" Data="{StaticResource Icons.LFS}"/>
</Button>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,4,0">
<Button Classes="icon_button" Width="32" Command="{Binding Cleanup}" ToolTip.Tip="{DynamicResource Text.Repository.Clean}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Clean}"/>
</Button>
<Button Classes="icon_button" Width="32" Click="OpenStatistics" ToolTip.Tip="{DynamicResource Text.Repository.Statistics}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Statistics}"/>
</Button>
<Button Classes="icon_button" Width="32" Command="{Binding OpenConfigure}" ToolTip.Tip="{DynamicResource Text.Repository.Configure}">
<Path Width="15" Height="15" Data="{StaticResource Icons.Settings}"/>
</Button>
</StackPanel>
</Grid>
</UserControl>

View file

@ -0,0 +1,56 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
namespace SourceGit.Views
{
public partial class RepositoryToolbar : UserControl
{
public RepositoryToolbar()
{
InitializeComponent();
}
private void OpenWithExternalTools(object sender, RoutedEventArgs e)
{
if (sender is Button button && DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForExternalTools();
button.OpenContextMenu(menu);
e.Handled = true;
}
}
private void OpenGitFlowMenu(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForGitFlow();
(sender as Control)?.OpenContextMenu(menu);
}
e.Handled = true;
}
private void OpenGitLFSMenu(object sender, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo)
{
var menu = repo.CreateContextMenuForGitLFS();
(sender as Control)?.OpenContextMenu(menu);
}
e.Handled = true;
}
private async void OpenStatistics(object _, RoutedEventArgs e)
{
if (DataContext is ViewModels.Repository repo && TopLevel.GetTopLevel(this) is Window owner)
{
var dialog = new Statistics() { DataContext = new ViewModels.Statistics(repo.FullPath) };
await dialog.ShowDialog(owner);
e.Handled = true;
}
}
}
}

View file

@ -4,37 +4,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="using:SourceGit.Converters" xmlns:c="using:SourceGit.Converters"
xmlns:vm="using:SourceGit.ViewModels" xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.Welcome" x:Class="SourceGit.Views.Welcome"
x:DataType="vm:Welcome"> x:DataType="vm:Welcome">
<Grid RowDefinitions="36,*,36" Background="{DynamicResource Brush.Window}"> <Grid RowDefinitions="*,36">
<Border Grid.Row="0" BorderBrush="{DynamicResource Brush.Border0}" BorderThickness="0,0,0,1" Background="{DynamicResource Brush.ToolBar}"> <Grid Grid.Row="0" Margin="0,8" ColumnDefinitions="*,600,*">
<StackPanel Orientation="Horizontal" Margin="4,0,0,0">
<Button Classes="icon_button" Width="32" Command="{Binding Clone}" ToolTip.Tip="{DynamicResource Text.Welcome.Clone}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Pull}"/>
</Button>
<Button Classes="icon_button" Width="32" Click="OpenLocalRepository" ToolTip.Tip="{DynamicResource Text.Welcome.OpenOrInit}">
<Path Width="16" Height="16" Data="{StaticResource Icons.Folder.Add2}" Margin="0,4,0,0"/>
</Button>
<Button Classes="icon_button" Width="32" Command="{Binding OpenTerminal}" ToolTip.Tip="{DynamicResource Text.Welcome.OpenTerminal}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Terminal}"/>
</Button>
<Rectangle Width="1" Height="16"
Margin="4,0"
VerticalAlignment="Center"
Fill="{DynamicResource Brush.Border2}"/>
<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>
</StackPanel>
</Border>
<Grid Grid.Row="1" Margin="0,8" ColumnDefinitions="*,600,*">
<Grid Grid.Column="1" RowDefinitions="Auto,*"> <Grid Grid.Column="1" RowDefinitions="Auto,*">
<TextBox Grid.Row="0" <TextBox Grid.Row="0"
Height="32" Height="32"
@ -126,7 +100,7 @@
</Grid> </Grid>
</Grid> </Grid>
<TextBlock Grid.Row="2" <TextBlock Grid.Row="1"
Classes="italic" Classes="italic"
Margin="0,0,8,0" Margin="0,0,8,0"
HorizontalAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center"

View file

@ -1,12 +1,9 @@
using System.IO; using System.IO;
using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using Avalonia.VisualTree; using Avalonia.VisualTree;
namespace SourceGit.Views namespace SourceGit.Views
@ -107,7 +104,7 @@ namespace SourceGit.Views
} }
} }
private async void DropOnTreeView(object sender, DragEventArgs e) private void DropOnTreeView(object sender, DragEventArgs e)
{ {
if (e.Data.Get("MovedRepositoryTreeNode") is ViewModels.RepositoryNode moved) if (e.Data.Get("MovedRepositoryTreeNode") is ViewModels.RepositoryNode moved)
{ {
@ -125,7 +122,7 @@ namespace SourceGit.Views
{ {
foreach (var item in items) foreach (var item in items)
{ {
await OpenOrInitRepository(item.Path.LocalPath); OpenOrInitRepository(item.Path.LocalPath);
break; break;
} }
} }
@ -160,7 +157,7 @@ namespace SourceGit.Views
} }
} }
private async void DropOnTreeNode(object sender, DragEventArgs e) private void DropOnTreeNode(object sender, DragEventArgs e)
{ {
if (sender is not Grid grid) if (sender is not Grid grid)
return; return;
@ -188,7 +185,7 @@ namespace SourceGit.Views
{ {
foreach (var item in items) foreach (var item in items)
{ {
await OpenOrInitRepository(item.Path.LocalPath, to); OpenOrInitRepository(item.Path.LocalPath, to);
break; break;
} }
} }
@ -212,55 +209,27 @@ namespace SourceGit.Views
e.Handled = true; e.Handled = true;
} }
private async void OpenLocalRepository(object _1, RoutedEventArgs e) private void OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null)
{
if (!ViewModels.PopupHost.CanCreatePopup())
return;
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel == null)
return;
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
await OpenOrInitRepository(selected[0].Path.LocalPath);
e.Handled = true;
}
private Task OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null)
{ {
if (!Directory.Exists(path)) if (!Directory.Exists(path))
{ {
if (File.Exists(path)) if (File.Exists(path))
path = Path.GetDirectoryName(path); path = Path.GetDirectoryName(path);
else else
return null; return;
} }
var owner = this.FindAncestorOfType<Launcher>(); var root = new Commands.QueryRepositoryRootPath(path).Result();
var launcher = owner?.DataContext as ViewModels.Launcher; if (string.IsNullOrEmpty(root))
if (launcher == null)
return null;
var page = launcher.ActivePage;
return Task.Run(() =>
{ {
var root = new Commands.QueryRepositoryRootPath(path).Result(); (DataContext as ViewModels.Welcome)?.InitRepository(path, parent);
if (string.IsNullOrEmpty(root)) return;
{ }
Dispatcher.UIThread.Invoke(() => (DataContext as ViewModels.Welcome)?.InitRepository(path, parent));
return;
}
Dispatcher.UIThread.Invoke(() => var normalizedPath = root.Replace("\\", "/");
{ var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true);
var normalizedPath = root.Replace("\\", "/"); var launcher = this.FindAncestorOfType<Launcher>()?.DataContext as ViewModels.Launcher;
var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true); launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
launcher.OpenRepositoryInTab(node, page);
});
});
} }
private bool _pressedTreeNode = false; private bool _pressedTreeNode = false;

View file

@ -0,0 +1,32 @@
<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.WelcomeToolbar"
x:DataType="vm:Welcome">
<StackPanel Orientation="Horizontal" Margin="4,0,0,0">
<Button Classes="icon_button" Width="32" Command="{Binding Clone}" ToolTip.Tip="{DynamicResource Text.Welcome.Clone}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Pull}"/>
</Button>
<Button Classes="icon_button" Width="32" Click="OpenLocalRepository" ToolTip.Tip="{DynamicResource Text.Welcome.OpenOrInit}">
<Path Width="16" Height="16" Data="{StaticResource Icons.Folder.Add2}" Margin="0,4,0,0"/>
</Button>
<Button Classes="icon_button" Width="32" Command="{Binding OpenTerminal}" ToolTip.Tip="{DynamicResource Text.Welcome.OpenTerminal}">
<Path Width="13" Height="13" Data="{StaticResource Icons.Terminal}"/>
</Button>
<Rectangle Width="1" Height="16"
Margin="4,0"
VerticalAlignment="Center"
Fill="{DynamicResource Brush.Border2}"/>
<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>
</StackPanel>
</UserControl>

View file

@ -0,0 +1,58 @@
using System.IO;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
public partial class WelcomeToolbar : UserControl
{
public WelcomeToolbar()
{
InitializeComponent();
}
private async void OpenLocalRepository(object _1, RoutedEventArgs e)
{
if (!ViewModels.PopupHost.CanCreatePopup())
return;
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel == null)
return;
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
OpenOrInitRepository(selected[0].Path.LocalPath);
e.Handled = true;
}
private void OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null)
{
if (!Directory.Exists(path))
{
if (File.Exists(path))
path = Path.GetDirectoryName(path);
else
return;
}
var root = new Commands.QueryRepositoryRootPath(path).Result();
if (string.IsNullOrEmpty(root))
{
(DataContext as ViewModels.Welcome)?.InitRepository(path, parent);
return;
}
var normalizedPath = root.Replace("\\", "/");
var node = ViewModels.Preference.FindOrAddNodeByRepositoryPath(normalizedPath, parent, true);
var launcher = this.FindAncestorOfType<Launcher>()?.DataContext as ViewModels.Launcher;
launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
}
}
}