Skip to content

Commit

Permalink
Added play beep button for test audio.
Browse files Browse the repository at this point in the history
Renamed Tests project.
  • Loading branch information
Ar6yZuK authored and Ar6yZuK committed Mar 6, 2024
2 parents 799c054 + 3d137d7 commit ff60ff6
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 26 deletions.
2 changes: 1 addition & 1 deletion HabiticaHourUpVSIX.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HabiticaHourUpVSIX", "HabiticaHourUpVSIX\HabiticaHourUpVSIX.csproj", "{07D5F794-ACB0-4774-96B5-8A9D1C7D2A07}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SettingsTests", "SettingsTests\SettingsTests.csproj", "{2E485C89-4D7C-410F-A8B5-0B27DBD1AB36}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HabiticaHourUpVSIX.Tests", "SettingsTests\HabiticaHourUpVSIX.Tests.csproj", "{2E485C89-4D7C-410F-A8B5-0B27DBD1AB36}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
84 changes: 78 additions & 6 deletions HabiticaHourUpVSIX/AppSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,78 @@ public override void Save()
Source.Save();
}
}
internal class SettingsInFile<T>(string fileName, T defaultSettings) : SettingsWithSaving<T>
where T : struct
{
public override T Read()
{
if (!File.Exists(fileName))
{
Write(defaultSettings);
return defaultSettings;
}

string data = File.ReadAllText(fileName);
var result = JsonConvert.DeserializeObject<T>(data);

return result;
}

public override void Write(T value)
{
string data = JsonConvert.SerializeObject(value, Formatting.Indented);
WriteDataToFile(fileName, data);

static void WriteDataToFile(string fileName, string data)
{
CreateDirectoryIfNotExists(Path.GetDirectoryName(fileName));
File.WriteAllText(fileName, data);
static void CreateDirectoryIfNotExists(string dirPath)
{
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
}
}
}

}
// TODO: Maybe add ICachedSettings interface if needed
internal class CachedSettings<T>(Settings<T> settingsToCache, TimeSpan timeOfCache) : Settings<T>
where T : struct
{
private DateTime _expires;
private T _cachedValue;

public override T Read()
{
if (_expires > DateTime.Now)
return _cachedValue;

_expires = DateTime.Now + timeOfCache;
return _cachedValue = settingsToCache.Read();
}
public override void Write(T value)
{
_expires = DateTime.Now - TimeSpan.FromSeconds(1d);
settingsToCache.Write(value);
}
}
internal class CachedSettingsWithSaving<T>(SettingsWithSaving<T> settings, TimeSpan timeOfCache) : SettingsWithSaving<T>
where T : struct
{
private readonly CachedSettings<T> _cachedSettings = new(settings, timeOfCache);

public override T Read() => _cachedSettings.Read();
public override void Write(T value) => _cachedSettings.Write(value);
}
internal class CachedSettingsInFile<T>(string fileName, T defaultSettings, TimeSpan timeOfCache) : SettingsWithSaving<T>
where T : struct
{
private readonly CachedSettingsWithSaving<T> _cachedSettingsInFile = new(new SettingsInFile<T>(fileName, defaultSettings), timeOfCache);

public override T Read() => _cachedSettingsInFile.Read();
public override void Write(T value) => _cachedSettingsInFile.Write(value);
}
internal sealed class HabiticaSettings : SettingsWithSaving<HabiticaSettings1, HabiticaSettingsModel>
{
protected override HabiticaSettings1 Source => HabiticaSettings1.Default;
Expand All @@ -81,13 +153,13 @@ public override void Save()
}
internal sealed class CredentialsSettings : SettingsWithSaving<CredentialsSettings1, HabiticaCredentials>
{
protected override CredentialsSettings1 Source => CredentialsSettings1.Default;
protected override CredentialsSettings1 Source => CredentialsSettings1.Default;

public override void Save()
{
base.Save();
Source.Save();
}
public override void Save()
{
base.Save();
Source.Save();
}
}
internal sealed class SessionSettings : Settings<SessionSettingsModel>
{
Expand Down
1 change: 1 addition & 0 deletions HabiticaHourUpVSIX/AppSettings/SettingsAbstractions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public interface ISettings<T>
T Read();
void Write(T value);
}
// TODO: Maybe add IDisposable
public interface ISaveable<T>
where T : struct
{
Expand Down
51 changes: 38 additions & 13 deletions HabiticaHourUpVSIX/HabiticaHourUpVSIXPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using HabiticaHourUpVSIX.ToolWindows;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Threading;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
#nullable enable
Expand Down Expand Up @@ -47,27 +48,31 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke
if (!userSettings.BeepOnSuccess)
return;

SetMusicPathIfNull(userSettings.BeepAudioPath);
_soundPlayer.Play();

void SetMusicPathIfNull(string beepMusicPath)
=> _soundPlayer.AudioPath = string.IsNullOrEmpty(_soundPlayer.AudioPath) ? beepMusicPath : _soundPlayer.AudioPath;
// UserSettingsReader is CachedSettings that means Play Beep can read from settings without performance decreasing
PlayBeep();
};

// timeOfCache is expected time of load
var timeOfCache = TimeSpan.FromSeconds(10);
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string vsixSettingsPath = $"{appDataPath}/Ar6yZuK/VSIX/{Vsix.Name}/";

SessionSettingsReader = new SessionSettings();
CredentialsSettings = new CredentialsSettings();
// TODO: Maybe encrypt HabiticaCredentials somehow
CredentialsSettings = new CachedSettingsInFile<HabiticaCredentials>($"{vsixSettingsPath}credentials.json", new("", ""), timeOfCache);

UserSettingsReader = new UserSettings();
UserSettingsModel defaultUserSettings = new(TimeSpan.FromHours(1), "", IsAutoScoreUp: false, ShowErrorOnFailure: true, BeepOnSuccess: true, "");
UserSettingsReader = new CachedSettingsInFile<UserSettingsModel>($"{vsixSettingsPath}user_settings.json", defaultUserSettings, timeOfCache);
UserSettingsReader.OnSaving += UserSettingsReader_OnSaving;

HabiticaSettingsReader = new HabiticaSettings();
HabiticaSettingsModel habiticaSettings = HabiticaSettingsReader.Read();

UserSettingsModel vsSettings = UserSettingsReader.Read();
HabiticaSettingsReader = new CachedSettingsInFile<HabiticaSettingsModel>($"{vsixSettingsPath}local_settings.json", new(), timeOfCache);

Timer = new MyTimer();
Timer.Tick += Tick;

HabiticaSettingsModel habiticaSettings = HabiticaSettingsReader.Read();
UserSettingsModel vsSettings = UserSettingsReader.Read();

TimeSpan tickAfter = habiticaSettings.LastWorkTime <= TimeSpan.Zero ? vsSettings.Divisor : habiticaSettings.LastWorkTime;

Timer.Change(tickAfter, vsSettings.Divisor);
Expand All @@ -78,6 +83,25 @@ void SetMusicPathIfNull(string beepMusicPath)
VS.Events.SolutionEvents.OnAfterCloseSolution += OnClose;
}

internal void PlayBeep()
{
var userSettings = UserSettingsReader.Read();

_soundPlayer.AudioPath = userSettings.BeepAudioPath;
if (string.IsNullOrWhiteSpace(userSettings.BeepAudioPath))
{
VS.MessageBox.ShowError($"{nameof(userSettings.BeepOnSuccess)} was enabled, but {nameof(userSettings.BeepAudioPath)} was empty");
return;
}
if (!File.Exists(userSettings.BeepAudioPath))
{
VS.MessageBox.ShowError("Attempt to play audio with non-existent audio file");
return;
}

_soundPlayer.Play();
}

private void Tick()
{
AddTicksToAllSettings(1);
Expand Down Expand Up @@ -122,7 +146,8 @@ private void UserSettingsReader_OnSaving(UserSettingsModel userSettingsModel)

private void OnClose()
{
this.HabiticaSettingsReader.SetLastTickAfterWithSave(Timer.NextTick);
// TODO: do not remember last work time. Maybe delete property LastWorkTime
this.HabiticaSettingsReader.SetWithSave(x => x.LastWorkTime, Timer.NextTick);
}

private void AddTicksToAllSettings(int addedTicks)
Expand All @@ -140,7 +165,7 @@ private void AddTicksToAllSettings(int addedTicks)

protected override void Dispose(bool disposing)
{
Timer.Dispose();
Timer?.Dispose();
base.Dispose(disposing);
}
}
12 changes: 10 additions & 2 deletions HabiticaHourUpVSIX/IAudioPlayer.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
namespace HabiticaHourUpVSIX;
using System.IO;

namespace HabiticaHourUpVSIX;
#nullable enable

internal interface IAudioPlayer
{
string? AudioPath { get; set; }
void Play();
[Serializable] public class AudioException(string message) : Exception(message);
}
internal class SoundPlayer : IAudioPlayer
{
Expand All @@ -22,5 +25,10 @@ internal class AudioPlayer : IAudioPlayer
public string? AudioPath { get => _player.URL; set => _player.URL = value; }

public void Play()
=> _player.controls.play();
{
if (!File.Exists(AudioPath))
throw new IAudioPlayer.AudioException($"Audio file not exists: {AudioPath}");

_player.controls.play();
}
}
4 changes: 3 additions & 1 deletion HabiticaHourUpVSIX/ToolWindows/SettingsWindowControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,13 @@
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>

<Label Content="Beep audio file path "/>
<TextBox Text="{Binding OnBeepAudioPath}" Grid.Column="1"/>
<Button Content="&#x1F4C1;" Command="{Binding GetAudioBeepPathDialogCommand}" Margin="3.45" Grid.Column="2"/>
<Button Content="&#x1F508;" Margin="2.7" Command="{Binding TestBeepCommand}" Grid.Column="2"/>
<Button Content="&#x1F4C1;" Command="{Binding GetAudioBeepPathDialogCommand}" Margin="0, 3.45, 3.45, 3.45" Grid.Column="3"/>
</Grid>
</Grid>
</ScrollViewer>
Expand Down
3 changes: 3 additions & 0 deletions HabiticaHourUpVSIX/ToolWindows/SettingsWindowControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ private void GetAudioBeepPathDialog()
OnPropertyChanged(nameof(OnBeepAudioPath));
}
}
[RelayCommand]
private void TestBeep()
=> _package.PlayBeep();

protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Expand Down
2 changes: 1 addition & 1 deletion HabiticaHourUpVSIX/source.extension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal sealed partial class Vsix
public const string Name = "HabiticaHourUpVSIX";
public const string Description = @"Empty VSIX Project.";
public const string Language = "en-US";
public const string Version = "1.3.2";
public const string Version = "1.5.0";
public const string Author = "Ar6";
public const string Tags = "";
}
Expand Down
2 changes: 1 addition & 1 deletion HabiticaHourUpVSIX/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" ?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="HabiticaHourUpVSIX.ade8e5f3-585d-49ca-8916-064b2237b928" Version="1.3.2" Language="en-US" Publisher="Ar6" />
<Identity Id="HabiticaHourUpVSIX.ade8e5f3-585d-49ca-8916-064b2237b928" Version="1.5.0" Language="en-US" Publisher="Ar6" />
<DisplayName>HabiticaHourUpVSIX</DisplayName>
<Description xml:space="preserve">Empty VSIX Project.</Description>
<Icon>Resources\Icon.png</Icon>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
Expand Down

0 comments on commit ff60ff6

Please sign in to comment.