From b7073c3e2a22ad17126637a7168a597b315f16c5 Mon Sep 17 00:00:00 2001 From: Ar6yZuK Date: Fri, 1 Mar 2024 10:09:24 +0300 Subject: [PATCH] Make beep on success. Added audio-path to audio file that will be played on success Tick. Also added bool value that means play audio on success or not. Also added (SettingsExtensions 2.0) with abstraction. Extract MyTimer to ITimer interface, but it not make sense. Make tests for Settings --- .../AppSettings/Models/UserSettingsModel.cs | 3 +- .../AppSettings/UserSettings3.Designer.cs | 24 ++++ .../AppSettings/UserSettings3.settings | 6 + HabiticaHourUpVSIX/DictionaryExtensions.cs | 9 ++ HabiticaHourUpVSIX/HabiticaHourUpVSIX.csproj | 15 ++- .../HabiticaHourUpVSIXPackage.cs | 23 +++- HabiticaHourUpVSIX/IAudioPlayer.cs | 26 ++++ HabiticaHourUpVSIX/MyTimer.cs | 57 ++++++-- HabiticaHourUpVSIX/SettingsExtensions.cs | 2 +- HabiticaHourUpVSIX/SettingsExtensions_v2.cs | 38 ++++++ .../ToolWindows/SettingsWindowControl.xaml | 21 ++- .../ToolWindows/SettingsWindowControl.xaml.cs | 55 ++++++-- HabiticaHourUpVSIX/app.config | 6 + SettingsTests/SettingsTest.cs | 123 ++++++++++++------ SettingsTests/SettingsTests.csproj | 2 + 15 files changed, 347 insertions(+), 63 deletions(-) create mode 100644 HabiticaHourUpVSIX/DictionaryExtensions.cs create mode 100644 HabiticaHourUpVSIX/IAudioPlayer.cs create mode 100644 HabiticaHourUpVSIX/SettingsExtensions_v2.cs diff --git a/HabiticaHourUpVSIX/AppSettings/Models/UserSettingsModel.cs b/HabiticaHourUpVSIX/AppSettings/Models/UserSettingsModel.cs index 5ff7c16..798b917 100644 --- a/HabiticaHourUpVSIX/AppSettings/Models/UserSettingsModel.cs +++ b/HabiticaHourUpVSIX/AppSettings/Models/UserSettingsModel.cs @@ -1,2 +1,3 @@ namespace HabiticaHourUpVSIX.AppSettings.Models; -public record struct UserSettingsModel(TimeSpan Divisor, string TaskIDToScoreUp, bool IsAutoScoreUp, bool ShowErrorOnFailure); \ No newline at end of file +public record struct UserSettingsModel(TimeSpan Divisor, string TaskIDToScoreUp, bool IsAutoScoreUp, bool ShowErrorOnFailure, + bool BeepOnSuccess, string BeepAudioPath); \ No newline at end of file diff --git a/HabiticaHourUpVSIX/AppSettings/UserSettings3.Designer.cs b/HabiticaHourUpVSIX/AppSettings/UserSettings3.Designer.cs index dcb92bf..6811564 100644 --- a/HabiticaHourUpVSIX/AppSettings/UserSettings3.Designer.cs +++ b/HabiticaHourUpVSIX/AppSettings/UserSettings3.Designer.cs @@ -70,5 +70,29 @@ public bool ShowErrorOnFailure { this["ShowErrorOnFailure"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool BeepOnSuccess { + get { + return ((bool)(this["BeepOnSuccess"])); + } + set { + this["BeepOnSuccess"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string BeepAudioPath { + get { + return ((string)(this["BeepAudioPath"])); + } + set { + this["BeepAudioPath"] = value; + } + } } } diff --git a/HabiticaHourUpVSIX/AppSettings/UserSettings3.settings b/HabiticaHourUpVSIX/AppSettings/UserSettings3.settings index 8b0a575..2372f00 100644 --- a/HabiticaHourUpVSIX/AppSettings/UserSettings3.settings +++ b/HabiticaHourUpVSIX/AppSettings/UserSettings3.settings @@ -14,5 +14,11 @@ True + + False + + + + \ No newline at end of file diff --git a/HabiticaHourUpVSIX/DictionaryExtensions.cs b/HabiticaHourUpVSIX/DictionaryExtensions.cs new file mode 100644 index 0000000..20d6cc2 --- /dev/null +++ b/HabiticaHourUpVSIX/DictionaryExtensions.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace HabiticaHourUpVSIX; + +public static class DictionaryExtensions +{ + public static TValue GetOrSet(this Dictionary obj1, TKey key, Func resultProvider) + => obj1.TryGetValue(key, out var result) ? result : obj1[key] = resultProvider(); +} \ No newline at end of file diff --git a/HabiticaHourUpVSIX/HabiticaHourUpVSIX.csproj b/HabiticaHourUpVSIX/HabiticaHourUpVSIX.csproj index cf53276..f369916 100644 --- a/HabiticaHourUpVSIX/HabiticaHourUpVSIX.csproj +++ b/HabiticaHourUpVSIX/HabiticaHourUpVSIX.csproj @@ -55,7 +55,9 @@ + + @@ -106,6 +108,7 @@ SettingsSingleFileGenerator UserSettings3.Designer.cs + Designer VsixManifestGenerator @@ -161,7 +164,17 @@ - + + + {6BF52A50-394A-11D3-B153-00C04F79FAA6} + 1 + 0 + 0 + tlbimp + False + True + + Designer diff --git a/HabiticaHourUpVSIX/HabiticaHourUpVSIXPackage.cs b/HabiticaHourUpVSIX/HabiticaHourUpVSIXPackage.cs index 686c2fa..c46ea57 100644 --- a/HabiticaHourUpVSIX/HabiticaHourUpVSIXPackage.cs +++ b/HabiticaHourUpVSIX/HabiticaHourUpVSIXPackage.cs @@ -23,12 +23,14 @@ namespace HabiticaHourUpVSIX; [ProvideToolWindow(typeof(SettingsToolWindow.Pane))] public sealed class HabiticaHourUpVSIXPackage : ToolkitPackage { + private IAudioPlayer _soundPlayer; + public SettingsWithSaving HabiticaSettingsReader { get; private set; } public SettingsWithSaving CredentialsSettings { get; private set; } public SettingsWithSaving UserSettingsReader { get; private set; } public Settings SessionSettingsReader { get; private set; } public HabiticaClientBase HabiticaClient { get; private set; } - public MyTimer Timer { get; private set; } + public ITimer Timer { get; private set; } protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { @@ -36,8 +38,21 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke this.RegisterToolWindows(); HabiticaClient = new HabiticaClient(this); + _soundPlayer = new AudioPlayer(); HabiticaClient.OnSuccessfullySend += delegate { SessionSettingsReader.AddSessionTicksSent(1); }; + HabiticaClient.OnSuccessfullySend += delegate + { + var userSettings = UserSettingsReader.Read(); + if (!userSettings.BeepOnSuccess) + return; + + SetMusicPathIfNull(userSettings.BeepAudioPath); + _soundPlayer.Play(); + + void SetMusicPathIfNull(string beepMusicPath) + => _soundPlayer.AudioPath = string.IsNullOrEmpty(_soundPlayer.AudioPath) ? beepMusicPath : _soundPlayer.AudioPath; + }; SessionSettingsReader = new SessionSettings(); CredentialsSettings = new CredentialsSettings(); @@ -122,4 +137,10 @@ private void AddTicksToAllSettings(int addedTicks) HabiticaSettingsReader.Save(); } + + protected override void Dispose(bool disposing) + { + Timer.Dispose(); + base.Dispose(disposing); + } } \ No newline at end of file diff --git a/HabiticaHourUpVSIX/IAudioPlayer.cs b/HabiticaHourUpVSIX/IAudioPlayer.cs new file mode 100644 index 0000000..d39b7b9 --- /dev/null +++ b/HabiticaHourUpVSIX/IAudioPlayer.cs @@ -0,0 +1,26 @@ +namespace HabiticaHourUpVSIX; +#nullable enable + +internal interface IAudioPlayer +{ + string? AudioPath { get; set; } + void Play(); +} +internal class SoundPlayer : IAudioPlayer +{ + private readonly System.Media.SoundPlayer _soundPlayer = new(); + + public string? AudioPath { get => _soundPlayer.SoundLocation; set => _soundPlayer.SoundLocation = value; } + + public void Play() + => _soundPlayer.PlaySync(); +} +internal class AudioPlayer : IAudioPlayer +{ + private readonly WMPLib.WindowsMediaPlayer _player = new(); + + public string? AudioPath { get => _player.URL; set => _player.URL = value; } + + public void Play() + => _player.controls.play(); +} \ No newline at end of file diff --git a/HabiticaHourUpVSIX/MyTimer.cs b/HabiticaHourUpVSIX/MyTimer.cs index 5142bbb..fb07030 100644 --- a/HabiticaHourUpVSIX/MyTimer.cs +++ b/HabiticaHourUpVSIX/MyTimer.cs @@ -2,14 +2,25 @@ #nullable enable namespace HabiticaHourUpVSIX; -public class MyTimer : IDisposable + +public interface ITimer : IDisposable +{ + event Action? Tick; + + DateTime? Next { get; } + TimeSpan NextTick { get; } + + bool Change(TimeSpan dueTime, TimeSpan period); +} +public class MyTimer : ITimer, IDisposable { private readonly Timer _timer; + private bool _disposedValue; public event Action? Tick; - public TimeSpan Divisor { get; private set; } - public DateTime? Next { get; private set; } + public TimeSpan Period { get; protected set; } + public DateTime? Next { get; protected set; } public TimeSpan NextTick => Next - DateTime.Now ?? Timeout.InfiniteTimeSpan; @@ -18,17 +29,47 @@ public MyTimer() _timer = new Timer( delegate { - Next = DateTime.Now.Add(Divisor); + Next = DateTime.Now.Add(Period); Tick?.Invoke(); }); } - public bool Change(TimeSpan dueTime, TimeSpan divisor) + public bool Change(TimeSpan dueTime, TimeSpan period) { - Divisor = divisor; + Period = period; Next = DateTime.Now.Add(dueTime); - return _timer.Change(dueTime, divisor); + return _timer.Change(dueTime, period); + } + + #region Dispose + protected virtual void Dispose(bool disposing) + { + if (_disposedValue) + return; + + if (disposing) + { + _timer.Dispose(); + // TODO: освободить управляемое состояние (управляемые объекты) + } + + // TODO: освободить неуправляемые ресурсы (неуправляемые объекты) и переопределить метод завершения + // TODO: установить значение NULL для больших полей + _disposedValue = true; } - public void Dispose() => _timer.Dispose(); + // // TODO: переопределить метод завершения, только если "Dispose(bool disposing)" содержит код для освобождения неуправляемых ресурсов + // ~MyTimer() + // { + // // Не изменяйте этот код. Разместите код очистки в методе "Dispose(bool disposing)". + // Dispose(disposing: false); + // } + + public void Dispose() + { + // Не изменяйте этот код. Разместите код очистки в методе "Dispose(bool disposing)". + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + #endregion } \ No newline at end of file diff --git a/HabiticaHourUpVSIX/SettingsExtensions.cs b/HabiticaHourUpVSIX/SettingsExtensions.cs index 9b5c190..7c0a2dc 100644 --- a/HabiticaHourUpVSIX/SettingsExtensions.cs +++ b/HabiticaHourUpVSIX/SettingsExtensions.cs @@ -4,7 +4,7 @@ namespace HabiticaHourUpVSIX; // Need read before write, because there may be data that needs to be left untouched -public static class SettingsExtensions +public static partial class SettingsExtensions { public static void SetLastTickAfterWithSave(this SettingsWithSaving obj1, TimeSpan lastTickToSet) { diff --git a/HabiticaHourUpVSIX/SettingsExtensions_v2.cs b/HabiticaHourUpVSIX/SettingsExtensions_v2.cs new file mode 100644 index 0000000..8ef840a --- /dev/null +++ b/HabiticaHourUpVSIX/SettingsExtensions_v2.cs @@ -0,0 +1,38 @@ +using HabiticaHourUpVSIX; +using HabiticaHourUpVSIX.AppSettings.Abstractions; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +public static partial class SettingsExtensions +{ + // Object as key because unknown T of SettingsWithSaving + private static readonly Dictionary<(object, string propertyName), PropertyInfo> _cache = []; + private static readonly Dictionary _cachedTypes = []; + + public static void SetWithSave(this SettingsWithSaving obj1, + Expression> expression, + TProperty value) where T : struct + { + if (expression.Body is not MemberExpression memberExpression) + throw new InvalidOperationException("Invalid expression. Should have property that returns."); + string memberName = memberExpression.Member.Name; + + var settingsReadBoxed = (object)obj1.Read(); + var property = GetProperty(obj1, memberName); + + property.SetValue(settingsReadBoxed, value); + + var settingsToWrite = (T)settingsReadBoxed; + obj1.Write(settingsToWrite); + obj1.Save(); + + PropertyInfo GetProperty(object obj1, string memberName) + { + Type type = _cachedTypes.GetOrSet(obj1, () => typeof(T)); + PropertyInfo property = _cache.GetOrSet((obj1, memberName), () => type.GetProperty(memberName)); + + return property; + } + } +} \ No newline at end of file diff --git a/HabiticaHourUpVSIX/ToolWindows/SettingsWindowControl.xaml b/HabiticaHourUpVSIX/ToolWindows/SettingsWindowControl.xaml index a007ac5..ee0134c 100644 --- a/HabiticaHourUpVSIX/ToolWindows/SettingsWindowControl.xaml +++ b/HabiticaHourUpVSIX/ToolWindows/SettingsWindowControl.xaml @@ -11,7 +11,7 @@ xmlns:toolkit="clr-namespace:Community.VisualStudio.Toolkit;assembly=Community.VisualStudio.Toolkit" toolkit:Themes.UseVsTheme="True" mc:Ignorable="d" - d:DesignHeight="370" + d:DesignHeight="450" d:DesignWidth="327" Name="MyToolWindow" xmlns:local="clr-namespace:HabiticaHourUpVSIX" @@ -34,6 +34,8 @@ + +