diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 98d671d37..c6ae45135 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -75,6 +75,12 @@ public override void Initialize() 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 @@ private void TryLaunchedAsNormal(IClassicDesktopStyleApplicationLifetime desktop var pref = ViewModels.Preference.Instance; if (pref.ShouldCheck4UpdateOnStartup()) { - pref.Save(); Check4Update(); } } diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index ed3c07249..a7aa6532d 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 @@ public void AddNode(RepositoryNode node, RepositoryNode to = null) 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 @@ public void MoveNode(RepositoryNode node, RepositoryNode to = null) 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 @@ public void SortByRenamedNode(RepositoryNode node) 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 @@ private bool RemoveNodeRecursive(RepositoryNode node, List colle 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 2621bcaf2..25dbfd96e 100644 --- a/src/Views/Preference.axaml.cs +++ b/src/Views/Preference.axaml.cs @@ -138,7 +138,7 @@ protected override void OnClosing(WindowClosingEventArgs e) if (!GPGFormat.Value.Equals("ssh", StringComparison.Ordinal)) SetIfChanged(config, $"gpg.{GPGFormat.Value}.program", GPGExecutableFile); - + base.OnClosing(e); } @@ -261,7 +261,6 @@ private void OnUseNativeWindowFrameChanged(object sender, RoutedEventArgs e) if (sender is CheckBox box) { ViewModels.Preference.Instance.UseSystemWindowFrame = box.IsChecked == true; - ViewModels.Preference.Instance.Save(); var dialog = new ConfirmRestart(); App.OpenDialog(dialog);