diff --git a/src/modules/poweraccent/PowerAccent.Core/Models/UsageInfoData.cs b/src/modules/poweraccent/PowerAccent.Core/Models/UsageInfoData.cs new file mode 100644 index 0000000000..322e4eae79 --- /dev/null +++ b/src/modules/poweraccent/PowerAccent.Core/Models/UsageInfoData.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace PowerAccent.Core.Models +{ + public class UsageInfoData + { + public Dictionary CharacterUsageCounters { get; set; } = []; + + public Dictionary CharacterUsageTimestamp { get; set; } = []; + } +} diff --git a/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs b/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs index c2f0698f25..fa020ee4fe 100644 --- a/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs +++ b/src/modules/poweraccent/PowerAccent.Core/PowerAccent.cs @@ -117,8 +117,8 @@ public partial class PowerAccent : IDisposable if (_settingService.SortByUsageFrequency) { characters = characters.OrderByDescending(character => _usageInfo.GetUsageFrequency(character)) - .ThenByDescending(character => _usageInfo.GetLastUsageTimestamp(character)). - ToArray(); + .ThenByDescending(character => _usageInfo.GetLastUsageTimestamp(character)) + .ToArray(); } else if (!_usageInfo.Empty()) { @@ -337,6 +337,14 @@ public partial class PowerAccent : IDisposable return _settingService.Position; } + public void SaveUsageInfo() + { + if (_settingService.SortByUsageFrequency) + { + _usageInfo.Save(); + } + } + public void Dispose() { _keyboardListener.UnInitHook(); diff --git a/src/modules/poweraccent/PowerAccent.Core/SerializationContext/SourceGenerationContext.cs b/src/modules/poweraccent/PowerAccent.Core/SerializationContext/SourceGenerationContext.cs index e682aa7b63..55fdd144a1 100644 --- a/src/modules/poweraccent/PowerAccent.Core/SerializationContext/SourceGenerationContext.cs +++ b/src/modules/poweraccent/PowerAccent.Core/SerializationContext/SourceGenerationContext.cs @@ -3,12 +3,14 @@ // See the LICENSE file in the project root for more information. using System.Text.Json.Serialization; +using PowerAccent.Core.Models; using PowerAccent.Core.Services; namespace PowerAccent.Core.SerializationContext; [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(SettingsService))] +[JsonSerializable(typeof(UsageInfoData))] public partial class SourceGenerationContext : JsonSerializerContext { } diff --git a/src/modules/poweraccent/PowerAccent.Core/Tools/CharactersUsageInfo.cs b/src/modules/poweraccent/PowerAccent.Core/Tools/CharactersUsageInfo.cs index 07a448bbe0..492a9828d9 100644 --- a/src/modules/poweraccent/PowerAccent.Core/Tools/CharactersUsageInfo.cs +++ b/src/modules/poweraccent/PowerAccent.Core/Tools/CharactersUsageInfo.cs @@ -2,12 +2,28 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.IO; +using System.Text.Json; +using ManagedCommon; +using Microsoft.PowerToys.Settings.UI.Library; +using PowerAccent.Core.Models; +using PowerAccent.Core.SerializationContext; + namespace PowerAccent.Core.Tools { public class CharactersUsageInfo { - private Dictionary _characterUsageCounters = new Dictionary(); - private Dictionary _characterUsageTimestamp = new Dictionary(); + private readonly string _filePath; + private readonly Dictionary _characterUsageCounters; + private readonly Dictionary _characterUsageTimestamp; + + public CharactersUsageInfo() + { + _filePath = new SettingsUtils().GetSettingsFilePath(PowerAccentSettings.ModuleName, "UsageInfo.json"); + var data = GetUsageInfoData(); + _characterUsageCounters = data.CharacterUsageCounters; + _characterUsageTimestamp = data.CharacterUsageTimestamp; + } public bool Empty() { @@ -18,19 +34,18 @@ namespace PowerAccent.Core.Tools { _characterUsageCounters.Clear(); _characterUsageTimestamp.Clear(); + Delete(); } public uint GetUsageFrequency(string character) { _characterUsageCounters.TryGetValue(character, out uint frequency); - return frequency; } public long GetLastUsageTimestamp(string character) { _characterUsageTimestamp.TryGetValue(character, out long timestamp); - return timestamp; } @@ -47,5 +62,58 @@ namespace PowerAccent.Core.Tools _characterUsageTimestamp[character] = DateTimeOffset.Now.ToUnixTimeSeconds(); } + + public void Save() + { + var data = new UsageInfoData + { + CharacterUsageCounters = _characterUsageCounters, + CharacterUsageTimestamp = _characterUsageTimestamp, + }; + + try + { + var json = JsonSerializer.Serialize(data, SourceGenerationContext.Default.UsageInfoData); + File.WriteAllText(_filePath, json); + } + catch (Exception ex) + { + Logger.LogError("Failed to save usage file", ex); + } + } + + public void Delete() + { + try + { + if (File.Exists(_filePath)) + { + File.Delete(_filePath); + } + } + catch (Exception ex) + { + Logger.LogError("Failed to delete usage file", ex); + } + } + + private UsageInfoData GetUsageInfoData() + { + if (!File.Exists(_filePath)) + { + return new UsageInfoData(); + } + + try + { + var json = File.ReadAllText(_filePath); + return JsonSerializer.Deserialize(json, SourceGenerationContext.Default.UsageInfoData) ?? new UsageInfoData(); + } + catch (Exception ex) + { + Logger.LogError("Failed to read usage file", ex); + return new UsageInfoData(); + } + } } } diff --git a/src/modules/poweraccent/PowerAccent.UI/Selector.xaml.cs b/src/modules/poweraccent/PowerAccent.UI/Selector.xaml.cs index 449aae94db..311417851a 100644 --- a/src/modules/poweraccent/PowerAccent.UI/Selector.xaml.cs +++ b/src/modules/poweraccent/PowerAccent.UI/Selector.xaml.cs @@ -98,6 +98,7 @@ public partial class Selector : FluentWindow, IDisposable, INotifyPropertyChange protected override void OnClosed(EventArgs e) { + _powerAccent.SaveUsageInfo(); _powerAccent.Dispose(); base.OnClosed(e); }