mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-24 20:57:19 -08:00
refactor: rewrite SourceGit.App
This commit is contained in:
parent
32e59c4048
commit
24dde77548
6 changed files with 121 additions and 186 deletions
223
src/App.axaml.cs
223
src/App.axaml.cs
|
@ -15,6 +15,7 @@ using Avalonia.Data.Core.Plugins;
|
|||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Fonts;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
|
||||
|
@ -41,6 +42,13 @@ namespace SourceGit
|
|||
|
||||
public partial class App : Application
|
||||
{
|
||||
public static readonly SimpleCommand OpenPreferenceCommand = new SimpleCommand(() => OpenDialog(new Views.Preference()));
|
||||
public static readonly SimpleCommand OpenHotkeysCommand = new SimpleCommand(() => OpenDialog(new Views.Hotkeys()));
|
||||
public static readonly SimpleCommand OpenAppDataDirCommand = new SimpleCommand(() => Native.OS.OpenInFileManager(Native.OS.DataDir));
|
||||
public static readonly SimpleCommand OpenAboutCommand = new SimpleCommand(() => OpenDialog(new Views.About()));
|
||||
public static readonly SimpleCommand CheckForUpdateCommand = new SimpleCommand(() => Check4Update(true));
|
||||
public static readonly SimpleCommand QuitCommand = new SimpleCommand(() => Quit(0));
|
||||
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
@ -89,47 +97,36 @@ namespace SourceGit
|
|||
return builder;
|
||||
}
|
||||
|
||||
public static readonly SimpleCommand OpenPreferenceCommand = new SimpleCommand(() =>
|
||||
public override void Initialize()
|
||||
{
|
||||
var toplevel = GetTopLevel() as Window;
|
||||
if (toplevel == null)
|
||||
return;
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
||||
var dialog = new Views.Preference();
|
||||
dialog.ShowDialog(toplevel);
|
||||
});
|
||||
var pref = ViewModels.Preference.Instance;
|
||||
SetLocale(pref.Locale);
|
||||
SetTheme(pref.Theme, pref.ThemeOverrides);
|
||||
}
|
||||
|
||||
public static readonly SimpleCommand OpenHotkeysCommand = new SimpleCommand(() =>
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
var toplevel = GetTopLevel() as Window;
|
||||
if (toplevel == null)
|
||||
return;
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
BindingPlugins.DataValidators.RemoveAt(0);
|
||||
|
||||
var dialog = new Views.Hotkeys();
|
||||
dialog.ShowDialog(toplevel);
|
||||
});
|
||||
if (TryLaunchedAsCoreEditor(desktop))
|
||||
return;
|
||||
|
||||
public static readonly SimpleCommand OpenAppDataDirCommand = new SimpleCommand(() =>
|
||||
if (TryLaunchedAsAskpass(desktop))
|
||||
return;
|
||||
|
||||
TryLaunchedAsNormal(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenDialog(Window window)
|
||||
{
|
||||
Native.OS.OpenInFileManager(Native.OS.DataDir);
|
||||
});
|
||||
|
||||
public static readonly SimpleCommand OpenAboutCommand = new SimpleCommand(() =>
|
||||
{
|
||||
var toplevel = GetTopLevel() as Window;
|
||||
if (toplevel == null)
|
||||
return;
|
||||
|
||||
var dialog = new Views.About();
|
||||
dialog.ShowDialog(toplevel);
|
||||
});
|
||||
|
||||
public static readonly SimpleCommand CheckForUpdateCommand = new SimpleCommand(() =>
|
||||
{
|
||||
Check4Update(true);
|
||||
});
|
||||
|
||||
public static readonly SimpleCommand QuitCommand = new SimpleCommand(() => Quit(0));
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
window.ShowDialog(desktop.MainWindow);
|
||||
}
|
||||
|
||||
public static void RaiseException(string context, string message)
|
||||
{
|
||||
|
@ -258,17 +255,74 @@ namespace SourceGit
|
|||
return icon;
|
||||
}
|
||||
|
||||
public static TopLevel GetTopLevel()
|
||||
public static IStorageProvider GetStorageProvider()
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
return desktop.MainWindow.StorageProvider;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ViewModels.Launcher GetLauncer()
|
||||
{
|
||||
return Current is App app ? app._launcher : null;
|
||||
}
|
||||
|
||||
public static ViewModels.Repository FindOpenedRepository(string repoPath)
|
||||
{
|
||||
if (Current is App app && app._launcher != null)
|
||||
{
|
||||
return desktop.MainWindow;
|
||||
foreach (var page in app._launcher.Pages)
|
||||
{
|
||||
var id = page.Node.Id.Replace("\\", "/");
|
||||
if (id == repoPath && page.Data is ViewModels.Repository repo)
|
||||
return repo;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Check4Update(bool manually = false)
|
||||
public static void Quit(int exitCode)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow?.Close();
|
||||
desktop.Shutdown(exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogException(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
return;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
|
||||
builder.Append("----------------------------\n");
|
||||
builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
|
||||
builder.Append($"OS: {Environment.OSVersion.ToString()}\n");
|
||||
builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
|
||||
builder.Append($"Source: {ex.Source}\n");
|
||||
builder.Append($"---------------------------\n\n");
|
||||
builder.Append(ex.StackTrace);
|
||||
while (ex.InnerException != null)
|
||||
{
|
||||
ex = ex.InnerException;
|
||||
builder.Append($"\n\nInnerException::: {ex.GetType().FullName}: {ex.Message}\n");
|
||||
builder.Append(ex.StackTrace);
|
||||
}
|
||||
|
||||
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
|
||||
File.WriteAllText(file, builder.ToString());
|
||||
}
|
||||
|
||||
private static void Check4Update(bool manually = false)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
@ -309,104 +363,11 @@ namespace SourceGit
|
|||
});
|
||||
}
|
||||
|
||||
public static ViewModels.Launcher GetLauncer()
|
||||
{
|
||||
return Current is App app ? app._launcher : null;
|
||||
}
|
||||
|
||||
public static ViewModels.Repository FindOpenedRepository(string repoPath)
|
||||
{
|
||||
if (Current is App app && app._launcher != null)
|
||||
{
|
||||
foreach (var page in app._launcher.Pages)
|
||||
{
|
||||
var id = page.Node.Id.Replace("\\", "/");
|
||||
if (id == repoPath && page.Data is ViewModels.Repository repo)
|
||||
return repo;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Quit(int exitCode)
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow?.Close();
|
||||
desktop.Shutdown(exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
||||
var pref = ViewModels.Preference.Instance;
|
||||
|
||||
SetLocale(pref.Locale);
|
||||
SetTheme(pref.Theme, pref.ThemeOverrides);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
BindingPlugins.DataValidators.RemoveAt(0);
|
||||
|
||||
if (TryLaunchedAsCoreEditor(desktop))
|
||||
return;
|
||||
|
||||
if (TryLaunchedAsAskpass(desktop))
|
||||
return;
|
||||
|
||||
TryLaunchedAsNormal(desktop);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogException(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
return;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
|
||||
builder.Append("----------------------------\n");
|
||||
builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
|
||||
builder.Append($"OS: {Environment.OSVersion.ToString()}\n");
|
||||
builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
|
||||
builder.Append($"Source: {ex.Source}\n");
|
||||
builder.Append($"---------------------------\n\n");
|
||||
builder.Append(ex.StackTrace);
|
||||
while (ex.InnerException != null)
|
||||
{
|
||||
ex = ex.InnerException;
|
||||
builder.Append($"\n\nInnerException::: {ex.GetType().FullName}: {ex.Message}\n");
|
||||
builder.Append(ex.StackTrace);
|
||||
}
|
||||
|
||||
var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||
var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
|
||||
File.WriteAllText(file, builder.ToString());
|
||||
}
|
||||
|
||||
private static void ShowSelfUpdateResult(object data)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: not null } desktop)
|
||||
{
|
||||
var dialog = new Views.SelfUpdate()
|
||||
{
|
||||
DataContext = new ViewModels.SelfUpdate() { Data = data }
|
||||
};
|
||||
|
||||
dialog.Show(desktop.MainWindow);
|
||||
}
|
||||
OpenDialog(new Views.SelfUpdate() { DataContext = new ViewModels.SelfUpdate() { Data = data } });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -380,12 +380,12 @@ namespace SourceGit.ViewModels
|
|||
saveAs.IsEnabled = file.Type == Models.ObjectType.Blob;
|
||||
saveAs.Click += async (_, ev) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel();
|
||||
if (topLevel == null)
|
||||
var storageProvider = App.GetStorageProvider();
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
|
||||
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
|
||||
var selected = await storageProvider.OpenFolderPickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
var saveTo = Path.Combine(selected[0].Path.LocalPath, Path.GetFileName(file.Path));
|
||||
|
|
|
@ -428,12 +428,12 @@ namespace SourceGit.ViewModels
|
|||
saveToPatch.Header = App.Text("CommitCM.SaveAsPatch");
|
||||
saveToPatch.Click += async (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel();
|
||||
if (topLevel == null)
|
||||
var storageProvider = App.GetStorageProvider();
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
|
||||
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
|
||||
var selected = await storageProvider.OpenFolderPickerAsync(options);
|
||||
if (selected.Count == 1)
|
||||
{
|
||||
var succ = new Commands.FormatPatch(_repo.FullPath, commit.SHA, selected[0].Path.LocalPath).Exec();
|
||||
|
|
|
@ -940,9 +940,7 @@ namespace SourceGit.ViewModels
|
|||
};
|
||||
}
|
||||
|
||||
var launcher = App.GetTopLevel().DataContext as Launcher;
|
||||
if (launcher != null)
|
||||
launcher.OpenRepositoryInTab(node, null);
|
||||
App.GetLauncer()?.OpenRepositoryInTab(node, null);
|
||||
}
|
||||
|
||||
public void AddWorktree()
|
||||
|
@ -971,9 +969,7 @@ namespace SourceGit.ViewModels
|
|||
};
|
||||
}
|
||||
|
||||
var launcher = App.GetTopLevel().DataContext as Launcher;
|
||||
if (launcher != null)
|
||||
launcher.OpenRepositoryInTab(node, null);
|
||||
App.GetLauncer()?.OpenRepositoryInTab(node, null);
|
||||
}
|
||||
|
||||
public ContextMenu CreateContextMenuForGitFlow()
|
||||
|
@ -1130,12 +1126,8 @@ namespace SourceGit.ViewModels
|
|||
{
|
||||
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) };
|
||||
dialog.Show(topLevel);
|
||||
App.OpenDialog(dialog);
|
||||
e.Handled = true;
|
||||
};
|
||||
}
|
||||
|
@ -1148,12 +1140,8 @@ namespace SourceGit.ViewModels
|
|||
lockRemote.Header = remoteName;
|
||||
lockRemote.Click += (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel() as Window;
|
||||
if (topLevel == null)
|
||||
return;
|
||||
|
||||
var dialog = new Views.LFSLocks() { DataContext = new LFSLocks(_fullpath, remoteName) };
|
||||
dialog.Show(topLevel);
|
||||
App.OpenDialog(dialog);
|
||||
e.Handled = true;
|
||||
};
|
||||
locks.Items.Add(lockRemote);
|
||||
|
@ -1878,16 +1866,9 @@ namespace SourceGit.ViewModels
|
|||
target.Icon = App.CreateMenuIcon(b.IsCurrent ? "Icons.Check" : "Icons.Branch");
|
||||
target.Click += (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel() as Window;
|
||||
if (topLevel == null)
|
||||
return;
|
||||
|
||||
var wnd = new Views.BranchCompare()
|
||||
{
|
||||
App.OpenDialog(new Views.BranchCompare() {
|
||||
DataContext = new BranchCompare(_fullpath, branch, dup)
|
||||
};
|
||||
|
||||
wnd.Show(topLevel);
|
||||
});
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
|
|
@ -303,16 +303,10 @@ namespace SourceGit.ViewModels
|
|||
|
||||
public void OpenAssumeUnchanged()
|
||||
{
|
||||
var toplevel = App.GetTopLevel() as Window;
|
||||
if (toplevel == null)
|
||||
return;
|
||||
|
||||
var dialog = new Views.AssumeUnchangedManager()
|
||||
App.OpenDialog(new Views.AssumeUnchangedManager()
|
||||
{
|
||||
DataContext = new AssumeUnchangedManager(_repo.FullPath)
|
||||
};
|
||||
|
||||
dialog.ShowDialog(toplevel);
|
||||
});
|
||||
}
|
||||
|
||||
public void StashAll(bool autoStart)
|
||||
|
@ -530,8 +524,8 @@ namespace SourceGit.ViewModels
|
|||
patch.Icon = App.CreateMenuIcon("Icons.Diff");
|
||||
patch.Click += async (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel();
|
||||
if (topLevel == null)
|
||||
var storageProvider = App.GetStorageProvider();
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FilePickerSaveOptions();
|
||||
|
@ -539,7 +533,7 @@ namespace SourceGit.ViewModels
|
|||
options.DefaultExtension = ".patch";
|
||||
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
||||
|
||||
var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options);
|
||||
var storageFile = await storageProvider.SaveFilePickerAsync(options);
|
||||
if (storageFile != null)
|
||||
{
|
||||
var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, _selectedUnstaged, true, storageFile.Path.LocalPath));
|
||||
|
@ -853,8 +847,8 @@ namespace SourceGit.ViewModels
|
|||
patch.Icon = App.CreateMenuIcon("Icons.Diff");
|
||||
patch.Click += async (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel();
|
||||
if (topLevel == null)
|
||||
var storageProvider = App.GetStorageProvider();
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FilePickerSaveOptions();
|
||||
|
@ -862,7 +856,7 @@ namespace SourceGit.ViewModels
|
|||
options.DefaultExtension = ".patch";
|
||||
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
||||
|
||||
var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options);
|
||||
var storageFile = await storageProvider.SaveFilePickerAsync(options);
|
||||
if (storageFile != null)
|
||||
{
|
||||
var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, _selectedUnstaged, true, storageFile.Path.LocalPath));
|
||||
|
@ -938,8 +932,8 @@ namespace SourceGit.ViewModels
|
|||
patch.Icon = App.CreateMenuIcon("Icons.Diff");
|
||||
patch.Click += async (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel();
|
||||
if (topLevel == null)
|
||||
var storageProvider = App.GetStorageProvider();
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FilePickerSaveOptions();
|
||||
|
@ -947,7 +941,7 @@ namespace SourceGit.ViewModels
|
|||
options.DefaultExtension = ".patch";
|
||||
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
||||
|
||||
var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options);
|
||||
var storageFile = await storageProvider.SaveFilePickerAsync(options);
|
||||
if (storageFile != null)
|
||||
{
|
||||
var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, _selectedStaged, false, storageFile.Path.LocalPath));
|
||||
|
@ -1085,9 +1079,8 @@ namespace SourceGit.ViewModels
|
|||
stash.Click += (_, e) =>
|
||||
{
|
||||
if (PopupHost.CanCreatePopup())
|
||||
{
|
||||
PopupHost.ShowPopup(new StashChanges(_repo, _selectedStaged, false));
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -1096,8 +1089,8 @@ namespace SourceGit.ViewModels
|
|||
patch.Icon = App.CreateMenuIcon("Icons.Diff");
|
||||
patch.Click += async (_, e) =>
|
||||
{
|
||||
var topLevel = App.GetTopLevel();
|
||||
if (topLevel == null)
|
||||
var storageProvider = App.GetStorageProvider();
|
||||
if (storageProvider == null)
|
||||
return;
|
||||
|
||||
var options = new FilePickerSaveOptions();
|
||||
|
@ -1105,7 +1098,7 @@ namespace SourceGit.ViewModels
|
|||
options.DefaultExtension = ".patch";
|
||||
options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
|
||||
|
||||
var storageFile = await topLevel.StorageProvider.SaveFilePickerAsync(options);
|
||||
var storageFile = await storageProvider.SaveFilePickerAsync(options);
|
||||
if (storageFile != null)
|
||||
{
|
||||
var succ = await Task.Run(() => Commands.SaveChangesAsPatch.Exec(_repo.FullPath, _selectedStaged, false, storageFile.Path.LocalPath));
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace SourceGit.Views
|
|||
// Ctrl+Shift+P opens preference dialog (macOS use hotkeys in system menu bar)
|
||||
if (!OperatingSystem.IsMacOS() && e.KeyModifiers == (KeyModifiers.Control | KeyModifiers.Shift) && e.Key == Key.P)
|
||||
{
|
||||
App.OpenPreferenceCommand.Execute(null);
|
||||
App.OpenDialog(new Preference());
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue