Release / release (push) Canceled after 47s
await certificate from ssl.com Reviewed-on: #4 Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
114 lines
3.6 KiB
C#
114 lines
3.6 KiB
C#
using System.Windows;
|
|
using CursorLang.Core.Services;
|
|
using CursorLang.Settings.Services;
|
|
using CursorLang.Settings.ViewModels;
|
|
using CursorLang.Settings.Views;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace CursorLang.Settings;
|
|
|
|
/// <summary>
|
|
/// The settings window as a process of its own.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// It is started by the agent — from the tray menu, or straight away when the user
|
|
/// launches the application themselves — and it ends when the window is closed. That
|
|
/// is the whole point of the split: WPF costs around a hundred megabytes, and this way
|
|
/// the system gets all of it back the moment the user is done, instead of the
|
|
/// background process carrying it until sign-out.
|
|
///
|
|
/// Nothing here talks to the agent directly. Every edit goes into settings.json, and
|
|
/// <see cref="SettingsService"/> nudges the agent to re-read it once the file is
|
|
/// written. An agent that is not running is a normal case: the window works the same.
|
|
/// </remarks>
|
|
// ReSharper disable once RedundantExtendsListEntry
|
|
public partial class App : Application
|
|
{
|
|
private ServiceProvider? _services;
|
|
private SingleInstanceGate? _instanceGate;
|
|
|
|
protected override void OnStartup(StartupEventArgs e)
|
|
{
|
|
base.OnStartup(e);
|
|
|
|
var gate = new SingleInstanceGate(SingleInstanceGate.SettingsName);
|
|
if (!gate.TryAcquire(showRunningInstance: true))
|
|
{
|
|
gate.Dispose();
|
|
Shutdown();
|
|
return;
|
|
}
|
|
|
|
_instanceGate = gate;
|
|
_instanceGate.ActivationRequested += OnActivationRequested;
|
|
|
|
var services = new ServiceCollection();
|
|
ConfigureServices(services);
|
|
_services = services.BuildServiceProvider();
|
|
|
|
_services.GetRequiredService<SettingsService>().TrackChanges();
|
|
_services.GetRequiredService<ThemeService>();
|
|
|
|
MainWindow = _services.GetRequiredService<MainWindow>();
|
|
|
|
ShutdownMode = ShutdownMode.OnMainWindowClose;
|
|
MainWindow.Show();
|
|
|
|
_ = _services.GetRequiredService<SettingsViewModel>().InitializeAsync();
|
|
}
|
|
|
|
protected override void OnExit(ExitEventArgs e)
|
|
{
|
|
_services?.Dispose();
|
|
|
|
if (_instanceGate is not null)
|
|
{
|
|
_instanceGate.ActivationRequested -= OnActivationRequested;
|
|
_instanceGate.Dispose();
|
|
}
|
|
|
|
base.OnExit(e);
|
|
}
|
|
|
|
internal static void ConfigureServices(IServiceCollection services)
|
|
{
|
|
services.AddSingleton(AppVersion.Current);
|
|
|
|
services.AddSingleton<SettingsService>();
|
|
services.AddSingleton(provider => provider.GetRequiredService<SettingsService>().Load());
|
|
|
|
services.AddSingleton<ThemeService>();
|
|
services.AddSingleton<IThemeService>(provider => provider.GetRequiredService<ThemeService>());
|
|
|
|
services.AddSingleton<MainWindowPlacement>();
|
|
|
|
services.AddSingleton<ILocalizationService, LocalizationService>();
|
|
services.AddSingleton<IStartupService, StartupService>();
|
|
|
|
services.AddSingleton<SettingsViewModel>();
|
|
|
|
services.AddSingleton<MainWindow>();
|
|
}
|
|
|
|
// A second launch — another click on "Settings" in the tray menu, say. The gate
|
|
// answers on a thread pool thread, and a window obeys only its own
|
|
private void OnActivationRequested(object? sender, EventArgs e) =>
|
|
Dispatcher.BeginInvoke(ShowMainWindow);
|
|
|
|
private void ShowMainWindow()
|
|
{
|
|
if (MainWindow is not { } window)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (window.WindowState == WindowState.Minimized)
|
|
{
|
|
window.WindowState = WindowState.Normal;
|
|
}
|
|
|
|
window.Show();
|
|
window.Activate();
|
|
}
|
|
}
|