diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 98d671d3..c6ae4513 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -75,6 +75,12 @@ namespace SourceGit AvaloniaXamlLoader.Load(this); var pref = ViewModels.Preference.Instance; + pref.PropertyChanged += (_1, _2) => + { +#pragma warning disable CS4014 + pref.SaveAsync(); +#pragma warning restore CS4014 + }; SetLocale(pref.Locale); SetTheme(pref.Theme, pref.ThemeOverrides); SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily, pref.OnlyUseMonoFontInEditor); @@ -522,7 +528,6 @@ namespace SourceGit var pref = ViewModels.Preference.Instance; if (pref.ShouldCheck4UpdateOnStartup()) { - pref.Save(); Check4Update(); } } diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index ed3c0724..a7aa6532 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Text.Json; using System.Text.Json.Serialization; - +using System.Threading; +using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -354,6 +356,9 @@ namespace SourceGit.ViewModels return string.Compare(l.Name, r.Name, StringComparison.Ordinal); }); +#pragma warning disable CS4014 + SaveAsync(); +#pragma warning restore CS4014 } public RepositoryNode FindNode(string id) @@ -398,6 +403,9 @@ namespace SourceGit.ViewModels public void RemoveNode(RepositoryNode node) { RemoveNodeRecursive(node, RepositoryNodes); +#pragma warning disable CS4014 + SaveAsync(); +#pragma warning restore CS4014 } public void SortByRenamedNode(RepositoryNode node) @@ -410,14 +418,43 @@ namespace SourceGit.ViewModels return string.Compare(l.Name, r.Name, StringComparison.Ordinal); }); +#pragma warning disable CS4014 + SaveAsync(); +#pragma warning restore CS4014 } public void Save() { + lock (_saveCtsLock) + { + _saveCts.Cancel(); + _saveCts = new CancellationTokenSource(); + } var data = JsonSerializer.Serialize(this, JsonCodeGen.Default.Preference); File.WriteAllText(_savePath, data); } + public async Task SaveAsync() + { + lock (_saveCtsLock) + { + _saveCts.Cancel(); + _saveCts = new CancellationTokenSource(); + } + + try + { + await Task.Delay(3000, _saveCts.Token); + } + catch (TaskCanceledException) + { + return; + } + + var data = JsonSerializer.Serialize(this, JsonCodeGen.Default.Preference); + await File.WriteAllTextAsync(_savePath, data); + } + private RepositoryNode FindNodeRecursive(string id, List collection) { foreach (var node in collection) @@ -468,6 +505,8 @@ namespace SourceGit.ViewModels private static Preference _instance = null; private static bool _isLoading = false; private static readonly string _savePath = Path.Combine(Native.OS.DataDir, "preference.json"); + private static CancellationTokenSource _saveCts = new(); + private static readonly object _saveCtsLock = new(); private string _locale = "en_US"; private string _theme = "Default"; diff --git a/src/Views/Preference.axaml.cs b/src/Views/Preference.axaml.cs index 2621bcaf..25dbfd96 100644 --- a/src/Views/Preference.axaml.cs +++ b/src/Views/Preference.axaml.cs @@ -138,7 +138,7 @@ namespace SourceGit.Views if (!GPGFormat.Value.Equals("ssh", StringComparison.Ordinal)) SetIfChanged(config, $"gpg.{GPGFormat.Value}.program", GPGExecutableFile); - + base.OnClosing(e); } @@ -261,7 +261,6 @@ namespace SourceGit.Views if (sender is CheckBox box) { ViewModels.Preference.Instance.UseSystemWindowFrame = box.IsChecked == true; - ViewModels.Preference.Instance.Save(); var dialog = new ConfirmRestart(); App.OpenDialog(dialog);