diff --git a/src/AudioBand.Logging/AudioBand.Logging.csproj b/src/AudioBand.Logging/AudioBand.Logging.csproj index 6e5a9557..170e0bbd 100644 --- a/src/AudioBand.Logging/AudioBand.Logging.csproj +++ b/src/AudioBand.Logging/AudioBand.Logging.csproj @@ -9,9 +9,10 @@ Properties AudioBand.Logging AudioBand.Logging - v4.6.1 + v4.7 512 true + true @@ -88,7 +89,7 @@ 0.1.4 - 4.6.3 + 4.6.5 1.1.118 diff --git a/src/AudioBand.Logging/app.config b/src/AudioBand.Logging/app.config index 74f5bf7e..9ea4dacd 100644 --- a/src/AudioBand.Logging/app.config +++ b/src/AudioBand.Logging/app.config @@ -1,15 +1,15 @@ - + - - + + - - + + - \ No newline at end of file + diff --git a/src/AudioBand.Test/Assets/imgsource.png b/src/AudioBand.Test/Assets/imgsource.png new file mode 100644 index 00000000..f6512b71 Binary files /dev/null and b/src/AudioBand.Test/Assets/imgsource.png differ diff --git a/src/AudioBand.Test/AudioBand.Test.csproj b/src/AudioBand.Test/AudioBand.Test.csproj index 7331766e..b4dca433 100644 --- a/src/AudioBand.Test/AudioBand.Test.csproj +++ b/src/AudioBand.Test/AudioBand.Test.csproj @@ -93,18 +93,20 @@ - - - - - - - - + + + + + + + + + + - - - + + + @@ -121,24 +123,28 @@ - 4.10.1 - - - 1.4.0 - - - 1.4.0 + 4.12.0 - 0.11.0 + 0.12.0 4.5.2 - - 4.5.0 + + 2.4.1 + + + 2.4.1 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + PreserveNewest + + \ No newline at end of file diff --git a/src/AudioBand.Test/AudioBand.Test.csproj.DotSettings b/src/AudioBand.Test/AudioBand.Test.csproj.DotSettings new file mode 100644 index 00000000..bf95c7ff --- /dev/null +++ b/src/AudioBand.Test/AudioBand.Test.csproj.DotSettings @@ -0,0 +1,5 @@ + + True + True + True + True \ No newline at end of file diff --git a/src/AudioBand.Test/ButtonViewModels.cs b/src/AudioBand.Test/ButtonViewModels.cs deleted file mode 100644 index 59b89fbc..00000000 --- a/src/AudioBand.Test/ButtonViewModels.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Drawing; -using System.Threading.Tasks; -using AudioBand.AudioSource; -using AudioBand.Models; -using AudioBand.Settings; -using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; - -namespace AudioBand.Test -{ - [TestClass] - public class ButtonViewModels - { - private Mock _appSettings; - private Mock _dialog; - - [TestInitialize] - public void TestInit() - { - _appSettings = new Mock(); - _dialog = new Mock(); - } - - [TestMethod] - public void NextButtonListensforProfileChanges() - { - var first = new NextButton() {Height = 1}; - var second = new NextButton() {Height = 2}; - _appSettings.SetupSequence(m => m.NextButton) - .Returns(first) - .Returns(second); - - var vm = new NextButtonViewModel(_appSettings.Object, _dialog.Object); - bool raised = false; - vm.PropertyChanged += (_, __) => raised = true; - - Assert.AreEqual(first.Height, vm.Height); - _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.Height, vm.Height); - } - - - [TestMethod] - public async Task NextButtonCommandCallsNextTrack() - { - _appSettings.SetupGet(m => m.NextButton).Returns(new NextButton()); - var vm = new NextButtonViewModel(_appSettings.Object, _dialog.Object); - var audioSourceMock = new Mock(); - audioSourceMock.Setup(m => m.NextTrackAsync()).Returns(Task.CompletedTask); - vm.AudioSource = audioSourceMock.Object; - - await vm.NextTrackCommand.ExecuteAsync(null); - audioSourceMock.Verify(m => m.NextTrackAsync()); - } - - [TestMethod] - public void PlayPauseButtonListensForProfileChanges() - { - var first = new PlayPauseButton() {Height = 1}; - var second = new PlayPauseButton() {Height = 2}; - _appSettings.SetupSequence(m => m.PlayPauseButton) - .Returns(first) - .Returns(second); - - var vm = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object); - bool raised = false; - vm.PropertyChanged += (_, __) => raised = true; - - Assert.AreEqual(first.Height, vm.Height); - _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.Height, vm.Height); - } - - [TestMethod] - public void PlayPauseButtonMarkedAsEditingWhenContentIsEdited() - { - _appSettings.SetupGet(m => m.PlayPauseButton).Returns(new PlayPauseButton()); - var viewModel = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object); - - viewModel.PlayContent.Text = ""; - Assert.IsTrue(viewModel.PlayContent.IsEditing); - Assert.IsTrue(viewModel.IsEditing); - - viewModel.EndEdit(); - Assert.IsFalse(viewModel.IsEditing); - Assert.IsFalse(viewModel.PlayContent.IsEditing); - - viewModel.PauseContent.Text = ""; - Assert.IsTrue(viewModel.IsEditing); - Assert.IsTrue(viewModel.PauseContent.IsEditing); - } - - [TestMethod] - public void PlayPauseButtonListensToAudioSource() - { - _appSettings.SetupGet(m => m.PlayPauseButton).Returns(new PlayPauseButton()); - var viewModel = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object); - var audioSourceMock = new Mock(); - - viewModel.AudioSource = audioSourceMock.Object; - - audioSourceMock.Raise(m => m.IsPlayingChanged += null, null, true); - Assert.IsTrue(viewModel.IsPlaying); - Assert.IsFalse(viewModel.IsPlayButtonShown); - - audioSourceMock.Raise(m => m.IsPlayingChanged += null, null, false); - Assert.IsFalse(viewModel.IsPlaying); - Assert.IsTrue(viewModel.IsPlayButtonShown); - } - - [TestMethod] - public async Task PlayPauseButtonPlayAndPauseCommandWorks() - { - _appSettings.SetupGet(m => m.PlayPauseButton).Returns(new PlayPauseButton()); - var viewModel = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object); - var audioSourceMock = new Mock(); - var isPlayingSequence = new[] {true, false}; - var index = 0; - audioSourceMock.Setup(m => m.PlayTrackAsync()) - .Callback(() => Assert.AreEqual(isPlayingSequence[index++], true)) - .Returns(Task.CompletedTask); - audioSourceMock.Setup(m => m.PauseTrackAsync()) - .Callback(() => Assert.AreEqual(isPlayingSequence[index++], false)) - .Returns(Task.CompletedTask); - - await viewModel.PlayPauseTrackCommand.ExecuteAsync(null); - audioSourceMock.Raise(m => m.IsPlayingChanged += null, null, true); - await viewModel.PlayPauseTrackCommand.ExecuteAsync(null); - } - - [TestMethod] - public void PreviousButtonListensForProfileChanges() - { - var first = new PreviousButton() { Height = 1 }; - var second = new PreviousButton() { Height = 2 }; - _appSettings.SetupSequence(m => m.PreviousButton) - .Returns(first) - .Returns(second); - - var vm = new PreviousButtonViewModel(_appSettings.Object, _dialog.Object); - bool raised = false; - vm.PropertyChanged += (_, __) => raised = true; - - Assert.AreEqual(first.Height, vm.Height); - _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.Height, vm.Height); - } - - [TestMethod] - public async Task PreviousButtonCommandCallsPreviousTrack() - { - _appSettings.SetupGet(m => m.PreviousButton).Returns(new PreviousButton()); - var vm = new PreviousButtonViewModel(_appSettings.Object, _dialog.Object); - var audioSourceMock = new Mock(); - audioSourceMock.Setup(m => m.PreviousTrackAsync()).Returns(Task.CompletedTask); - vm.AudioSource = audioSourceMock.Object; - - await vm.PreviousTrackCommand.ExecuteAsync(null); - audioSourceMock.Verify(m => m.PreviousTrackAsync()); - } - - [TestMethod] - public void RepeatModeButtonListensForProfileChanges() - { - var first = new RepeatModeButton() { Height = 1 }; - var second = new RepeatModeButton() { Height = 2 }; - _appSettings.SetupSequence(m => m.RepeatModeButton) - .Returns(first) - .Returns(second); - - var vm = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object); - bool raised = false; - vm.PropertyChanged += (_, __) => raised = true; - - Assert.AreEqual(first.Height, vm.Height); - _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.Height, vm.Height); - } - - [TestMethod] - public void RepeatModeButtonMarkedAsEditingWhenContentIsEditing() - { - _appSettings.SetupGet(m => m.RepeatModeButton).Returns(new RepeatModeButton()); - var viewModel = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object); - - Assert.IsFalse(viewModel.RepeatTrackContent.IsEditing); - Assert.IsFalse(viewModel.IsEditing); - - viewModel.RepeatTrackContent.Text = "test"; - - Assert.IsTrue(viewModel.RepeatTrackContent.IsEditing); - Assert.IsTrue(viewModel.IsEditing); - } - - [TestMethod] - public void RepeatModeButtonSubscribesToAudioSource() - { - _appSettings.SetupGet(m => m.RepeatModeButton).Returns(new RepeatModeButton()); - var viewModel = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object); - var audiosourceMock = new Mock(); - viewModel.AudioSource = audiosourceMock.Object; - - audiosourceMock.Raise(m => m.RepeatModeChanged += null, null, RepeatMode.RepeatTrack); - Assert.AreEqual(RepeatMode.RepeatTrack, viewModel.RepeatMode); - } - - [TestMethod] - public async Task RepeatModeButtonCyclesRepeatMode() - { - _appSettings.SetupGet(m => m.RepeatModeButton).Returns(new RepeatModeButton()); - var viewModel = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object); - var audiosourceMock = new Mock(); - var repeatSequence = new[] {RepeatMode.RepeatContext, RepeatMode.RepeatTrack, RepeatMode.Off}; - var index = 0; - audiosourceMock.Setup(m => m.SetRepeatModeAsync(It.IsAny())) - .Callback((RepeatMode mode) => Assert.AreEqual(repeatSequence[index++], mode)) - .Returns(Task.CompletedTask); - - viewModel.AudioSource = audiosourceMock.Object; - - Assert.AreEqual(RepeatMode.Off, viewModel.RepeatMode); - await viewModel.CycleRepeatModeCommand.ExecuteAsync(null); - audiosourceMock.Raise(m => m.RepeatModeChanged += null, null, RepeatMode.RepeatContext); - await viewModel.CycleRepeatModeCommand.ExecuteAsync(null); - audiosourceMock.Raise(m => m.RepeatModeChanged += null, null, RepeatMode.RepeatTrack); - await viewModel.CycleRepeatModeCommand.ExecuteAsync(null); - } - - [TestMethod] - public void ShuffleModeButtonListensForProfileChanges() - { - var first = new ShuffleModeButton() { Height = 1 }; - var second = new ShuffleModeButton() { Height = 2 }; - _appSettings.SetupSequence(m => m.ShuffleModeButton) - .Returns(first) - .Returns(second); - - var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object); - bool raised = false; - vm.PropertyChanged += (_, __) => raised = true; - - Assert.AreEqual(first.Height, vm.Height); - _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.Height, vm.Height); - } - - [TestMethod] - public void ShuffleModeButtonMarkedAsEditingWhenContentIsEdited() - { - _appSettings.SetupGet(m => m.ShuffleModeButton).Returns(new ShuffleModeButton()); - var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object); - - vm.ShuffleOnContent.Text = "A"; - Assert.IsTrue(vm.ShuffleOnContent.IsEditing); - Assert.IsTrue(vm.IsEditing); - - vm.EndEdit(); - Assert.IsFalse(vm.ShuffleOnContent.IsEditing); - Assert.IsFalse(vm.IsEditing); - - vm.ShuffleOffContent.Text = "..."; - Assert.IsTrue(vm.ShuffleOffContent.IsEditing); - Assert.IsTrue(vm.IsEditing); - } - - [TestMethod] - public void ShuffleModeButtonSubscribesToAudioSource() - { - _appSettings.SetupGet(m => m.ShuffleModeButton).Returns(new ShuffleModeButton()); - var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object); - var audioSourceMock = new Mock(); - vm.AudioSource = audioSourceMock.Object; - - audioSourceMock.Raise(m => m.ShuffleChanged += null, null, true); - Assert.IsTrue(vm.IsShuffleOn); - - audioSourceMock.Raise(m => m.ShuffleChanged += null, null, false); - Assert.IsFalse(vm.IsShuffleOn); - } - - [TestMethod] - public async Task ShuffleModeButtonCommandTogglesShuffle() - { - _appSettings.SetupGet(m => m.ShuffleModeButton).Returns(new ShuffleModeButton()); - var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object); - var audioSourceMock = new Mock(); - var sequence = new[] {true, false}; - var index = 0; - audioSourceMock.Setup(m => m.SetShuffleAsync(It.IsAny())) - .Callback((bool shuffle) => Assert.AreEqual(sequence[index++], shuffle)) - .Returns(Task.CompletedTask); - - vm.AudioSource = audioSourceMock.Object; - await vm.ToggleShuffleCommand.ExecuteAsync(null); - audioSourceMock.Raise(m => m.ShuffleChanged += null, null, true); - await vm.ToggleShuffleCommand.ExecuteAsync(null); - } - } -} diff --git a/src/AudioBand.Test/Settings/SettingsMigrationTests.cs b/src/AudioBand.Test/Settings/SettingsMigrationTests.cs new file mode 100644 index 00000000..9c28c433 --- /dev/null +++ b/src/AudioBand.Test/Settings/SettingsMigrationTests.cs @@ -0,0 +1,503 @@ +using System.Collections.Generic; +using System.Windows.Media; +using AudioBand.Models; +using AudioBand.Settings; +using AudioBand.Settings.Migrations; +using AudioBand.Settings.Models.v3; +using AudioBand.Settings.Models.V1; +using V1Settings = AudioBand.Settings.Models.V1.AudioBandSettings; +using V2Settings = AudioBand.Settings.Models.V2.Settings; +using Nett; +using Xunit; +using AudioSourceSetting = AudioBand.Settings.Models.V1.AudioSourceSetting; + +namespace AudioBand.Test +{ + public class SettingsMigrationTests + { + [Fact] + public void MigrateV1ToV2_Main() + { + var v1 = new V1Settings() + { + AudioSource = "test" + }; + + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal("2", v2.Version); + Assert.Equal("test", v2.AudioSource); + } + + [Fact] + public void MigrateV1ToV2_AlbumArtPopup() + { + var setting = new AlbumArtPopupAppearance + { + Width = 100, + Height = 50, + IsVisible = true, + Margin = 100, + XOffset = 50 + }; + + var v1 = new V1Settings() + { + AlbumArtPopupAppearance = setting, + }; + + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.AlbumArtPopupSettings.Width, setting.Width); + Assert.Equal(v2.AlbumArtPopupSettings.Height, setting.Height); + Assert.Equal(v2.AlbumArtPopupSettings.IsVisible, setting.IsVisible); + Assert.Equal(v2.AlbumArtPopupSettings.Margin, setting.Margin); + Assert.Equal(v2.AlbumArtPopupSettings.XPosition, setting.XOffset); + } + + [Fact] + public void MigrateV1ToV2_AlbumArt() + { + var setting = new AlbumArtAppearance + { + Width = 10, + Height = 10, + IsVisible = true, + XPosition = 10, + YPosition = 10, + PlaceholderPath = "test" + }; + + var v1 = new V1Settings + { + AlbumArtAppearance = setting + }; + + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.AlbumArtSettings.Width, setting.Width); + Assert.Equal(v2.AlbumArtSettings.Height, setting.Height); + Assert.Equal(v2.AlbumArtSettings.IsVisible, setting.IsVisible); + Assert.Equal(v2.AlbumArtSettings.XPosition, setting.XPosition); + Assert.Equal(v2.AlbumArtSettings.YPosition, setting.YPosition); + Assert.Equal(v2.AlbumArtSettings.PlaceholderPath, setting.PlaceholderPath); + } + + [Fact] + public void MigrateV1ToV2_Audioband() + { + var setting = new AudioBandAppearance + { + Height = 20, + Width = 50, + }; + + var v1 = new V1Settings + { + AudioBandAppearance = setting + }; + + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.AudioBandSettings.Width, setting.Width); + Assert.Equal(v2.AudioBandSettings.Height, setting.Height); + } + + [Fact] + public void MigrateV1ToV2_NextSong() + { + var setting = new NextSongButtonAppearance + { + Width = 20, + Height = 20, + XPosition = 10, + IsVisible = false, + YPosition = 30, + ImagePath = "path" + }; + + var v1 = new V1Settings + { + NextSongButtonAppearance = setting + }; + + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.NextButtonSettings.Width, setting.Width); + Assert.Equal(v2.NextButtonSettings.Height, setting.Height); + Assert.Equal(v2.NextButtonSettings.IsVisible, setting.IsVisible); + Assert.Equal(v2.NextButtonSettings.XPosition, setting.XPosition); + Assert.Equal(v2.NextButtonSettings.YPosition, setting.YPosition); + Assert.Equal(v2.NextButtonSettings.ImagePath, setting.ImagePath); + } + + [Fact] + public void MigrateV1ToV2_AudioSourceSettings() + { + var setting1 = new AudioSourceSettingsCollection + { + Name = "test", + Settings = new List {new AudioSourceSetting {Name = "key1", Value = "val1"}} + }; + + var setting2 = new AudioSourceSettingsCollection + { + Name = "test2", + Settings = new List { new AudioSourceSetting { Name = "key2", Value = "val2" } } + }; + + var settings = new List {setting1,setting2}; + var v1 = new V1Settings + { + AudioSourceSettings = settings + }; + + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.AudioSourceSettings.Count, settings.Count); + Assert.Equal(v2.AudioSourceSettings[0].AudioSourceName, setting1.Name); + Assert.Equal(v2.AudioSourceSettings[0].Settings.Count, setting1.Settings.Count); + Assert.Equal(v2.AudioSourceSettings[0].Settings[0].Name, setting1.Settings[0].Name); + Assert.Equal(v2.AudioSourceSettings[0].Settings[0].Value, setting1.Settings[0].Value); + + Assert.Equal(v2.AudioSourceSettings[1].AudioSourceName, setting2.Name); + Assert.Equal(v2.AudioSourceSettings[1].Settings.Count, setting2.Settings.Count); + Assert.Equal(v2.AudioSourceSettings[1].Settings[0].Name, setting2.Settings[0].Name); + Assert.Equal(v2.AudioSourceSettings[1].Settings[0].Value, setting2.Settings[0].Value); + } + + [Fact] + public void MigrateV1ToV2_PlayPauseButton() + { + var setting = new PlayPauseButtonAppearance + { + Width = 1, + Height = 2, + XPosition = 3, + IsVisible = true, + YPosition = 4, + PauseButtonImagePath = "pause", + PlayButtonImagePath = "play" + }; + + var v1 = new V1Settings {PlayPauseButtonAppearance = setting}; + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.PlayPauseButtonSettings.Width, setting.Width); + Assert.Equal(v2.PlayPauseButtonSettings.Height, setting.Height); + Assert.Equal(v2.PlayPauseButtonSettings.XPosition, setting.XPosition); + Assert.Equal(v2.PlayPauseButtonSettings.YPosition, setting.YPosition); + Assert.Equal(v2.PlayPauseButtonSettings.IsVisible, setting.IsVisible); + Assert.Equal(v2.PlayPauseButtonSettings.PauseButtonImagePath, setting.PauseButtonImagePath); + Assert.Equal(v2.PlayPauseButtonSettings.PlayButtonImagePath, setting.PlayButtonImagePath); + } + + [Fact] + public void MigrateV1ToV2_PreviousButton() + { + var setting = new PreviousSongButtonAppearance + { + Width = 1, + Height = 2, + XPosition = 3, + IsVisible = true, + YPosition = 4, + ImagePath = "path" + }; + + var v1 = new V1Settings {PreviousSongButtonAppearance = setting}; + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.PreviousButtonSettings.Height, setting.Height); + Assert.Equal(v2.PreviousButtonSettings.Width, setting.Width); + Assert.Equal(v2.PreviousButtonSettings.XPosition, setting.XPosition); + Assert.Equal(v2.PreviousButtonSettings.YPosition, setting.YPosition); + Assert.Equal(v2.PreviousButtonSettings.IsVisible, setting.IsVisible); + Assert.Equal(v2.PreviousButtonSettings.ImagePath, setting.ImagePath); + } + + [Fact] + public void MigrateV1ToV2_ProgressBar() + { + var setting = new ProgressBarAppearance + { + Height = 1, + Width = 2, + XPosition = 3, + IsVisible = false, + YPosition = 5, + BackgroundColor = Colors.White, + ForegroundColor = Colors.Red, + }; + + var v1 = new V1Settings {ProgressBarAppearance = setting}; + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.ProgressBarSettings.Width, setting.Width); + Assert.Equal(v2.ProgressBarSettings.Height, setting.Height); + Assert.Equal(v2.ProgressBarSettings.XPosition, setting.XPosition); + Assert.Equal(v2.ProgressBarSettings.YPosition, setting.YPosition); + Assert.Equal(v2.ProgressBarSettings.IsVisible, setting.IsVisible); + Assert.Equal(v2.ProgressBarSettings.BackgroundColor, setting.BackgroundColor); + Assert.Equal(v2.ProgressBarSettings.ForegroundColor, setting.ForegroundColor); + } + + [Fact] + public void MigrateV1ToV2_CustomText() + { + var text1 = new TextAppearance + { + Color = Colors.Red, + Width = 1, + Height = 2, + Name = "test", + XPosition = 4, + IsVisible = true, + YPosition = 10, + ScrollSpeed = 20, + FontSize = 1f, + FontFamily = "family", + Alignment = CustomLabel.TextAlignment.Center, + FormatString = "123", + }; + + var texts = new List() {text1}; + var v1 = new V1Settings {TextAppearances = texts}; + var v2 = Migration.MigrateSettings(v1, "0.1", "2"); + + Assert.Equal(v2.CustomLabelSettings.Count, texts.Count); + Assert.Equal(v2.CustomLabelSettings[0].Color, text1.Color); + Assert.Equal(v2.CustomLabelSettings[0].Width, text1.Width); + Assert.Equal(v2.CustomLabelSettings[0].Height, text1.Height); + Assert.Equal(v2.CustomLabelSettings[0].Name, text1.Name); + Assert.Equal(v2.CustomLabelSettings[0].XPosition, text1.XPosition); + Assert.Equal(v2.CustomLabelSettings[0].IsVisible, text1.IsVisible); + Assert.Equal(v2.CustomLabelSettings[0].YPosition, text1.YPosition); + Assert.Equal(v2.CustomLabelSettings[0].ScrollSpeed, text1.ScrollSpeed); + Assert.Equal(v2.CustomLabelSettings[0].FontSize, text1.FontSize); + Assert.Equal(v2.CustomLabelSettings[0].FontFamily, text1.FontFamily); + Assert.Equal(v2.CustomLabelSettings[0].Alignment, text1.Alignment); + Assert.Equal(v2.CustomLabelSettings[0].FormatString, text1.FormatString); + } + + [Fact] + public void MigrateV2ToV3_MigratesSuccessfully() + { + string settingsFile = @"Version = ""2"" +AudioSource = ""Spotify"" + +[AudioBandSettings] +Width = 500 +Height = 30 + +[PreviousButtonSettings] +ImagePath = """" +IsVisible = false +Width = 73 +Height = 12 +XPosition = 30 +YPosition = 15 + +[PlayPauseButtonSettings] +PlayButtonImagePath = """" +PauseButtonImagePath = """" +XPosition = 109 +YPosition = 15 +Width = 73 +Height = 12 +IsVisible = false + +[NextButtonSettings] +ImagePath = """" +IsVisible = false +Width = 73 +Height = 12 +XPosition = 176 +YPosition = 15 + +[ProgressBarSettings] +ForegroundColor = ""#32ABCD"" +BackgroundColor = ""#232323"" +IsVisible = true +XPosition = 330 +YPosition = 24 +Width = 130 +Height = 3 + +[AlbumArtSettings] +IsVisible = true +Width = 30 +Height = 30 +XPosition = 260 +YPosition = 0 +PlaceholderPath = """" + +[AlbumArtPopupSettings] +IsVisible = true +Width = 300 +Height = 300 +XPosition = 125 +Margin = 4 + +[[CustomLabelSettings]] +IsVisible = true +Width = 200 +Height = 20 +XPosition = 295 +YPosition = 0 +FontFamily = ""Segoe UI"" +FontSize = 11.0 +Color = ""#FFFFFF"" +FormatString = ""{*song}"" +Alignment = ""Center"" +Name = ""Song"" +ScrollSpeed = 50 +[[CustomLabelSettings]] +IsVisible = true +Width = 34 +Height = 12 +XPosition = 292 +YPosition = 17 +FontFamily = ""Segoe UI"" +FontSize = 8.0 +Color = ""#C3C3C3"" +FormatString = ""{time}"" +Alignment = ""Left"" +Name = ""Time"" +ScrollSpeed = 50 +[[CustomLabelSettings]] +IsVisible = true +Width = 35 +Height = 12 +XPosition = 460 +YPosition = 17 +FontFamily = ""Segoe UI"" +FontSize = 8.0 +Color = ""#C3C3C3"" +FormatString = ""{length}"" +Alignment = ""Right"" +Name = ""Song Length"" +ScrollSpeed = 50 +[[CustomLabelSettings]] +IsVisible = true +Width = 260 +Height = 15 +XPosition = 0 +YPosition = 0 +FontFamily = ""Segoe UI"" +FontSize = 9.0 +Color = ""White"" +FormatString = ""{artist}"" +Alignment = ""Right"" +Name = ""Artist"" +ScrollSpeed = 50 +[[CustomLabelSettings]] +IsVisible = true +Width = 260 +Height = 15 +XPosition = 0 +YPosition = 15 +FontFamily = ""Segoe UI"" +FontSize = 9.0 +Color = ""#AFAFAF"" +FormatString = ""{album}"" +Alignment = ""Right"" +Name = ""Album"" +ScrollSpeed = 50 + +[[AudioSourceSettings]] +AudioSourceName = ""Spotify"" + +[[AudioSourceSettings.Settings]] +Name = ""Spotify Client ID"" +Value = ""id"" +[[AudioSourceSettings.Settings]] +Name = ""Spotify Client secret"" +Value = ""secret"" +"; + var settings = TomlSettings.Create(cfg => + { + cfg.ConfigureType(type => type.WithConversionFor(convert => convert + .ToToml(SerializationConversions.ColorToString) + .FromToml(tomlString => SerializationConversions.StringToColor(tomlString.Value)))); + cfg.ConfigureType(type => type.WithConversionFor(convert => convert + .ToToml(SerializationConversions.EnumToString) + .FromToml(str => SerializationConversions.StringToEnum(str.Value)))); + cfg.ConfigureType(type => type.WithConversionFor(c => c + .FromToml(tml => tml.Value))); + }); + + var v2 = Toml.ReadString(settingsFile, settings); + var v3 = Migration.MigrateSettings(v2, "2", "3"); + + Assert.Equal("3", v3.Version); + Assert.Equal(v2.AudioSource, v3.AudioSource); + + Assert.Equal(v2.AlbumArtPopupSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.Width); + Assert.Equal(v2.AlbumArtPopupSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.Height); + Assert.Equal(v2.AlbumArtPopupSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.IsVisible); + Assert.Equal(v2.AlbumArtPopupSettings.Margin, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.Margin); + Assert.Equal(v2.AlbumArtPopupSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.XPosition); + + Assert.Equal(v2.AlbumArtSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.Width); + Assert.Equal(v2.AlbumArtSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.Height); + Assert.Equal(v2.AlbumArtSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.IsVisible); + Assert.Equal(v2.AlbumArtSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.XPosition); + Assert.Equal(v2.AlbumArtSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.YPosition); + Assert.Equal(v2.AlbumArtSettings.PlaceholderPath, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.PlaceholderPath); + + Assert.Equal(v2.AudioBandSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].AudioBandSettings.Width); + Assert.Equal(v2.AudioBandSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].AudioBandSettings.Height); + + Assert.Equal(v2.NextButtonSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.Width); + Assert.Equal(v2.NextButtonSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.Height); + Assert.Equal(v2.NextButtonSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.IsVisible); + Assert.Equal(v2.NextButtonSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.XPosition); + Assert.Equal(v2.NextButtonSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.YPosition); + Assert.Equal(v2.NextButtonSettings.ImagePath, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.Content.ImagePath); + + Assert.Equal(v2.AudioSourceSettings.Count, v3.AudioSourceSettings.Count); + Assert.Equal(v2.AudioSourceSettings[0].AudioSourceName, v3.AudioSourceSettings[0].AudioSourceName); + Assert.Equal(v2.AudioSourceSettings[0].Settings.Count, v3.AudioSourceSettings[0].Settings.Count); + Assert.Equal(v2.AudioSourceSettings[0].Settings[0].Name, v3.AudioSourceSettings[0].Settings[0].Name); + Assert.Equal(v2.AudioSourceSettings[0].Settings[0].Value, v3.AudioSourceSettings[0].Settings[0].Value); + + Assert.Equal(v2.PlayPauseButtonSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.Width); + Assert.Equal(v2.PlayPauseButtonSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.Height); + Assert.Equal(v2.PlayPauseButtonSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.XPosition); + Assert.Equal(v2.PlayPauseButtonSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.YPosition); + Assert.Equal(v2.PlayPauseButtonSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.IsVisible); + Assert.Equal(v2.PlayPauseButtonSettings.PauseButtonImagePath, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.PauseContent.ImagePath); + Assert.Equal(v2.PlayPauseButtonSettings.PlayButtonImagePath, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.PlayContent.ImagePath); + + Assert.Equal(v2.PreviousButtonSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.Height); + Assert.Equal(v2.PreviousButtonSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.Width); + Assert.Equal(v2.PreviousButtonSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.XPosition); + Assert.Equal(v2.PreviousButtonSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.YPosition); + Assert.Equal(v2.PreviousButtonSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.IsVisible); + Assert.Equal(v2.PreviousButtonSettings.ImagePath, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.Content.ImagePath); + + Assert.Equal(v2.ProgressBarSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.Width); + Assert.Equal(v2.ProgressBarSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.Height); + Assert.Equal(v2.ProgressBarSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.XPosition); + Assert.Equal(v2.ProgressBarSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.YPosition); + Assert.Equal(v2.ProgressBarSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.IsVisible); + Assert.Equal(v2.ProgressBarSettings.BackgroundColor, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.BackgroundColor); + Assert.Equal(v2.ProgressBarSettings.ForegroundColor, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.ForegroundColor); + + Assert.Equal(v2.CustomLabelSettings.Count, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings.Count); + Assert.Equal(v2.CustomLabelSettings[0].Color, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Color); + Assert.Equal(v2.CustomLabelSettings[0].Width, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Width); + Assert.Equal(v2.CustomLabelSettings[0].Height, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Height); + Assert.Equal(v2.CustomLabelSettings[0].Name, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Name); + Assert.Equal(v2.CustomLabelSettings[0].XPosition, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].XPosition); + Assert.Equal(v2.CustomLabelSettings[0].IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].IsVisible); + Assert.Equal(v2.CustomLabelSettings[0].YPosition, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].YPosition); + Assert.Equal(v2.CustomLabelSettings[0].ScrollSpeed, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].ScrollSpeed); + Assert.Equal(v2.CustomLabelSettings[0].FontSize, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].FontSize); + Assert.Equal(v2.CustomLabelSettings[0].FontFamily, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].FontFamily); + Assert.Equal(v2.CustomLabelSettings[0].Alignment, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Alignment); + Assert.Equal(v2.CustomLabelSettings[0].FormatString, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].FormatString); + } + } +} diff --git a/src/AudioBand.Test/SettingsMigrationTests.cs b/src/AudioBand.Test/SettingsMigrationTests.cs deleted file mode 100644 index e9c82729..00000000 --- a/src/AudioBand.Test/SettingsMigrationTests.cs +++ /dev/null @@ -1,505 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Media; -using AudioBand.Models; -using AudioBand.Settings; -using AudioBand.Settings.Migrations; -using AudioBand.Settings.Models.v3; -using AudioBand.Settings.Models.V1; -using V1Settings = AudioBand.Settings.Models.V1.AudioBandSettings; -using V2Settings = AudioBand.Settings.Models.V2.Settings; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Nett; -using AudioSourceSetting = AudioBand.Settings.Models.V1.AudioSourceSetting; - -namespace AudioBand.Test -{ - [TestClass] - public class SettingsMigrationTests - { - [TestMethod] - public void MigrateV1ToV2_Main() - { - var v1 = new V1Settings() - { - AudioSource = "test" - }; - - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.Version, "2"); - Assert.AreEqual(v2.AudioSource, "test"); - } - - [TestMethod] - public void MigrateV1ToV2_AlbumArtPopup() - { - var setting = new AlbumArtPopupAppearance - { - Width = 100, - Height = 50, - IsVisible = true, - Margin = 100, - XOffset = 50 - }; - - var v1 = new V1Settings() - { - AlbumArtPopupAppearance = setting, - }; - - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.AlbumArtPopupSettings.Width, setting.Width); - Assert.AreEqual(v2.AlbumArtPopupSettings.Height, setting.Height); - Assert.AreEqual(v2.AlbumArtPopupSettings.IsVisible, setting.IsVisible); - Assert.AreEqual(v2.AlbumArtPopupSettings.Margin, setting.Margin); - Assert.AreEqual(v2.AlbumArtPopupSettings.XPosition, setting.XOffset); - } - - [TestMethod] - public void MigrateV1ToV2_AlbumArt() - { - var setting = new AlbumArtAppearance - { - Width = 10, - Height = 10, - IsVisible = true, - XPosition = 10, - YPosition = 10, - PlaceholderPath = "test" - }; - - var v1 = new V1Settings - { - AlbumArtAppearance = setting - }; - - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.AlbumArtSettings.Width, setting.Width); - Assert.AreEqual(v2.AlbumArtSettings.Height, setting.Height); - Assert.AreEqual(v2.AlbumArtSettings.IsVisible, setting.IsVisible); - Assert.AreEqual(v2.AlbumArtSettings.XPosition, setting.XPosition); - Assert.AreEqual(v2.AlbumArtSettings.YPosition, setting.YPosition); - Assert.AreEqual(v2.AlbumArtSettings.PlaceholderPath, setting.PlaceholderPath); - } - - [TestMethod] - public void MigrateV1ToV2_Audioband() - { - var setting = new AudioBandAppearance - { - Height = 20, - Width = 50, - }; - - var v1 = new V1Settings - { - AudioBandAppearance = setting - }; - - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.AudioBandSettings.Width, setting.Width); - Assert.AreEqual(v2.AudioBandSettings.Height, setting.Height); - } - - [TestMethod] - public void MigrateV1ToV2_NextSong() - { - var setting = new NextSongButtonAppearance - { - Width = 20, - Height = 20, - XPosition = 10, - IsVisible = false, - YPosition = 30, - ImagePath = "path" - }; - - var v1 = new V1Settings - { - NextSongButtonAppearance = setting - }; - - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.NextButtonSettings.Width, setting.Width); - Assert.AreEqual(v2.NextButtonSettings.Height, setting.Height); - Assert.AreEqual(v2.NextButtonSettings.IsVisible, setting.IsVisible); - Assert.AreEqual(v2.NextButtonSettings.XPosition, setting.XPosition); - Assert.AreEqual(v2.NextButtonSettings.YPosition, setting.YPosition); - Assert.AreEqual(v2.NextButtonSettings.ImagePath, setting.ImagePath); - } - - [TestMethod] - public void MigrateV1ToV2_AudioSourceSettings() - { - var setting1 = new AudioSourceSettingsCollection - { - Name = "test", - Settings = new List {new AudioSourceSetting {Name = "key1", Value = "val1"}} - }; - - var setting2 = new AudioSourceSettingsCollection - { - Name = "test2", - Settings = new List { new AudioSourceSetting { Name = "key2", Value = "val2" } } - }; - - var settings = new List {setting1,setting2}; - var v1 = new V1Settings - { - AudioSourceSettings = settings - }; - - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.AudioSourceSettings.Count, settings.Count); - Assert.AreEqual(v2.AudioSourceSettings[0].AudioSourceName, setting1.Name); - Assert.AreEqual(v2.AudioSourceSettings[0].Settings.Count, setting1.Settings.Count); - Assert.AreEqual(v2.AudioSourceSettings[0].Settings[0].Name, setting1.Settings[0].Name); - Assert.AreEqual(v2.AudioSourceSettings[0].Settings[0].Value, setting1.Settings[0].Value); - - Assert.AreEqual(v2.AudioSourceSettings[1].AudioSourceName, setting2.Name); - Assert.AreEqual(v2.AudioSourceSettings[1].Settings.Count, setting2.Settings.Count); - Assert.AreEqual(v2.AudioSourceSettings[1].Settings[0].Name, setting2.Settings[0].Name); - Assert.AreEqual(v2.AudioSourceSettings[1].Settings[0].Value, setting2.Settings[0].Value); - } - - [TestMethod] - public void MigrateV1ToV2_PlayPauseButton() - { - var setting = new PlayPauseButtonAppearance - { - Width = 1, - Height = 2, - XPosition = 3, - IsVisible = true, - YPosition = 4, - PauseButtonImagePath = "pause", - PlayButtonImagePath = "play" - }; - - var v1 = new V1Settings {PlayPauseButtonAppearance = setting}; - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.PlayPauseButtonSettings.Width, setting.Width); - Assert.AreEqual(v2.PlayPauseButtonSettings.Height, setting.Height); - Assert.AreEqual(v2.PlayPauseButtonSettings.XPosition, setting.XPosition); - Assert.AreEqual(v2.PlayPauseButtonSettings.YPosition, setting.YPosition); - Assert.AreEqual(v2.PlayPauseButtonSettings.IsVisible, setting.IsVisible); - Assert.AreEqual(v2.PlayPauseButtonSettings.PauseButtonImagePath, setting.PauseButtonImagePath); - Assert.AreEqual(v2.PlayPauseButtonSettings.PlayButtonImagePath, setting.PlayButtonImagePath); - } - - [TestMethod] - public void MigrateV1ToV2_PreviousButton() - { - var setting = new PreviousSongButtonAppearance - { - Width = 1, - Height = 2, - XPosition = 3, - IsVisible = true, - YPosition = 4, - ImagePath = "path" - }; - - var v1 = new V1Settings {PreviousSongButtonAppearance = setting}; - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.PreviousButtonSettings.Height, setting.Height); - Assert.AreEqual(v2.PreviousButtonSettings.Width, setting.Width); - Assert.AreEqual(v2.PreviousButtonSettings.XPosition, setting.XPosition); - Assert.AreEqual(v2.PreviousButtonSettings.YPosition, setting.YPosition); - Assert.AreEqual(v2.PreviousButtonSettings.IsVisible, setting.IsVisible); - Assert.AreEqual(v2.PreviousButtonSettings.ImagePath, setting.ImagePath); - } - - [TestMethod] - public void MigrateV1ToV2_ProgressBar() - { - var setting = new ProgressBarAppearance - { - Height = 1, - Width = 2, - XPosition = 3, - IsVisible = false, - YPosition = 5, - BackgroundColor = Colors.White, - ForegroundColor = Colors.Red, - }; - - var v1 = new V1Settings {ProgressBarAppearance = setting}; - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.ProgressBarSettings.Width, setting.Width); - Assert.AreEqual(v2.ProgressBarSettings.Height, setting.Height); - Assert.AreEqual(v2.ProgressBarSettings.XPosition, setting.XPosition); - Assert.AreEqual(v2.ProgressBarSettings.YPosition, setting.YPosition); - Assert.AreEqual(v2.ProgressBarSettings.IsVisible, setting.IsVisible); - Assert.AreEqual(v2.ProgressBarSettings.BackgroundColor, setting.BackgroundColor); - Assert.AreEqual(v2.ProgressBarSettings.ForegroundColor, setting.ForegroundColor); - } - - [TestMethod] - public void MigrateV1ToV2_CustomText() - { - var text1 = new TextAppearance - { - Color = Colors.Red, - Width = 1, - Height = 2, - Name = "test", - XPosition = 4, - IsVisible = true, - YPosition = 10, - ScrollSpeed = 20, - FontSize = 1f, - FontFamily = "family", - Alignment = CustomLabel.TextAlignment.Center, - FormatString = "123", - }; - - var texts = new List() {text1}; - var v1 = new V1Settings {TextAppearances = texts}; - var v2 = Migration.MigrateSettings(v1, "0.1", "2"); - - Assert.AreEqual(v2.CustomLabelSettings.Count, texts.Count); - Assert.AreEqual(v2.CustomLabelSettings[0].Color, text1.Color); - Assert.AreEqual(v2.CustomLabelSettings[0].Width, text1.Width); - Assert.AreEqual(v2.CustomLabelSettings[0].Height, text1.Height); - Assert.AreEqual(v2.CustomLabelSettings[0].Name, text1.Name); - Assert.AreEqual(v2.CustomLabelSettings[0].XPosition, text1.XPosition); - Assert.AreEqual(v2.CustomLabelSettings[0].IsVisible, text1.IsVisible); - Assert.AreEqual(v2.CustomLabelSettings[0].YPosition, text1.YPosition); - Assert.AreEqual(v2.CustomLabelSettings[0].ScrollSpeed, text1.ScrollSpeed); - Assert.AreEqual(v2.CustomLabelSettings[0].FontSize, text1.FontSize); - Assert.AreEqual(v2.CustomLabelSettings[0].FontFamily, text1.FontFamily); - Assert.AreEqual(v2.CustomLabelSettings[0].Alignment, text1.Alignment); - Assert.AreEqual(v2.CustomLabelSettings[0].FormatString, text1.FormatString); - } - - [TestMethod] - public void MigrateV2ToV3() - { - string settingsFile = @"Version = ""2"" -AudioSource = ""Spotify"" - -[AudioBandSettings] -Width = 500 -Height = 30 - -[PreviousButtonSettings] -ImagePath = """" -IsVisible = false -Width = 73 -Height = 12 -XPosition = 30 -YPosition = 15 - -[PlayPauseButtonSettings] -PlayButtonImagePath = """" -PauseButtonImagePath = """" -XPosition = 109 -YPosition = 15 -Width = 73 -Height = 12 -IsVisible = false - -[NextButtonSettings] -ImagePath = """" -IsVisible = false -Width = 73 -Height = 12 -XPosition = 176 -YPosition = 15 - -[ProgressBarSettings] -ForegroundColor = ""#32ABCD"" -BackgroundColor = ""#232323"" -IsVisible = true -XPosition = 330 -YPosition = 24 -Width = 130 -Height = 3 - -[AlbumArtSettings] -IsVisible = true -Width = 30 -Height = 30 -XPosition = 260 -YPosition = 0 -PlaceholderPath = """" - -[AlbumArtPopupSettings] -IsVisible = true -Width = 300 -Height = 300 -XPosition = 125 -Margin = 4 - -[[CustomLabelSettings]] -IsVisible = true -Width = 200 -Height = 20 -XPosition = 295 -YPosition = 0 -FontFamily = ""Segoe UI"" -FontSize = 11.0 -Color = ""#FFFFFF"" -FormatString = ""{*song}"" -Alignment = ""Center"" -Name = ""Song"" -ScrollSpeed = 50 -[[CustomLabelSettings]] -IsVisible = true -Width = 34 -Height = 12 -XPosition = 292 -YPosition = 17 -FontFamily = ""Segoe UI"" -FontSize = 8.0 -Color = ""#C3C3C3"" -FormatString = ""{time}"" -Alignment = ""Left"" -Name = ""Time"" -ScrollSpeed = 50 -[[CustomLabelSettings]] -IsVisible = true -Width = 35 -Height = 12 -XPosition = 460 -YPosition = 17 -FontFamily = ""Segoe UI"" -FontSize = 8.0 -Color = ""#C3C3C3"" -FormatString = ""{length}"" -Alignment = ""Right"" -Name = ""Song Length"" -ScrollSpeed = 50 -[[CustomLabelSettings]] -IsVisible = true -Width = 260 -Height = 15 -XPosition = 0 -YPosition = 0 -FontFamily = ""Segoe UI"" -FontSize = 9.0 -Color = ""White"" -FormatString = ""{artist}"" -Alignment = ""Right"" -Name = ""Artist"" -ScrollSpeed = 50 -[[CustomLabelSettings]] -IsVisible = true -Width = 260 -Height = 15 -XPosition = 0 -YPosition = 15 -FontFamily = ""Segoe UI"" -FontSize = 9.0 -Color = ""#AFAFAF"" -FormatString = ""{album}"" -Alignment = ""Right"" -Name = ""Album"" -ScrollSpeed = 50 - -[[AudioSourceSettings]] -AudioSourceName = ""Spotify"" - -[[AudioSourceSettings.Settings]] -Name = ""Spotify Client ID"" -Value = ""id"" -[[AudioSourceSettings.Settings]] -Name = ""Spotify Client secret"" -Value = ""secret"" -"; - var settings = TomlSettings.Create(cfg => - { - cfg.ConfigureType(type => type.WithConversionFor(convert => convert - .ToToml(SerializationConversions.ColorToString) - .FromToml(tomlString => SerializationConversions.StringToColor(tomlString.Value)))); - cfg.ConfigureType(type => type.WithConversionFor(convert => convert - .ToToml(SerializationConversions.EnumToString) - .FromToml(str => SerializationConversions.StringToEnum(str.Value)))); - cfg.ConfigureType(type => type.WithConversionFor(c => c - .FromToml(tml => tml.Value))); - }); - - var v2 = Toml.ReadString(settingsFile, settings); - var v3 = Migration.MigrateSettings(v2, "2", "3"); - - Assert.AreEqual("3", v3.Version); - Assert.AreEqual(v2.AudioSource, v3.AudioSource); - - Assert.AreEqual(v2.AlbumArtPopupSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.Width); - Assert.AreEqual(v2.AlbumArtPopupSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.Height); - Assert.AreEqual(v2.AlbumArtPopupSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.IsVisible); - Assert.AreEqual(v2.AlbumArtPopupSettings.Margin, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.Margin); - Assert.AreEqual(v2.AlbumArtPopupSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtPopupSettings.XPosition); - - Assert.AreEqual(v2.AlbumArtSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.Width); - Assert.AreEqual(v2.AlbumArtSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.Height); - Assert.AreEqual(v2.AlbumArtSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.IsVisible); - Assert.AreEqual(v2.AlbumArtSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.XPosition); - Assert.AreEqual(v2.AlbumArtSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.YPosition); - Assert.AreEqual(v2.AlbumArtSettings.PlaceholderPath, v3.Profiles[SettingsV3.DefaultProfileName].AlbumArtSettings.PlaceholderPath); - - Assert.AreEqual(v2.AudioBandSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].AudioBandSettings.Width); - Assert.AreEqual(v2.AudioBandSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].AudioBandSettings.Height); - - Assert.AreEqual(v2.NextButtonSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.Width); - Assert.AreEqual(v2.NextButtonSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.Height); - Assert.AreEqual(v2.NextButtonSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.IsVisible); - Assert.AreEqual(v2.NextButtonSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.XPosition); - Assert.AreEqual(v2.NextButtonSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.YPosition); - Assert.AreEqual(v2.NextButtonSettings.ImagePath, v3.Profiles[SettingsV3.DefaultProfileName].NextButtonSettings.Content.ImagePath); - - Assert.AreEqual(v2.AudioSourceSettings.Count, v3.AudioSourceSettings.Count); - Assert.AreEqual(v2.AudioSourceSettings[0].AudioSourceName, v3.AudioSourceSettings[0].AudioSourceName); - Assert.AreEqual(v2.AudioSourceSettings[0].Settings.Count, v3.AudioSourceSettings[0].Settings.Count); - Assert.AreEqual(v2.AudioSourceSettings[0].Settings[0].Name, v3.AudioSourceSettings[0].Settings[0].Name); - Assert.AreEqual(v2.AudioSourceSettings[0].Settings[0].Value, v3.AudioSourceSettings[0].Settings[0].Value); - - Assert.AreEqual(v2.PlayPauseButtonSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.Width); - Assert.AreEqual(v2.PlayPauseButtonSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.Height); - Assert.AreEqual(v2.PlayPauseButtonSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.XPosition); - Assert.AreEqual(v2.PlayPauseButtonSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.YPosition); - Assert.AreEqual(v2.PlayPauseButtonSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.IsVisible); - Assert.AreEqual(v2.PlayPauseButtonSettings.PauseButtonImagePath, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.PauseContent.ImagePath); - Assert.AreEqual(v2.PlayPauseButtonSettings.PlayButtonImagePath, v3.Profiles[SettingsV3.DefaultProfileName].PlayPauseButtonSettings.PlayContent.ImagePath); - - Assert.AreEqual(v2.PreviousButtonSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.Height); - Assert.AreEqual(v2.PreviousButtonSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.Width); - Assert.AreEqual(v2.PreviousButtonSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.XPosition); - Assert.AreEqual(v2.PreviousButtonSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.YPosition); - Assert.AreEqual(v2.PreviousButtonSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.IsVisible); - Assert.AreEqual(v2.PreviousButtonSettings.ImagePath, v3.Profiles[SettingsV3.DefaultProfileName].PreviousButtonSettings.Content.ImagePath); - - Assert.AreEqual(v2.ProgressBarSettings.Width, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.Width); - Assert.AreEqual(v2.ProgressBarSettings.Height, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.Height); - Assert.AreEqual(v2.ProgressBarSettings.XPosition, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.XPosition); - Assert.AreEqual(v2.ProgressBarSettings.YPosition, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.YPosition); - Assert.AreEqual(v2.ProgressBarSettings.IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.IsVisible); - Assert.AreEqual(v2.ProgressBarSettings.BackgroundColor, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.BackgroundColor); - Assert.AreEqual(v2.ProgressBarSettings.ForegroundColor, v3.Profiles[SettingsV3.DefaultProfileName].ProgressBarSettings.ForegroundColor); - - Assert.AreEqual(v2.CustomLabelSettings.Count, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings.Count); - Assert.AreEqual(v2.CustomLabelSettings[0].Color, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Color); - Assert.AreEqual(v2.CustomLabelSettings[0].Width, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Width); - Assert.AreEqual(v2.CustomLabelSettings[0].Height, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Height); - Assert.AreEqual(v2.CustomLabelSettings[0].Name, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Name); - Assert.AreEqual(v2.CustomLabelSettings[0].XPosition, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].XPosition); - Assert.AreEqual(v2.CustomLabelSettings[0].IsVisible, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].IsVisible); - Assert.AreEqual(v2.CustomLabelSettings[0].YPosition, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].YPosition); - Assert.AreEqual(v2.CustomLabelSettings[0].ScrollSpeed, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].ScrollSpeed); - Assert.AreEqual(v2.CustomLabelSettings[0].FontSize, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].FontSize); - Assert.AreEqual(v2.CustomLabelSettings[0].FontFamily, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].FontFamily); - Assert.AreEqual(v2.CustomLabelSettings[0].Alignment, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].Alignment); - Assert.AreEqual(v2.CustomLabelSettings[0].FormatString, v3.Profiles[SettingsV3.DefaultProfileName].CustomLabelSettings[0].FormatString); - } - } -} diff --git a/src/AudioBand.Test/TextFormatting/CustomTextParsingTests.cs b/src/AudioBand.Test/TextFormatting/CustomTextParsingTests.cs new file mode 100644 index 00000000..be90a96d --- /dev/null +++ b/src/AudioBand.Test/TextFormatting/CustomTextParsingTests.cs @@ -0,0 +1,276 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows.Media; +using AudioBand.AudioSource; +using AudioBand.TextFormatting; +using Moq; +using Xunit; + +namespace AudioBand.Test +{ + public class CustomTextParsingTests + { + [Fact] + public void Parse_NormalTextFormat() + { + var format = "hello"; + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.Equal("hello", segments[0].Text); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Normal)); + } + + [Fact] + public void Parse_EmptyTextFormat_CreatesNoSegments() + { + var format = ""; + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Empty(segments); + } + + [Fact] + public void Parse_SinglePlaceholder_CreatesPlaceholderSegment() + { + var format = "{artist}"; + var artist = "123"; + var session = new Mock(); + session.SetupGet(m => m.SongArtist).Returns(artist); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, session.Object).ToList(); + + Assert.Single(segments); + Assert.Equal(artist, segments[0].Text); + } + + [Fact] + public void Parse_PlaceholderTextWithNormal_CreatesPlaceholderAndNormalSegments() + { + var format = "{artist} song"; + var artist = "123"; + var session = new Mock(); + session.SetupGet(m => m.SongArtist).Returns(artist); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, session.Object).ToList(); + Assert.Equal(2, segments.Count); + + Assert.Equal(artist, segments[0].Text); + + Assert.Equal(" song", segments[1].Text); + Assert.True(segments[1].Flags.HasFlag(FormattedTextFlags.Normal)); + } + + [Fact] + public void Parse_NormalWithPlaceholder_CreatesNormalAndPlaceholderSegments() + { + var format = "by {artist}"; + var artist = "123"; + var session = new Mock(); + session.SetupGet(m => m.SongArtist).Returns(artist); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, session.Object).ToList(); + + Assert.Equal(2, segments.Count); + + Assert.Equal("by ", segments[0].Text); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Normal)); + + Assert.Equal(artist, segments[1].Text); + } + + [Fact] + public void Parse_FormatContainsPlaceholderWithUnclosedBrace_CreatesNormalSegment() + { + var format = "{artist"; + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.Equal("{artist", segments[0].Text); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Normal)); + } + + [Fact] + public void Parse_FormatOnlyClosingBrace_CreatesNormalSegment() + { + var format = "}"; + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.Equal("}", segments[0].Text); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Normal)); + } + + [Fact] + public void Parse_ComplexFormat_CreatesProperSegments() + { + var format = "this is {artist} and "; + var artist = "123"; + var session = new Mock(); + session.SetupGet(m => m.SongArtist).Returns(artist); + var segments = FormattedTextParser + .ParseFormattedString(format, Colors.Black, session.Object).ToList(); + + Assert.Equal(3, segments.Count); + + Assert.Equal("this is ", segments[0].Text); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Normal)); + + Assert.Equal(artist, segments[1].Text); + + Assert.Equal(" and ", segments[2].Text); + Assert.True(segments[2].Flags.HasFlag(FormattedTextFlags.Normal)); + } + + [Fact] + public void Parse_InvalidPlaceholder_CreatesSegmentWithInvalidValue() + { + var format = "{something}"; + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + + Assert.Equal("!Invalid format!", segments[0].Text); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Normal)); + } + + [Fact] + public void Parse_ArtistPlaceholder_SubstitutesText() + { + var format = "{artist}"; + var artist = "123"; + var artist2 = "next"; + var mock = new Mock(); + mock.SetupSequence(m => m.SongArtist).Returns(artist).Returns(artist2); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.Equal(artist, segments[0].Text); + + mock.Raise(m => m.PropertyChanged += null, null, new PropertyChangedEventArgs(nameof(IAudioSession.SongArtist))); + Assert.Equal(artist2, segments[0].Text); + } + + [Fact] + public void Parse_SongPlaceholder_SubstitutesText() + { + var format = "{song}"; + var song = "the song"; + var mock = new Mock(); + mock.SetupGet(m => m.SongName).Returns(song); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.Equal(song, segments[0].Text); + } + + [Fact] + public void Parse_AlbumPlaceholder_SubstitutesText() + { + var format = "{album}"; + var album = "the album"; + var mock = new Mock(); + mock.SetupGet(m => m.AlbumName).Returns(album); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.Equal(album, segments[0].Text); + } + + [Fact] + public void Parse_TimePlaceholder_SubstitutesText() + { + var format = "{time}"; + var time = TimeSpan.FromSeconds(40); + var mock = new Mock(); + mock.SetupGet(m => m.SongProgress).Returns(time); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.Equal("0:40", segments[0].Text); + } + + [Fact] + public void Parse_RemainingTimePlaceholder_SubstitutesText() + { + var format = "{remaining}"; + var time = TimeSpan.FromSeconds(40); + var length = TimeSpan.FromSeconds(60); + var mock = new Mock(); + mock.SetupGet(m => m.SongProgress).Returns(time); + mock.SetupGet(m => m.SongLength).Returns(length); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.Equal("0:20", segments[0].Text); + } + + [Fact] + public void Parse_LengthPlaceholder_SubstitutesText() + { + var format = "{length}"; + var time = TimeSpan.FromSeconds(80); + var mock = new Mock(); + mock.SetupGet(m => m.SongLength).Returns(time); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.Equal("1:20", segments[0].Text); + } + + [Fact] + public void Parse_StyleBold_SegmentContainsBoldFlag() + { + var format = "{*artist}"; + var mock = new Mock(); + var segments = FormattedTextParser.ParseFormattedString(format, Colors.Black, mock.Object).ToList(); + + Assert.Single(segments); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Bold)); + } + + [Fact] + public void Parse_StyleItalic_SegmentContainsItalicFlag() + { + var format = "{&artist}"; + var segments = FormattedTextParser + .ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Italic)); + } + + [Fact] + public void Parse_StyleUnderline_SegmentContainsUnderlineFlag() + { + var format = "{_artist}"; + var segments = FormattedTextParser + .ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Underline)); + } + + [Fact] + public void Parse_StyleWithColor_SegmentContainsColorAndStyle() + { + var format = "{_artist:#ff00ff}"; + var segments = FormattedTextParser + .ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Underline)); + Assert.Equal(Color.FromRgb(255, 0, 255), segments[0].Color); + } + + [Fact] + public void Parse_MultipleStyles_SegmentContainsMatchingStyleFlags() + { + var format = "{*_artist}"; + var segments = FormattedTextParser + .ParseFormattedString(format, Colors.Black, new Mock().Object).ToList(); + + Assert.Single(segments); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Underline)); + Assert.True(segments[0].Flags.HasFlag(FormattedTextFlags.Bold)); + } + } +} diff --git a/src/AudioBand.Test/TextRendererTests.cs b/src/AudioBand.Test/TextRendererTests.cs deleted file mode 100644 index 73383013..00000000 --- a/src/AudioBand.Test/TextRendererTests.cs +++ /dev/null @@ -1,296 +0,0 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Windows.Media; -using AudioBand.TextFormatting; - -namespace AudioBand.Test -{ - [TestClass] - public class TextRendererTests - { - [TestMethod] - public void ParseNormal() - { - var format = "hello"; - var r = new FormattedTextParser(format, Colors.Black); - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual("hello", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Normal)); - } - - [TestMethod] - public void ParseEmpty() - { - var format = ""; - var r = new FormattedTextParser(format, Colors.Black); - - Assert.AreEqual(0, r.TextSegments.Count); - } - - [TestMethod] - public void ParseSinglePlaceholder() - { - var format = "{artist}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - } - - [TestMethod] - public void ParsePlaceholderWithNormal() - { - var format = "{artist} song"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(2, r.TextSegments.Count); - - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - - Assert.AreEqual(" song", r.TextSegments[1].Text); - Assert.IsTrue(r.TextSegments[1].Type.HasFlag(FormattedTextFlags.Normal)); - } - - [TestMethod] - public void ParseSingleNormalWithPlaceholder() - { - var format = "by {artist}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(2, r.TextSegments.Count); - - Assert.AreEqual("by ", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Normal)); - - Assert.AreEqual(artist, r.TextSegments[1].Text); - Assert.IsTrue(r.TextSegments[1].Type.HasFlag(FormattedTextFlags.Artist)); - } - - [TestMethod] - public void ParseUnclosed() - { - var format = "{artist"; - var r = new FormattedTextParser(format, Colors.Black); - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual("{artist", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Normal)); - } - - [TestMethod] - public void ParseOnlyClosing() - { - var format = "}"; - var r = new FormattedTextParser(format, Colors.Black); - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual("}", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Normal)); - } - - [TestMethod] - public void ParseComplex() - { - var format = "this is {artist} and "; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(3, r.TextSegments.Count); - - Assert.AreEqual("this is ", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Normal)); - - Assert.AreEqual(artist, r.TextSegments[1].Text); - Assert.IsTrue(r.TextSegments[1].Type.HasFlag(FormattedTextFlags.Artist)); - - Assert.AreEqual(" and ", r.TextSegments[2].Text); - Assert.IsTrue(r.TextSegments[2].Type.HasFlag(FormattedTextFlags.Normal)); - } - - [TestMethod] - public void ParseInvalidFormat() - { - var format = "{something}"; - var r = new FormattedTextParser(format, Colors.Black); - - Assert.AreEqual(1, r.TextSegments.Count); - - Assert.AreEqual("! invalid format !", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Normal)); - } - - [TestMethod] - public void ParseArtist() - { - var format = "{artist}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - } - - [TestMethod] - public void ParseSong() - { - var format = "{song}"; - var song = "the song"; - var r = new FormattedTextParser(format, Colors.Black) - { - SongName = song - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(song, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Song)); - } - - [TestMethod] - public void ParseAlbum() - { - var format = "{album}"; - var album = "the album"; - var r = new FormattedTextParser(format, Colors.Black) - { - AlbumName = album - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(album, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Album)); - } - - [TestMethod] - public void ParseTime() - { - var format = "{time}"; - var time = TimeSpan.FromSeconds(40); - var r = new FormattedTextParser(format, Colors.Black) - { - SongProgress = time, - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual("0:40", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.CurrentTime)); - } - - [TestMethod] - public void ParseLength() - { - var format = "{length}"; - var time = TimeSpan.FromSeconds(80); - var r = new FormattedTextParser(format, Colors.Black) - { - SongLength = time, - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual("1:20", r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.SongLength)); - } - - [TestMethod] - public void ParseStyleBold() - { - var format = "{*artist}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Bold)); - } - - [TestMethod] - public void ParseStyleItalic() - { - var format = "{&artist}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Italic)); - } - - [TestMethod] - public void ParseStyleUnderline() - { - var format = "{_artist}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Underline)); - } - - [TestMethod] - public void ParseStyleWithColor() - { - var format = "{_artist:#ff00ff}"; - var artist = "123"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist - }; - - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Underline)); - Assert.AreEqual(Color.FromRgb(255, 0, 255), r.TextSegments[0].Color); - } - - [TestMethod] - public void ParseMultipleStyles() - { - var format = "{*_artist}"; - var artist = "test"; - var r = new FormattedTextParser(format, Colors.Black) - { - Artist = artist, - }; - Assert.AreEqual(1, r.TextSegments.Count); - Assert.AreEqual(artist, r.TextSegments[0].Text); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Artist)); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Underline)); - Assert.IsTrue(r.TextSegments[0].Type.HasFlag(FormattedTextFlags.Bold)); - } - } -} diff --git a/src/AudioBand.Test/ValueConveters/PathToImageConverterTests.cs b/src/AudioBand.Test/ValueConveters/PathToImageConverterTests.cs new file mode 100644 index 00000000..88a43bbf --- /dev/null +++ b/src/AudioBand.Test/ValueConveters/PathToImageConverterTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using AudioBand.ValueConverters; +using Xunit; + +namespace AudioBand.Test +{ + public class PathToImageConverterTests + { + private PathToImageSourceConverter _converter = new PathToImageSourceConverter(); + private string _sampleImagePath = Path.GetFullPath("Assets/imgsource.png"); + + [Fact] + void Convert_EmptyPath_ReturnsNull() + { + Assert.Null(_converter.Convert("", typeof(ImageSource), null, CultureInfo.CurrentCulture)); + } + + [Fact] + void Convert_Null_ReturnsNull() + { + Assert.Null(_converter.Convert((object)null, typeof(ImageSource), null, CultureInfo.CurrentCulture)); + } + + [Fact] + void Convert_NoFile_ReturnsNull() + { + Assert.Null(_converter.Convert("nonexistingfile.png", typeof(ImageSource), null, CultureInfo.CurrentCulture)); + } + + [Fact] + void Convert_ValidFile_ReturnsImageSource() + { + var imgSource = _converter.Convert(_sampleImagePath, typeof(ImageSource), null, CultureInfo.CurrentCulture); + + Assert.NotNull(imgSource); + Assert.IsAssignableFrom(imgSource); + } + + [Fact] + void MultiConvert_InvalidFile_UsesFallback() + { + object fallback = new object(); + var imgSource = _converter.Convert(new[] {"invalidfile.png", fallback}, typeof(ImageSource), null, + CultureInfo.CurrentCulture); + + Assert.NotNull(imgSource); + Assert.Equal(fallback, imgSource); + } + } +} diff --git a/src/AudioBand.Test/ViewModelBaseTests.cs b/src/AudioBand.Test/ViewModelBaseTests.cs deleted file mode 100644 index 949b57c1..00000000 --- a/src/AudioBand.Test/ViewModelBaseTests.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Windows.Controls; -using AudioBand.Messages; -using AudioBand.Models; -using AudioBand.ViewModels; -using Castle.DynamicProxy.Generators.Emitters.SimpleAST; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace AudioBand.Test -{ - [TestClass] - public class ViewModelBaseTests - { - [TestMethod] - public void SetPropertyWithChangedFieldCallsPropertyChanged() - { - string propertyName = null; - var vm = new ViewModel(); - vm.PropertyChanged += (o, e) => { propertyName = e.PropertyName; }; - vm._field = 0; - vm.Field = 10; - - Assert.AreEqual(nameof(ViewModel.Field), propertyName); - Assert.AreEqual(10, vm._field); - } - - [TestMethod] - public void SetPropertySameField() - { - int called = 0; - string propertyName = null; - var vm = new ViewModel(); - vm.PropertyChanged += (o, e) => { propertyName = e.PropertyName; called++; }; - vm._field = 0; - vm.Field = 0; - - Assert.AreEqual(0, called); - Assert.AreEqual(null, propertyName); - Assert.AreEqual(0, vm._field); - } - - [TestMethod] - public void SetPropertyAutomaticallyStartsEdit() - { - var vm = new ViewModel(); - vm._field = 0; - vm.Field = 0; - - Assert.IsFalse(vm.IsEditing); - vm.Field = 1; - Assert.IsTrue(vm.IsEditing); - } - - [TestMethod] - public void SetPropertyWithModelAutomaticallyStartsEdit() - { - var vm = new ViewModelWithModel(); - vm.Field = 0; - - Assert.IsFalse(vm.IsEditing); - vm.Field = 1; - Assert.IsTrue(vm.IsEditing); - } - - [TestMethod] - public void ResetViewModelWithModelStartsEdit() - { - var vm = new ViewModelWithModel(); - vm.Reset(); - - Assert.IsTrue(vm.IsEditing); - } - - [TestMethod] - public void ViewModelWithModelSetupBindingsProperly() - { - var m = new Model(); - var vm = new ViewModelWithModel(m); - - bool raised = false; - vm.PropertyChanged += (sender, e) => - { - if (e.PropertyName == nameof(ViewModelWithModel.Field)) - { - raised = true; - } - }; - - m.ModelField = 10; - - Assert.IsTrue(raised); - } - - [TestMethod] - public void ViewModelWithModelUnbindModelProperly() - { - var m = new Model(); - var vm = new ViewModelWithModel(m); - - bool raised = false; - vm.PropertyChanged += (sender, e) => - { - if (e.PropertyName == nameof(ViewModelWithModel.Field)) - { - raised = true; - } - }; - - vm.Unbind(); - - m.ModelField = 10; - - Assert.IsFalse(raised); - } - - private class ViewModel : ViewModelBase - { - public int _field; - - public int Field - { - get => _field; - set => SetProperty(ref _field, value); - } - } - - private class ViewModelWithModel : ViewModelBase - { - public ViewModelWithModel() : base(new Model()) - { - } - - public ViewModelWithModel(Model m) : base(m) - { - } - - [PropertyChangeBinding(nameof(ViewModelBaseTests.Model.ModelField))] - public int Field - { - get => Model.ModelField; - set => SetProperty(nameof(ViewModelBaseTests.Model.ModelField), value); - } - - public void Unbind() - { - UnbindModel(Model); - } - } - - private class Model : ModelBase - { - private int _field = 0; - - public int ModelField - { - get => _field; - set => SetProperty(ref _field, value); - } - } - } -} diff --git a/src/AudioBand.Test/AlbumArtPopupViewModelTests.cs b/src/AudioBand.Test/ViewModels/AlbumArtPopupViewModelTests.cs similarity index 52% rename from src/AudioBand.Test/AlbumArtPopupViewModelTests.cs rename to src/AudioBand.Test/ViewModels/AlbumArtPopupViewModelTests.cs index 1ec831e5..a4064cdd 100644 --- a/src/AudioBand.Test/AlbumArtPopupViewModelTests.cs +++ b/src/AudioBand.Test/ViewModels/AlbumArtPopupViewModelTests.cs @@ -1,46 +1,41 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using AudioBand.Messages; using AudioBand.Models; using AudioBand.Settings; using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Xunit; namespace AudioBand.Test { - [TestClass] public class AlbumArtPopupViewModelTests { private Mock _appSettings; + private Mock _messageBus; - [TestInitialize] - public void TestInit() + public AlbumArtPopupViewModelTests() { _appSettings = new Mock(); + _messageBus = new Mock(); } - [TestMethod] - public void ListensForProfileChangesAndMapsProperly() + [Fact] + public void AlbumArtPopupViewModel_ProfileChangedEvent_ListensToProfileChanges() { var first = new AlbumArtPopup() {Height = 10}; var second = new AlbumArtPopup() {Height = 20}; _appSettings.SetupSequence(m => m.AlbumArtPopup) .Returns(first) + .Returns(second) .Returns(second); - var vm = new AlbumArtPopupViewModel(_appSettings.Object); - bool raise = false; - vm.PropertyChanged += (_, __) => raise = true; - Assert.AreEqual(first.Height, vm.Height); + var vm = new AlbumArtPopupViewModel(_appSettings.Object, _messageBus.Object); + + Assert.Equal(first.Height, vm.Height); _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raise); - Assert.AreEqual(second.Height, vm.Height); + Assert.False(vm.IsEditing); + Assert.Equal(second.Height, vm.Height); } } } diff --git a/src/AudioBand.Test/AlbumArtViewModelTests.cs b/src/AudioBand.Test/ViewModels/AlbumArtViewModelTests.cs similarity index 62% rename from src/AudioBand.Test/AlbumArtViewModelTests.cs rename to src/AudioBand.Test/ViewModels/AlbumArtViewModelTests.cs index 51d405b9..b26e3ca9 100644 --- a/src/AudioBand.Test/AlbumArtViewModelTests.cs +++ b/src/AudioBand.Test/ViewModels/AlbumArtViewModelTests.cs @@ -1,49 +1,46 @@ using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using AudioBand.AudioSource; +using AudioBand.Messages; using AudioBand.Models; using AudioBand.Settings; using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Xunit; namespace AudioBand.Test { - [TestClass] public class AlbumArtViewModelTests { private Mock _appSettings; private Mock _dialog; + private Mock _messageBus; - [TestInitialize] - public void TestInit() + public AlbumArtViewModelTests() { _appSettings = new Mock(); _appSettings.SetupGet(m => m.AlbumArt).Returns(new AlbumArt()); _dialog = new Mock(); + _messageBus = new Mock(); } - [TestMethod] - public void ListensToProfileChanges() + [Fact] + public void AlbumArtViewModel_ProfileChangedEvent_ListensToProfileChanges() { var first = new AlbumArt() {Height = 10}; var second = new AlbumArt() {Height = 20}; _appSettings.SetupSequence(m => m.AlbumArt) .Returns(first) .Returns(second); - var vm = new AlbumArtViewModel(_appSettings.Object, _dialog.Object); + var vm = new AlbumArtViewModel(_appSettings.Object, _dialog.Object, new Mock().Object, _messageBus.Object); bool raised = false; vm.PropertyChanged += (sender, e) => raised = true; - Assert.AreEqual(vm.Height, first.Height); + Assert.Equal(vm.Height, first.Height); _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.Height, vm.Height); + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.Height, vm.Height); } } } diff --git a/src/AudioBand.Test/AudioBandViewModelTests.cs b/src/AudioBand.Test/ViewModels/AudioBandViewModelTests.cs similarity index 57% rename from src/AudioBand.Test/AudioBandViewModelTests.cs rename to src/AudioBand.Test/ViewModels/AudioBandViewModelTests.cs index 6f3adeaf..13cd94f4 100644 --- a/src/AudioBand.Test/AudioBandViewModelTests.cs +++ b/src/AudioBand.Test/ViewModels/AudioBandViewModelTests.cs @@ -1,45 +1,42 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using AudioBand.Messages; using AudioBand.Settings; using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Xunit; namespace AudioBand.Test { - [TestClass] public class AudioBandViewModelTests { private Mock _appSettings; + private Mock _messageBus; - [TestInitialize] - public void TestInit() + public AudioBandViewModelTests() { + _messageBus = new Mock(); _appSettings = new Mock(); } - [TestMethod] - public void AudioBandViewModelListensToProfileChanges() + [Fact] + public void AudioBandViewModel_ProfileChangedEvent_ListensToProfileChanges() { var first = new Models.AudioBand(){Height = 10}; var second = new Models.AudioBand(){Height = 20}; _appSettings.SetupSequence(m => m.AudioBand) .Returns(first) .Returns(second); - var vm = new AudioBandViewModel(_appSettings.Object, new Mock().Object); + var vm = new AudioBandViewModel(_appSettings.Object, new Mock().Object, _messageBus.Object); bool raised = false; vm.PropertyChanged += (_, __) => raised = true; - Assert.AreEqual(first.Height, vm.Height); + Assert.Equal(first.Height, vm.Height); _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - Assert.IsTrue(raised); - Assert.IsFalse(vm.IsEditing); - Assert.AreEqual(second.Height, vm.Height); + Assert.True(raised); + Assert.False(vm.IsEditing); + Assert.Equal(second.Height, vm.Height); } } } diff --git a/src/AudioBand.Test/AudioSourceSettingsCollectionTests.cs b/src/AudioBand.Test/ViewModels/AudioSourceSettingsCollectionTests.cs similarity index 74% rename from src/AudioBand.Test/AudioSourceSettingsCollectionTests.cs rename to src/AudioBand.Test/ViewModels/AudioSourceSettingsCollectionTests.cs index 43afa163..03e69864 100644 --- a/src/AudioBand.Test/AudioSourceSettingsCollectionTests.cs +++ b/src/AudioBand.Test/ViewModels/AudioSourceSettingsCollectionTests.cs @@ -1,31 +1,26 @@ using AudioBand.AudioSource; using AudioBand.Models; using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; +using AudioBand.Messages; +using Xunit; namespace AudioBand.Test { - [TestClass] public class AudioSourceSettingsCollectionTests { private Mock _audioSourceMock; + private Mock _messageBus; - - [TestInitialize] - public void Init() + public AudioSourceSettingsCollectionTests() { _audioSourceMock = new Mock(); + _messageBus = new Mock(); } - [TestMethod] - public void NoMatchingSettings() + [Fact] + public void NoMatchingSettings_CreatesNoChildViewModels() { _audioSourceMock.SetupGet(s => s.Settings).Returns(new List()); var name = "test"; @@ -38,14 +33,14 @@ public void NoMatchingSettings() }; var settings = new AudioSourceSettings { AudioSourceName = name, Settings = keyVals }; - var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings); + var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings, _messageBus.Object); - Assert.AreEqual(0, vm.SettingsList.Count); - Assert.AreEqual(name, vm.AudioSourceName); + Assert.Empty(vm.SettingsList); + Assert.Equal(name, vm.AudioSourceName); } - [TestMethod] - public void MatchingSettingsShouldCreateVmsInOrder() + [Fact] + public void MatchingSettings_ShouldCreateChildViewModelsInOrder() { var setting1 = "Setting1"; var setting2 = "setting2"; @@ -61,7 +56,7 @@ public void MatchingSettingsShouldCreateVmsInOrder() _audioSourceMock.SetupGet(s => s[It.Is(x => x == setting1)]).Returns(val1); _audioSourceMock.SetupGet(s => s[It.Is(x => x == setting2)]).Returns(val2); _audioSourceMock.Setup(s => s.GetSettingType(It.Is(x => x == setting1))).Returns(typeof(string)); - _audioSourceMock.Setup(s => s.GetSettingType(It.Is(x => x == setting2))).Returns(typeof(string)); + _audioSourceMock.Setup(s => s.GetSettingType(It.Is(x => x == setting2))).Returns(typeof(int)); var settingModels = new List { @@ -70,18 +65,17 @@ public void MatchingSettingsShouldCreateVmsInOrder() }; var settings = new AudioSourceSettings { Settings = settingModels }; - var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings); - - Assert.AreEqual(settingModels.Count, vm.SettingsList.Count); - Assert.AreEqual(settingModels[0].Name, vm.SettingsList[0].Name); - Assert.AreEqual(settingModels[1].Name, vm.SettingsList[1].Name); + var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings, _messageBus.Object); - Assert.AreEqual(settingModels[0].Value, vm.SettingsList[0].Value); - Assert.AreEqual(settingModels[1].Value, vm.SettingsList[1].Value); + Assert.Equal(settingModels.Count, vm.SettingsList.Count); + Assert.Equal(settingModels[0].Name, vm.SettingsList[0].Name); + Assert.Equal(settingModels[1].Name, vm.SettingsList[1].Name); + Assert.Equal(settingModels[0].Value, vm.SettingsList[0].Value); + Assert.Equal(settingModels[1].Value, vm.SettingsList[1].Value); } - [TestMethod] - public void AudioSourceSettingUpdatesAreHandled() + [Fact] + public void AudioSourceSettingUpdate_NewValueIsWrittenBackToSettings() { var setting = "setting"; @@ -91,18 +85,19 @@ public void AudioSourceSettingUpdatesAreHandled() { Settings = new List { settingModel } }; - - var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings); - object newSettingValue = 1; _audioSourceMock.SetupGet(s => s[It.Is(x => x == setting)]).Returns(newSettingValue); + + var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings, _messageBus.Object); + _audioSourceMock.Raise(s => s.SettingChanged += null, new SettingChangedEventArgs(setting)); - Assert.AreEqual(settingModel.Value, newSettingValue); + vm.EndEdit(); + Assert.Equal(newSettingValue, settingModel.Value); } - [TestMethod] - public void AudioSourceSettingsCalledInPriority() + [Fact] + public void AudioSourceSettingsUpdated_AudioSourceIsUpdatedInPriority() { var setting1 = new AudioSourceSettingAttribute("test1") { Priority = 10 }; var setting2 = new AudioSourceSettingAttribute("test2") { Priority = 5 }; @@ -126,7 +121,7 @@ public void AudioSourceSettingsCalledInPriority() _audioSourceMock.InSequence(s).SetupSet(source => source[It.Is(x => x == setting1.Name)] = null); _audioSourceMock.InSequence(s).SetupSet(source => source[It.Is(x => x == setting2.Name)] = null); - var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings); + var vm = new AudioSourceSettingsCollectionViewModel(_audioSourceMock.Object, settings, _messageBus.Object); _audioSourceMock.VerifySet(source => source[setting3.Name] = null); _audioSourceMock.VerifySet(source => source[setting1.Name] = null); diff --git a/src/AudioBand.Test/ViewModels/ButtonViewModels.cs b/src/AudioBand.Test/ViewModels/ButtonViewModels.cs new file mode 100644 index 00000000..177e7144 --- /dev/null +++ b/src/AudioBand.Test/ViewModels/ButtonViewModels.cs @@ -0,0 +1,303 @@ +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using AudioBand.AudioSource; +using AudioBand.Messages; +using AudioBand.Models; +using AudioBand.Settings; +using AudioBand.ViewModels; +using Moq; +using Xunit; + +namespace AudioBand.Test +{ + public class ButtonViewModels + { + private Mock _appSettings; + private Mock _dialog; + private Mock _session; + private Mock _messageBus; + + public ButtonViewModels() + { + _appSettings = new Mock(); + _dialog = new Mock(); + _session = new Mock(); + _messageBus = new Mock(); + } + + [Fact] + public void NextButton_ProfilesChanged_ListensforProfileChanges() + { + var first = new NextButton() {Height = 1}; + var second = new NextButton() {Height = 2}; + _appSettings.SetupSequence(m => m.NextButton) + .Returns(first) + .Returns(second); + + var vm = new NextButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + bool raised = false; + vm.PropertyChanged += (_, __) => raised = true; + + Assert.Equal(first.Height, vm.Height); + _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); + + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.Height, vm.Height); + } + + + [Fact] + public async Task NextButton_NextCommandExecuted_CallsNextTrack() + { + _appSettings.SetupGet(m => m.NextButton).Returns(new NextButton()); + var audioSourceMock = new Mock(); + audioSourceMock.Setup(m => m.NextTrackAsync()).Returns(Task.CompletedTask); + _session.SetupGet(m => m.CurrentAudioSource).Returns(audioSourceMock.Object); + var vm = new NextButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + await vm.NextTrackCommand.ExecuteAsync(null); + audioSourceMock.Verify(m => m.NextTrackAsync()); + } + + [Fact] + public void PlayPauseButton_ProfileChanged_ListensForProfileChanges() + { + var first = new PlayPauseButton() {Height = 1}; + var second = new PlayPauseButton() {Height = 2}; + _appSettings.SetupSequence(m => m.PlayPauseButton) + .Returns(first) + .Returns(second); + + var vm = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + bool raised = false; + vm.PropertyChanged += (_, __) => raised = true; + + Assert.Equal(first.Height, vm.Height); + _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); + + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.Height, vm.Height); + } + + [Fact] + public void PlayPauseButton_PropertiesInContentAreChanged_ViewModelIsMarkedAsEditing() + { + _appSettings.SetupGet(m => m.PlayPauseButton).Returns(new PlayPauseButton()); + var viewModel = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + viewModel.PlayContent.Text = ""; + Assert.True(viewModel.PlayContent.IsEditing); + Assert.True(viewModel.IsEditing); + + viewModel.EndEdit(); + Assert.False(viewModel.IsEditing); + Assert.False(viewModel.PlayContent.IsEditing); + + viewModel.PauseContent.Text = ""; + Assert.True(viewModel.IsEditing); + Assert.True(viewModel.PauseContent.IsEditing); + } + + [Fact] + public void PlayPauseButton_AudioSessionPlayStateChanged_ListensToEvent() + { + _appSettings.SetupGet(m => m.PlayPauseButton).Returns(new PlayPauseButton()); + _session.SetupSequence(m => m.IsPlaying).Returns(true).Returns(false); + var viewModel = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + _session.Raise(m => m.PropertyChanged+= null, null, new PropertyChangedEventArgs(nameof(IAudioSession.IsPlaying))); + Assert.True(viewModel.IsPlaying); + Assert.False(viewModel.IsPlayButtonShown); + + _session.Raise(m => m.PropertyChanged += null, null, new PropertyChangedEventArgs(nameof(IAudioSession.IsPlaying))); + Assert.False(viewModel.IsPlaying); + Assert.True(viewModel.IsPlayButtonShown); + } + + [Fact] + public async Task PlayPauseButton_PlayAndPauseCommandExecuted_AudioSourceIsNotified() + { + _appSettings.SetupGet(m => m.PlayPauseButton).Returns(new PlayPauseButton()); + var audioSourceMock = new Mock(); + var isPlayingSequence = new[] {true, false}; + var index = 0; + audioSourceMock.Setup(m => m.PlayTrackAsync()) + .Callback(() => Assert.True(isPlayingSequence[index++])) + .Returns(Task.CompletedTask); + audioSourceMock.Setup(m => m.PauseTrackAsync()) + .Callback(() => Assert.False(isPlayingSequence[index++])) + .Returns(Task.CompletedTask); + + _session.SetupGet(m => m.CurrentAudioSource).Returns(audioSourceMock.Object); + _session.SetupSequence(m => m.IsPlaying).Returns(true).Returns(false); + + var viewModel = new PlayPauseButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + await viewModel.PlayPauseTrackCommand.ExecuteAsync(null); + _session.Raise(m => m.PropertyChanged += null, null, new PropertyChangedEventArgs(nameof(IAudioSession.IsPlaying))); + audioSourceMock.Raise(m => m.IsPlayingChanged += null, null, true); + await viewModel.PlayPauseTrackCommand.ExecuteAsync(null); + } + + [Fact] + public void PreviousButton_ProfileChanged_ListensForProfileChanges() + { + var first = new PreviousButton() { Height = 1 }; + var second = new PreviousButton() { Height = 2 }; + _appSettings.SetupSequence(m => m.PreviousButton) + .Returns(first) + .Returns(second); + + var vm = new PreviousButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + bool raised = false; + vm.PropertyChanged += (_, __) => raised = true; + + Assert.Equal(first.Height, vm.Height); + _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); + + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.Height, vm.Height); + } + + [Fact] + public async Task PreviousButton_PreviousCommand_CallsPreviousTrackOnAudioSource() + { + _appSettings.SetupGet(m => m.PreviousButton).Returns(new PreviousButton()); + var audioSourceMock = new Mock(); + audioSourceMock.Setup(m => m.PreviousTrackAsync()).Returns(Task.CompletedTask); + _session.SetupGet(m => m.CurrentAudioSource).Returns(audioSourceMock.Object); + var vm = new PreviousButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + await vm.PreviousTrackCommand.ExecuteAsync(null); + audioSourceMock.Verify(m => m.PreviousTrackAsync()); + } + + [Fact] + public void RepeatModeButton_ProfileChanged_ListensForProfileChanges() + { + var first = new RepeatModeButton() { Height = 1 }; + var second = new RepeatModeButton() { Height = 2 }; + _appSettings.SetupSequence(m => m.RepeatModeButton) + .Returns(first) + .Returns(second); + + var vm = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + bool raised = false; + vm.PropertyChanged += (_, __) => raised = true; + + Assert.Equal(first.Height, vm.Height); + _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); + + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.Height, vm.Height); + } + + [Fact] + public void RepeatModeButton_ContentPropertiesAreModified_ViewModelIsMarkedAsEditing() + { + _appSettings.SetupGet(m => m.RepeatModeButton).Returns(new RepeatModeButton()); + var viewModel = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + Assert.False(viewModel.RepeatTrackContent.IsEditing); + Assert.False(viewModel.IsEditing); + + viewModel.RepeatTrackContent.Text = "test"; + + Assert.True(viewModel.RepeatTrackContent.IsEditing); + Assert.True(viewModel.IsEditing); + } + + [Fact] + public async Task RepeatModeButton_RepeatCommandExecuted_CyclesThroughRepeatModes() + { + var repeatSequence = new[] {RepeatMode.RepeatContext, RepeatMode.RepeatTrack, RepeatMode.Off}; + var index = 0; + var audiosourceMock = new Mock(); + audiosourceMock.Setup(m => m.SetRepeatModeAsync(It.IsAny())) + .Callback((RepeatMode mode) => Assert.Equal(repeatSequence[index++], mode)) + .Returns(Task.CompletedTask); + _appSettings.SetupGet(m => m.RepeatModeButton).Returns(new RepeatModeButton()); + _session.SetupGet(m => m.CurrentAudioSource).Returns(audiosourceMock.Object); + _session.SetupSequence(m => m.RepeatMode) + .Returns(RepeatMode.RepeatContext) + .Returns(RepeatMode.RepeatTrack) + .Returns(RepeatMode.Off) + ; + + var viewModel = new RepeatModeButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + Assert.Equal(RepeatMode.Off, viewModel.RepeatMode); + await viewModel.CycleRepeatModeCommand.ExecuteAsync(null); + _session.Raise(m => m.PropertyChanged += null, null, new PropertyChangedEventArgs(nameof(IAudioSession.RepeatMode))); + await viewModel.CycleRepeatModeCommand.ExecuteAsync(null); + _session.Raise(m => m.PropertyChanged += null, null, new PropertyChangedEventArgs(nameof(IAudioSession.RepeatMode))); + await viewModel.CycleRepeatModeCommand.ExecuteAsync(null); + } + + [Fact] + public void ShuffleModeButton_ProfileChanged_ListensForProfileChanges() + { + var first = new ShuffleModeButton() { Height = 1 }; + var second = new ShuffleModeButton() { Height = 2 }; + _appSettings.SetupSequence(m => m.ShuffleModeButton) + .Returns(first) + .Returns(second); + + var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + bool raised = false; + vm.PropertyChanged += (_, __) => raised = true; + + Assert.Equal(first.Height, vm.Height); + _appSettings.Raise(m => m.ProfileChanged += null, EventArgs.Empty); + + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.Height, vm.Height); + } + + [Fact] + public void ShuffleModeButton_ContentIsEdited_ViewModelIsMarkedAsEditing() + { + _appSettings.SetupGet(m => m.ShuffleModeButton).Returns(new ShuffleModeButton()); + var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + + vm.ShuffleOnContent.Text = "A"; + Assert.True(vm.ShuffleOnContent.IsEditing); + Assert.True(vm.IsEditing); + + vm.EndEdit(); + Assert.False(vm.ShuffleOnContent.IsEditing); + Assert.False(vm.IsEditing); + + vm.ShuffleOffContent.Text = "..."; + Assert.True(vm.ShuffleOffContent.IsEditing); + Assert.True(vm.IsEditing); + } + + [Fact] + public async Task ShuffleModeButton_ShuffleCommandExecuted_TogglesShuffle() + { + _appSettings.SetupGet(m => m.ShuffleModeButton).Returns(new ShuffleModeButton()); + var vm = new ShuffleModeButtonViewModel(_appSettings.Object, _dialog.Object, _session.Object, _messageBus.Object); + var audioSourceMock = new Mock(); + _session.SetupGet(m => m.CurrentAudioSource).Returns(audioSourceMock.Object); + _session.SetupSequence(m => m.IsShuffleOn) + .Returns(true) + .Returns(false); + + var sequence = new[] {true, false}; + var index = 0; + audioSourceMock.Setup(m => m.SetShuffleAsync(It.IsAny())) + .Callback((bool shuffle) => Assert.Equal(sequence[index++], shuffle)) + .Returns(Task.CompletedTask); + + await vm.ToggleShuffleCommand.ExecuteAsync(null); + _session.Raise(m => m.PropertyChanged += null, null, new PropertyChangedEventArgs(nameof(IAudioSession.IsShuffleOn))); + await vm.ToggleShuffleCommand.ExecuteAsync(null); + } + } +} diff --git a/src/AudioBand.Test/ViewModels/CustomLabelViewModelTests.cs b/src/AudioBand.Test/ViewModels/CustomLabelViewModelTests.cs new file mode 100644 index 00000000..396aef52 --- /dev/null +++ b/src/AudioBand.Test/ViewModels/CustomLabelViewModelTests.cs @@ -0,0 +1,77 @@ +using System.Linq; +using System.Windows.Media; +using AudioBand.AudioSource; +using AudioBand.Messages; +using AudioBand.Models; +using AudioBand.ViewModels; +using Moq; +using Xunit; + +namespace AudioBand.Test +{ + public class CustomLabelViewModelTests + { + private Mock _dialogMock; + private Mock _messageBusMock; + private Mock _sessionMock; + + public CustomLabelViewModelTests() + { + _dialogMock = new Mock(); + _messageBusMock = new Mock(); + _sessionMock = new Mock(); + } + + [Fact] + void CustomLabel_TextFormatStringChanged_TextSegmentsMatch() + { + var songname = "song"; + var artist = "artist"; + var model = new CustomLabel { FormatString = "first format" }; + _sessionMock.SetupGet(m => m.SongName).Returns(songname); + _sessionMock.SetupGet(m => m.SongArtist).Returns(artist); + var vm = new CustomLabelViewModel(model, _dialogMock.Object, _sessionMock.Object, _messageBusMock.Object); + + var firstSegment = "second format with"; + var secondSegment = "{artist}"; + var thirdSegment = "and"; + var forthSegment = "{song}"; + vm.FormatString = firstSegment + secondSegment + thirdSegment + forthSegment; + + var segments = vm.TextSegments.ToList(); + Assert.Equal(4, segments.Count); + Assert.Equal(firstSegment, segments[0].Text); + Assert.Equal(artist, segments[1].Text); + Assert.Equal(thirdSegment, segments[2].Text); + Assert.Equal(songname, segments[3].Text); + } + + [Fact] + void CustomLabel_TextFormatStringChangedThenCanceled_CorrectTextSegments() + { + var songname = "song"; + var model = new CustomLabel {FormatString = "text format {song}"}; + _sessionMock.SetupGet(m => m.SongName).Returns(songname); + var vm = new CustomLabelViewModel(model, _dialogMock.Object, _sessionMock.Object, _messageBusMock.Object); + + Assert.Equal(2, vm.TextSegments.Count()); + vm.FormatString = "new format string"; + vm.CancelEdit(); + + Assert.Equal(2, vm.TextSegments.Count()); + Assert.Equal(songname, vm.TextSegments.ToList()[1].Text); + } + + [Fact] + void CustomLabel_ColorChangedThenCanceled_TextSegmentsHaveCorrectColor() + { + var model = new CustomLabel { FormatString = "text format {song}", Color = Colors.Blue }; + var vm = new CustomLabelViewModel(model, _dialogMock.Object, _sessionMock.Object, _messageBusMock.Object); + + vm.Color = Colors.Black; + vm.CancelEdit(); + + Assert.All(vm.TextSegments, segment => Assert.Equal(Colors.Blue, segment.Color)); + } + } +} diff --git a/src/AudioBand.Test/CustomLabelsViewModelTests.cs b/src/AudioBand.Test/ViewModels/CustomLabelsViewModelTests.cs similarity index 65% rename from src/AudioBand.Test/CustomLabelsViewModelTests.cs rename to src/AudioBand.Test/ViewModels/CustomLabelsViewModelTests.cs index 502b65b1..2dafa58d 100644 --- a/src/AudioBand.Test/CustomLabelsViewModelTests.cs +++ b/src/AudioBand.Test/ViewModels/CustomLabelsViewModelTests.cs @@ -1,103 +1,104 @@ using System; -using System.Text; using System.Collections.Generic; -using System.Threading.Tasks; using AudioBand.AudioSource; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using AudioBand.Messages; using AudioBand.ViewModels; using AudioBand.Models; using Moq; using AudioBand.Settings; +using Xunit; namespace AudioBand.Test { /// /// Summary description for CustomLabelsViewModel /// - [TestClass] public class CustomLabelsViewModelTests { private Mock _dialogMock; private Mock _appSettingsMock; + private Mock _sessionMock; + private Mock _messageBus; private CustomLabel _label; private CustomLabelsViewModel _viewModel; - [TestInitialize] - public void Init() + public CustomLabelsViewModelTests() { _dialogMock = new Mock(); _appSettingsMock = new Mock(); _appSettingsMock.Setup(x => x.CustomLabels).Returns(new List()); _label = new CustomLabel(); - _viewModel = new CustomLabelsViewModel(_appSettingsMock.Object, _dialogMock.Object); + _sessionMock = new Mock(); + _messageBus = new Mock(); + _viewModel = new CustomLabelsViewModel(_appSettingsMock.Object, _dialogMock.Object, _sessionMock.Object, _messageBus.Object); } - [TestMethod] - public void AddLabel() + [Fact] + public void AddLabel_CreatesNewViewModel() { _viewModel.AddLabelCommand.Execute(null); - Assert.AreEqual(1, _viewModel.CustomLabels.Count); + Assert.Single(_viewModel.CustomLabels); } - [TestMethod] - public void RemoveLabel_confirm() + [Fact] + public void RemoveLabel_DialogShownAndConfirmed_RemovesCorrectLabel() { _dialogMock.Setup(o => o.ShowConfirmationDialog(It.IsAny(), It.IsAny())).Returns(true); _viewModel.AddLabelCommand.Execute(null); var newLabel = _viewModel.CustomLabels[0]; _viewModel.RemoveLabelCommand.Execute(newLabel); - Assert.AreEqual(0, _viewModel.CustomLabels.Count); + Assert.Empty(_viewModel.CustomLabels); _dialogMock.Verify(o => o.ShowConfirmationDialog( It.Is(type => type == ConfirmationDialogType.DeleteLabel), It.Is(data => data.Length == 1)), Times.Once); } - [TestMethod] - public void RemoveLabel_deny() + [Fact] + public void RemoveLabel_DialogShownAndCanceled_DoesNotRemoveLabel() { _dialogMock.Setup(o => o.ShowConfirmationDialog(It.IsAny(), It.IsAny())).Returns(false); _viewModel.AddLabelCommand.Execute(null); var newLabel = _viewModel.CustomLabels[0]; _viewModel.RemoveLabelCommand.Execute(newLabel); - Assert.AreEqual(1, _viewModel.CustomLabels.Count); + Assert.Single(_viewModel.CustomLabels); _dialogMock.Verify(o => o.ShowConfirmationDialog( It.Is(type => type == ConfirmationDialogType.DeleteLabel), It.Is(data => data.Length == 1)), Times.Once); } - [TestMethod] - public void AddLabel_ThenCancel() + [Fact] + public void AddLabel_CancelMessageIsPublished_NewLabelIsRemoved() { _viewModel.BeginEdit(); _viewModel.AddLabelCommand.Execute(null); var newLabel = _viewModel.CustomLabels[0]; _viewModel.CancelEdit(); - Assert.AreEqual(0, _viewModel.CustomLabels.Count); + Assert.Empty(_viewModel.CustomLabels); } - [TestMethod] - public void RemoveLabel_ThenCancel() + [Fact] + public void RemoveLabel_CancelMessageIsPublished_DeletedLabelIsAddedBack() { _appSettingsMock.SetupGet(x => x.CustomLabels).Returns(new List { new CustomLabel() }); _dialogMock.Setup(o => o.ShowConfirmationDialog(It.IsAny(), It.IsAny())).Returns(true); - _viewModel = new CustomLabelsViewModel(_appSettingsMock.Object, _dialogMock.Object); + _viewModel = new CustomLabelsViewModel(_appSettingsMock.Object, _dialogMock.Object, _sessionMock.Object, _messageBus.Object); _viewModel.BeginEdit(); var label = _viewModel.CustomLabels[0]; _viewModel.RemoveLabelCommand.Execute(label); _viewModel.CancelEdit(); - Assert.AreEqual(1, _viewModel.CustomLabels.Count); - Assert.AreEqual(label, _viewModel.CustomLabels[0]); + Assert.Single(_viewModel.CustomLabels); + Assert.Equal(label, _viewModel.CustomLabels[0]); } - [TestMethod] - public void AddRemoveLabel_ThenCancel() + [Fact] + public void AddRemoveLabel_CancelMessageIsPublished_NoChanges() { _viewModel.BeginEdit(); _dialogMock.Setup(o => o.ShowConfirmationDialog(It.IsAny())).Returns(true); @@ -106,38 +107,35 @@ public void AddRemoveLabel_ThenCancel() _viewModel.RemoveLabelCommand.Execute(newLabel); _viewModel.CancelEdit(); - Assert.AreEqual(0, _viewModel.CustomLabels.Count); + Assert.Empty(_viewModel.CustomLabels); } - [TestMethod, Ignore("Unable to setup sequence")] - public void ProfileChangeRemovesAllLabelsAndAddsNewOnes() + [Fact(Skip = "Unable to setup sequence")] + public void ProfileChanged_RemovesAllLabelsAndAddsNewOnes() { var settingsMock = new Mock(); settingsMock.SetupSequence(m => m.CustomLabels) .Returns(new List { new CustomLabel { Name = "test" } }) .Returns(new List { new CustomLabel { Name = "second" } }); - var vm = new CustomLabelsViewModel(settingsMock.Object, new Mock().Object); - Assert.AreEqual(1, vm.CustomLabels.Count); - Assert.AreEqual("test", vm.CustomLabels[0].Name); + var vm = new CustomLabelsViewModel(settingsMock.Object, new Mock().Object, _sessionMock.Object, _messageBus.Object); + Assert.Single(vm.CustomLabels); + Assert.Equal("test", vm.CustomLabels[0].Name); _appSettingsMock.Raise(m => m.ProfileChanged += null, null, EventArgs.Empty); - Assert.AreEqual("second", vm.CustomLabels[0].Name); + Assert.Equal("second", vm.CustomLabels[0].Name); } - [TestMethod] - public void ProfileChangeUpdateAudioSources() + [Fact] + public void ProfileChanged_NewLabelsHaveCorrectAudioSessionData() { var settingsMock = new Mock(); settingsMock.SetupSequence(m => m.CustomLabels) .Returns(new List {new CustomLabel()}); - var audioSourceMock = new Mock(); - audioSourceMock.SetupGet(m => m.LastTrackInfo).Returns(new TrackInfoChangedEventArgs()); + _sessionMock.SetupGet(m => m.IsPlaying).Returns(true); - var vm = new CustomLabelsViewModel(settingsMock.Object, new Mock().Object); - vm.AudioSource = audioSourceMock.Object; + var vm = new CustomLabelsViewModel(settingsMock.Object, new Mock().Object, _sessionMock.Object, _messageBus.Object); _appSettingsMock.Raise(m => m.ProfileChanged += null, null, EventArgs.Empty); - audioSourceMock.Raise(m => m.IsPlayingChanged += null, null, true); - Assert.IsTrue(vm.CustomLabels[0].IsPlaying); + Assert.True(vm.CustomLabels[0].IsPlaying); } } } diff --git a/src/AudioBand.Test/ProgressBarViewModelTests.cs b/src/AudioBand.Test/ViewModels/ProgressBarViewModelTests.cs similarity index 61% rename from src/AudioBand.Test/ProgressBarViewModelTests.cs rename to src/AudioBand.Test/ViewModels/ProgressBarViewModelTests.cs index 7d76eead..c0daeb37 100644 --- a/src/AudioBand.Test/ProgressBarViewModelTests.cs +++ b/src/AudioBand.Test/ViewModels/ProgressBarViewModelTests.cs @@ -2,17 +2,18 @@ using AudioBand.Models; using AudioBand.Settings; using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using System.Windows.Media; +using AudioBand.AudioSource; +using AudioBand.Messages; +using Xunit; namespace AudioBand.Test { - [TestClass] public class ProgressBarViewModelTests { - [TestMethod] - public void ListensForProfileChanges() + [Fact] + public void ProgressBarViewModel_ProfileChanged_ListensForProfileChanges() { var settingsMock = new Mock(); @@ -22,16 +23,16 @@ public void ListensForProfileChanges() .Returns(first) .Returns(second); - var vm = new ProgressBarViewModel(settingsMock.Object, new Mock().Object); + var vm = new ProgressBarViewModel(settingsMock.Object, new Mock().Object, new Mock().Object, new Mock().Object); bool raised = false; vm.PropertyChanged += (_, __) => raised = true; - Assert.AreEqual(first.BackgroundColor, vm.BackgroundColor); + Assert.Equal(first.BackgroundColor, vm.BackgroundColor); settingsMock.Raise(m => m.ProfileChanged += null, EventArgs.Empty); - Assert.IsFalse(vm.IsEditing); - Assert.IsTrue(raised); - Assert.AreEqual(second.BackgroundColor, vm.BackgroundColor); + Assert.False(vm.IsEditing); + Assert.True(raised); + Assert.Equal(second.BackgroundColor, vm.BackgroundColor); } } } diff --git a/src/AudioBand.Test/SettingsWindowViewModelTests.cs b/src/AudioBand.Test/ViewModels/SettingsWindowViewModelTests.cs similarity index 65% rename from src/AudioBand.Test/SettingsWindowViewModelTests.cs rename to src/AudioBand.Test/ViewModels/SettingsWindowViewModelTests.cs index 4da78bb7..966ab661 100644 --- a/src/AudioBand.Test/SettingsWindowViewModelTests.cs +++ b/src/AudioBand.Test/ViewModels/SettingsWindowViewModelTests.cs @@ -1,22 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.Remoting; -using System.Text; -using System.Threading.Tasks; -using System.Web.ModelBinding; -using System.Windows.Controls; -using System.Windows.Forms; +using AudioBand.AudioSource; using AudioBand.Messages; using AudioBand.Models; using AudioBand.Settings; using AudioBand.ViewModels; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Xunit; namespace AudioBand.Test { - [TestClass] public class SettingsWindowViewModelTests { private Mock _appSettings; @@ -24,16 +18,15 @@ public class SettingsWindowViewModelTests private Mock _container; private Mock _messageBus; - [TestInitialize] - public void TestSetup() + public SettingsWindowViewModelTests() { _appSettings = new Mock(); _appSettings.SetupGet(m => m.Profiles).Returns(new List()); _appSettings.SetupGet(m => m.CustomLabels).Returns(new List()); _dialog = new Mock(); _container = new Mock(); - _container.SetupGet(m => m.CustomLabelsViewModel).Returns(new CustomLabelsViewModel(_appSettings.Object, _dialog.Object)); _messageBus = new Mock(); + _container.SetupGet(m => m.CustomLabelsViewModel).Returns(new CustomLabelsViewModel(_appSettings.Object, _dialog.Object, new Mock().Object, _messageBus.Object)); } private SettingsWindowViewModel CreateVm() @@ -45,130 +38,122 @@ private class TestViewmodel : ViewModelBase { } - [TestMethod] - public void HasUnsavedChangesWhenSelectedViewModelIsEditing() + [Fact] + public void StartEditMessageIsPublished_HasUnsavedChangesPropertyIsTrue() { - var vm = CreateVm(); + Action handler = null; + _messageBus.Setup(m => m.Subscribe(It.IsAny>())) + .Callback>(x => handler = x); - Assert.IsFalse(vm.HasUnsavedChanges); - var newViewModel = new TestViewmodel(); - vm.SelectedViewModel = newViewModel; + var vm = CreateVm(); - newViewModel.BeginEdit(); - Assert.IsTrue(vm.HasUnsavedChanges); + Assert.False(vm.HasUnsavedChanges); + handler(default(EditStartMessage)); + Assert.True(vm.HasUnsavedChanges); } - [TestMethod] - public void SaveCommandCanExecuteBasedOnUnsavedChanges() + [Fact] + public void UnsavedChangesIsTrue_SaveCommandCanExecuteIsTrue() { var vm = CreateVm(); - Assert.IsFalse(vm.SaveCommand.CanExecute(null)); + Assert.False(vm.SaveCommand.CanExecute(null)); vm.HasUnsavedChanges = true; - Assert.IsTrue(vm.SaveCommand.CanExecute(null)); + Assert.True(vm.SaveCommand.CanExecute(null)); } - [TestMethod] - public void SaveCommandEndsEditsAndSavesSettings() + [Fact] + public void SaveCommandExecuted_PublishesEndsEditMessageAndSavesSettings() { var vm = CreateVm(); var childViewModel = new TestViewmodel(); - vm.HasUnsavedChanges = true; - vm.SelectedViewModel = childViewModel; - childViewModel.BeginEdit(); + vm.HasUnsavedChanges = true; ; vm.SaveCommand.Execute(null); _appSettings.Verify(m => m.Save(), Times.Once); - Assert.IsFalse(childViewModel.IsEditing); - Assert.IsFalse(vm.HasUnsavedChanges); + _messageBus.Verify(m => m.Publish(It.Is(msg => msg == EditEndMessage.Accepted), It.IsAny())); + Assert.False(vm.HasUnsavedChanges); } - [TestMethod] - public void CloseCommandShowsDialogIfUnsavedChanges() + [Fact] + public void CloseCommandOnExecuted_ShowsDialogIfUnsavedChanges() { _dialog.Setup(m => m.ShowConfirmationDialog(It.IsAny(), It.IsAny())) .Returns(true); var vm = CreateVm(); - var childViewModel = new TestViewmodel(); - vm.SelectedViewModel = childViewModel; - childViewModel.BeginEdit(); + vm.HasUnsavedChanges = true; vm.CloseCommand.Execute(null); _dialog.Verify(m => m.ShowConfirmationDialog(It.Is(d => d == ConfirmationDialogType.DiscardChanges), It.IsAny())); } - [TestMethod] - public void CloseCommandShowsDialogIfUnsavedChanges_DiscardChangesCancelsEditsAndClosesWindow() + [Fact] + public void CloseCommandExecuted_ShowsDialogIfUnsavedChanges_DiscardChangesCancelsEditsAndClosesWindow() { _dialog.Setup(m => m.ShowConfirmationDialog(It.IsAny(), It.IsAny())) .Returns(true); var vm = CreateVm(); - var childViewModel = new TestViewmodel(); - vm.SelectedViewModel = childViewModel; - childViewModel.BeginEdit(); + vm.HasUnsavedChanges = true; vm.CloseCommand.Execute(null); - Assert.IsFalse(childViewModel.IsEditing); _messageBus.Verify(m => m.Publish(It.Is(msg => msg == SettingsWindowMessage.CloseWindow), It.IsAny())); - Assert.IsFalse(vm.HasUnsavedChanges); + Assert.False(vm.HasUnsavedChanges); + _messageBus.Verify(m => m.Publish(It.Is(msg => msg == EditEndMessage.Cancelled), It.IsAny())); } - [TestMethod] - public void CloseCommandShowsDialogIfUnsavedChanges_CancelCloseDoesNotCloseWindow() + [Fact] + public void CloseCommandExecuted_ShowsDialogIfUnsavedChanges_CancelCloseDoesNotCloseWindow() { _dialog.Setup(m => m.ShowConfirmationDialog(It.IsAny(), It.IsAny())) .Returns(false); var vm = CreateVm(); - var childViewModel = new TestViewmodel(); - vm.SelectedViewModel = childViewModel; - childViewModel.BeginEdit(); + vm.HasUnsavedChanges = true; vm.CloseCommand.Execute(null); - Assert.IsTrue(childViewModel.IsEditing); _messageBus.Verify(m => m.Publish(It.Is(msg => msg == SettingsWindowMessage.CloseWindow), It.IsAny()), Times.Never); } - [TestMethod] - public void DisableDeleteProfileCommandWhenOnlyOneProfile() + [Fact] + public void OnlyOneProfile_DeleteProfileCommandCanExecuteIsFalse() { _appSettings.SetupGet(m => m.Profiles).Returns(new List{"profile 1"}); var vm = CreateVm(); - Assert.IsFalse(vm.DeleteProfileCommand.CanExecute(null)); + Assert.False(vm.DeleteProfileCommand.CanExecute(null)); } - [TestMethod] - public void ProfilesCollectionMatchesSettings() + [Fact] + public void SettingsHasProfiles_ProfilesCollectionMatches() { string profile1 = "profile 1"; string profile2 = "profile 2"; _appSettings.SetupGet(m => m.Profiles).Returns(new List {profile1, profile2}); var vm = CreateVm(); - Assert.AreEqual(2, vm.Profiles.Count); - Assert.AreEqual(profile1, vm.Profiles[0]); - Assert.AreEqual(profile2, vm.Profiles[1]); + Assert.Equal(2, vm.Profiles.Count); + Assert.Equal(profile1, vm.Profiles[0]); + Assert.Equal(profile2, vm.Profiles[1]); } - [TestMethod] - public void CreateProfileAddsProfileToSettingsAndViewModel() + [Fact] + public void CreateProfileCommandExecuted_AddsProfileToSettingsAndViewModel() { _appSettings.Setup(m => m.CreateProfile(It.IsAny())); var vm = CreateVm(); - Assert.AreEqual(0, vm.Profiles.Count); + Assert.Empty(vm.Profiles); vm.AddProfileCommand.Execute(null); - Assert.AreEqual(1, vm.Profiles.Count); + Assert.Single(vm.Profiles); _appSettings.Verify(m => m.CreateProfile(It.IsAny()), Times.Once); } - [TestMethod] - public void SelectedProfileCommandUpdatesSettings() + [Fact] + public void SelectedProfileCommandExecuted_UpdatesProfileInSettings() { string profile1 = "profile 1"; string profile2 = "profile 2"; @@ -180,8 +165,8 @@ public void SelectedProfileCommandUpdatesSettings() _appSettings.VerifySet(m => m.CurrentProfile = It.Is(x => x == profile2)); } - [TestMethod] - public void DeleteProfileConfirmationCancelDoesNotDelete() + [Fact] + public void DeleteProfileCommandExecuted_ConfirmationDialogCancelDoesNotDelete() { string profile1 = "profile 1"; string profile2 = "profile 2"; @@ -194,15 +179,15 @@ public void DeleteProfileConfirmationCancelDoesNotDelete() vm.SelectedProfileName = profile2; vm.DeleteProfileCommand.Execute(profile2); - Assert.AreEqual(2, vm.Profiles.Count); - Assert.AreEqual(profile2, vm.SelectedProfileName); + Assert.Equal(2, vm.Profiles.Count); + Assert.Equal(profile2, vm.SelectedProfileName); _dialog.Verify(m => m.ShowConfirmationDialog(It.Is(c => c == ConfirmationDialogType.DeleteProfile), It.Is(data => (string)data[0] == profile2))); _appSettings.Verify(m => m.DeleteProfile(It.IsAny()), Times.Never); } - [TestMethod] - public void DeleteProfileSelectsNewItem() + [Fact] + public void DeleteProfileCommandExecuted_SelectsDifferentProfile() { string profile1 = "profile 1"; string profile2 = "profile 2"; @@ -215,12 +200,12 @@ public void DeleteProfileSelectsNewItem() vm.SelectedProfileName = profile2; vm.DeleteProfileCommand.Execute(profile2); - Assert.AreEqual(profile1, vm.SelectedProfileName); + Assert.Equal(profile1, vm.SelectedProfileName); _appSettings.Verify(m => m.DeleteProfile(It.Is(x => x == profile2)), Times.Once); } - [TestMethod] - public void SelectProfileEndsEdits() + [Fact] + public void SelectProfileCommandExecuted_PublishesEndsEditMessage() { string profile1 = "profile 1"; string profile2 = "profile 2"; @@ -233,11 +218,11 @@ public void SelectProfileEndsEdits() vm.SelectedProfileName = profile2; - Assert.IsFalse(vm.IsEditing); + Assert.False(vm.IsEditing); } - [TestMethod] - public void RenameProfileDialogAccepted() + [Fact] + public void RenameProfileCommandExecuted_DialogAcceptedRenamesProfile() { string profile1 = "profile1"; string profile2 = "profile2"; @@ -252,13 +237,13 @@ public void RenameProfileDialogAccepted() _dialog.Verify(m => m.ShowRenameDialog(It.Is(s => s == profile1), It.Is>(e => e.Contains(profile1)))); _appSettings.Verify(m => m.RenameCurrentProfile(It.Is(s => s == profile2)), Times.Once); - Assert.AreEqual(profile2, vm.SelectedProfileName); - Assert.AreEqual(profile2, vm.Profiles[0]); - Assert.AreEqual(1, vm.Profiles.Count); + Assert.Equal(profile2, vm.SelectedProfileName); + Assert.Equal(profile2, vm.Profiles[0]); + Assert.Single(vm.Profiles); } - [TestMethod] - public void RenameProfileDialogCanceled() + [Fact] + public void RenameProfileCommandExecuted_DialogCanceledDoesNotRenameProfile() { string profile1 = "profile1"; @@ -269,12 +254,12 @@ public void RenameProfileDialogCanceled() vm.SelectedProfileName = profile1; _appSettings.Verify(m => m.RenameCurrentProfile(It.IsAny()), Times.Never); - Assert.AreEqual(profile1, vm.SelectedProfileName); - Assert.AreEqual(profile1, vm.Profiles[0]); + Assert.Equal(profile1, vm.SelectedProfileName); + Assert.Equal(profile1, vm.Profiles[0]); } - [TestMethod] - public void RenameProfileSameProfileIgnored() + [Fact] + public void RenameProfileCommandExecuted_NameNotChangedInDialogDoesNotChangeProfileName() { string profile1 = "profile1"; @@ -285,8 +270,8 @@ public void RenameProfileSameProfileIgnored() vm.SelectedProfileName = profile1; _appSettings.Verify(m => m.RenameCurrentProfile(It.IsAny()), Times.Never); - Assert.AreEqual(profile1, vm.SelectedProfileName); - Assert.AreEqual(profile1, vm.Profiles[0]); + Assert.Equal(profile1, vm.SelectedProfileName); + Assert.Equal(profile1, vm.Profiles[0]); } } } diff --git a/src/AudioBand.Test/ViewModels/ViewModelBaseTests.cs b/src/AudioBand.Test/ViewModels/ViewModelBaseTests.cs new file mode 100644 index 00000000..1dd2dfa8 --- /dev/null +++ b/src/AudioBand.Test/ViewModels/ViewModelBaseTests.cs @@ -0,0 +1,121 @@ +using AudioBand.ViewModels; +using Xunit; + +namespace AudioBand.Test +{ + public class ViewModelBaseTests + { + [Fact] + public void SetProperty_WithChangedField_CallsPropertyChanged() + { + string propertyName = null; + var vm = new ViewModel(); + vm.PropertyChanged += (o, e) => { propertyName = e.PropertyName; }; + vm.Field = 10; + + Assert.Equal(nameof(ViewModel.Field), propertyName); + Assert.Equal(10, vm.Field); + } + + [Fact] + public void SetProperty_SameField_DoesNotCallPropertyChanged() + { + int called = 0; + string propertyName = null; + var vm = new ViewModel(); + vm.PropertyChanged += (o, e) => { propertyName = e.PropertyName; called++; }; + vm.Field = 0; + + Assert.Equal(0, called); + Assert.Null(propertyName); + Assert.Equal(0, vm.Field); + } + + [Fact] + public void SetProperty_WithTrackedStateAttribute_AutomaticallyStartsEdit() + { + var vm = new ViewModel(); + vm.Field = 0; + + Assert.False(vm.IsEditing); + vm.Field = 1; + Assert.True(vm.IsEditing); + } + + [Fact] + public void SetProperty_WithoutTrackedStateAttribute_DoesNotStartEdit() + { + var vm = new ViewModel(); + vm.FieldNotTracked = 0; + + Assert.False(vm.IsEditing); + vm.FieldNotTracked = 1; + Assert.False(vm.IsEditing); + } + + [Fact] + public void SetPropertyWithModel_AutomaticallyStartsEdit() + { + var vm = new ViewModelWithModel(); + vm.Field = 0; + + Assert.False(vm.IsEditing); + vm.Field = 1; + Assert.True(vm.IsEditing); + } + + [Fact] + public void ResetViewModelWithModel_StartsEdit() + { + var vm = new ViewModelWithModel(); + vm.Reset(); + + Assert.True(vm.IsEditing); + } + + private class ViewModel : ViewModelBase + { + private int _field = 0; + private int _notTracked = 0; + + [TrackState] + public int Field + { + get => _field; + set => SetProperty(ref _field, value); + } + + public int FieldNotTracked + { + get => _notTracked; + set => SetProperty(ref _notTracked, value); + } + } + + private class ViewModelWithModel : ViewModelBase + { + private Model model = new Model(); + + public ViewModelWithModel() + { + } + + public ViewModelWithModel(Model m) + { + model = m; + } + + [TrackState] + public int Field + { + get => model.Value; + set => SetProperty(model, nameof(ViewModelBaseTests.Model.Value), value); + } + } + + private class Model + { + public int Value { get; set; } = 0; + } + } +} diff --git a/src/AudioBand/ViewModels/AlsoNotifyAttribute.cs b/src/AudioBand/AlsoNotifyAttribute.cs similarity index 85% rename from src/AudioBand/ViewModels/AlsoNotifyAttribute.cs rename to src/AudioBand/AlsoNotifyAttribute.cs index 1f25c7bb..9794ebc7 100644 --- a/src/AudioBand/ViewModels/AlsoNotifyAttribute.cs +++ b/src/AudioBand/AlsoNotifyAttribute.cs @@ -1,10 +1,10 @@ using System; using System.ComponentModel; -namespace AudioBand.ViewModels +namespace AudioBand { /// - /// Specifies that event of will be raised for other properties. + /// Specifies that events will be raised for other properties. /// [AttributeUsage(AttributeTargets.Property)] internal class AlsoNotifyAttribute : Attribute diff --git a/src/AudioBand/AudioBand.csproj b/src/AudioBand/AudioBand.csproj index 5205809e..5b038a20 100644 --- a/src/AudioBand/AudioBand.csproj +++ b/src/AudioBand/AudioBand.csproj @@ -97,6 +97,8 @@ + + @@ -105,6 +107,8 @@ + + @@ -117,6 +121,8 @@ + + @@ -128,7 +134,6 @@ - @@ -142,6 +147,7 @@ + @@ -182,13 +188,24 @@ + + + + + + + + + + + - + @@ -201,13 +218,12 @@ - + - @@ -464,13 +480,13 @@ - 8.1.0 + 8.1.1 1.2.0 - 1.4.1 + 1.5.0 0.6.1 @@ -482,7 +498,7 @@ 10.0.17134.1000-preview - 0.11.0 + 0.12.0 1.3.0 @@ -495,9 +511,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - 4.5.0 - diff --git a/src/AudioBand/AudioSource/AudioSession.cs b/src/AudioBand/AudioSource/AudioSession.cs new file mode 100644 index 00000000..fbafc942 --- /dev/null +++ b/src/AudioBand/AudioSource/AudioSession.cs @@ -0,0 +1,167 @@ +using System; +using System.Drawing; + +namespace AudioBand.AudioSource +{ + /// + /// Persistent audio source session that updates when the audio source changes. + /// + public class AudioSession : ObservableObject, IAudioSession + { + private IInternalAudioSource _currentAudioSource; + private bool _isPlaying; + private string _songArtist; + private string _songName; + private string _albumName; + private TimeSpan _songProgress; + private TimeSpan _songLength; + private bool _isShuffleOn; + private RepeatMode _repeatMode; + private Image _album; + + /// + /// Gets or sets the current audio source. + /// + public IInternalAudioSource CurrentAudioSource + { + get => _currentAudioSource; + set + { + if (_currentAudioSource == value) + { + return; + } + + _currentAudioSource = value; + AudioSourceChanged(); + } + } + + /// + public bool IsPlaying + { + get => _isPlaying; + set => SetProperty(ref _isPlaying, value); + } + + /// + public string SongArtist + { + get => _songArtist; + set => SetProperty(ref _songArtist, value); + } + + /// + public string SongName + { + get => _songName; + set => SetProperty(ref _songName, value); + } + + /// + public string AlbumName + { + get => _albumName; + set => SetProperty(ref _albumName, value); + } + + /// + public Image AlbumArt + { + get => _album; + set => SetProperty(ref _album, value); + } + + /// + public TimeSpan SongProgress + { + get => _songProgress; + set => SetProperty(ref _songProgress, value); + } + + /// + public TimeSpan SongLength + { + get => _songLength; + set => SetProperty(ref _songLength, value); + } + + /// + public bool IsShuffleOn + { + get => _isShuffleOn; + set => SetProperty(ref _isShuffleOn, value); + } + + /// + public RepeatMode RepeatMode + { + get => _repeatMode; + set => SetProperty(ref _repeatMode, value); + } + + private void AudioSourceChanged() + { + if (_currentAudioSource != null) + { + ClearSession(); + _currentAudioSource.TrackInfoChanged -= AudioSourceOnTrackInfoChanged; + _currentAudioSource.IsPlayingChanged -= AudioSourceOnIsPlayingChanged; + _currentAudioSource.TrackProgressChanged -= AudioSourceOnTrackProgressChanged; + _currentAudioSource.RepeatModeChanged -= AudioSourceOnRepeatModeChanged; + _currentAudioSource.ShuffleChanged -= AudioSourceOnShuffleChanged; + } + + if (_currentAudioSource == null) + { + ClearSession(); + return; + } + + _currentAudioSource.TrackInfoChanged += AudioSourceOnTrackInfoChanged; + _currentAudioSource.IsPlayingChanged += AudioSourceOnIsPlayingChanged; + _currentAudioSource.TrackProgressChanged += AudioSourceOnTrackProgressChanged; + _currentAudioSource.RepeatModeChanged += AudioSourceOnRepeatModeChanged; + _currentAudioSource.ShuffleChanged += AudioSourceOnShuffleChanged; + } + + private void AudioSourceOnShuffleChanged(object sender, bool e) + { + IsShuffleOn = e; + } + + private void AudioSourceOnRepeatModeChanged(object sender, RepeatMode e) + { + RepeatMode = e; + } + + private void AudioSourceOnTrackProgressChanged(object sender, TimeSpan e) + { + SongProgress = e; + } + + private void AudioSourceOnIsPlayingChanged(object sender, bool e) + { + IsPlaying = e; + } + + private void AudioSourceOnTrackInfoChanged(object sender, TrackInfoChangedEventArgs e) + { + SongArtist = e.Artist; + SongLength = e.TrackLength; + SongName = e.TrackName; + AlbumName = e.Album; + AlbumArt = e.AlbumArt; + } + + private void ClearSession() + { + IsPlaying = false; + SongArtist = null; + SongName = null; + AlbumName = null; + SongProgress = TimeSpan.Zero; + SongLength = TimeSpan.Zero; + } + } +} diff --git a/src/AudioBand/AudioSource/IAudioSession.cs b/src/AudioBand/AudioSource/IAudioSession.cs new file mode 100644 index 00000000..5494ebd2 --- /dev/null +++ b/src/AudioBand/AudioSource/IAudioSession.cs @@ -0,0 +1,62 @@ +using System; +using System.ComponentModel; +using System.Drawing; + +namespace AudioBand.AudioSource +{ + /// + /// Encapsulates the the audio session. + /// + public interface IAudioSession : INotifyPropertyChanged + { + /// + /// Gets or sets the current audio source. + /// + IInternalAudioSource CurrentAudioSource { get; set; } + + /// + /// Gets a value indicating whether the audio source is currently playing. + /// + bool IsPlaying { get; } + + /// + /// Gets the current song artist. + /// + string SongArtist { get; } + + /// + /// Gets the current song name. + /// + string SongName { get; } + + /// + /// Gets the current album name. + /// + string AlbumName { get; } + + /// + /// Gets the current album. + /// + Image AlbumArt { get; } + + /// + /// Gets the current song progress. + /// + TimeSpan SongProgress { get; } + + /// + /// Gets the current song length. + /// + TimeSpan SongLength { get; } + + /// + /// Gets a value indicating whether shuffle is currently on. + /// + bool IsShuffleOn { get; } + + /// + /// Gets the current repeat mode. + /// + RepeatMode RepeatMode { get; } + } +} diff --git a/src/AudioBand/AudioSource/IInternalAudioSource.cs b/src/AudioBand/AudioSource/IInternalAudioSource.cs index 24217b80..319713f8 100644 --- a/src/AudioBand/AudioSource/IInternalAudioSource.cs +++ b/src/AudioBand/AudioSource/IInternalAudioSource.cs @@ -8,21 +8,6 @@ namespace AudioBand.AudioSource /// public interface IInternalAudioSource : IAudioSource { - /// - /// Gets a value indicating whether the audio source is currently playing. - /// - bool IsPlaying { get; } - - /// - /// Gets the current progress. - /// - TimeSpan CurrentProgress { get; } - - /// - /// Gets the last track info. - /// - TrackInfoChangedEventArgs LastTrackInfo { get; } - /// /// Gets the settings that the audio source exposes. /// diff --git a/src/AudioBand/Behaviors/TextBlockTextSegments.cs b/src/AudioBand/Behaviors/TextBlockTextSegments.cs index d005172f..58af6d2f 100644 --- a/src/AudioBand/Behaviors/TextBlockTextSegments.cs +++ b/src/AudioBand/Behaviors/TextBlockTextSegments.cs @@ -52,17 +52,17 @@ private static IEnumerable CreateInlines(IEnumerable segmen var run = new Run(); run.SetBinding(Run.TextProperty, textBinding); run.SetBinding(TextElement.ForegroundProperty, colorBinding); - if (textSegment.Type.HasFlag(FormattedTextFlags.Bold)) + if (textSegment.Flags.HasFlag(FormattedTextFlags.Bold)) { run.FontWeight = FontWeights.Bold; } - if (textSegment.Type.HasFlag(FormattedTextFlags.Italic)) + if (textSegment.Flags.HasFlag(FormattedTextFlags.Italic)) { run.FontStyle = FontStyles.Italic; } - if (textSegment.Type.HasFlag(FormattedTextFlags.Underline)) + if (textSegment.Flags.HasFlag(FormattedTextFlags.Underline)) { run.TextDecorations.Add(TextDecorations.Underline); } diff --git a/src/AudioBand/Commands/AsyncRelayCommand.cs b/src/AudioBand/Commands/AsyncRelayCommand.cs index 1c55ede8..f22f0638 100644 --- a/src/AudioBand/Commands/AsyncRelayCommand.cs +++ b/src/AudioBand/Commands/AsyncRelayCommand.cs @@ -1,67 +1,30 @@ using System; using System.Threading.Tasks; -using System.Windows.Input; namespace AudioBand.Commands { /// - /// Basic async command. + /// An async relay command that does not have a parameter. /// - /// Type of the command parameter. - public class AsyncRelayCommand : IAsyncCommand + public class AsyncRelayCommand : AsyncRelayCommand { - private readonly Func _execute; - private readonly Predicate _canExecute; - - /// - /// Initializes a new instance of the class - /// with a delegate to be executed. - /// - /// Action to execute. - public AsyncRelayCommand(Func execute) - : this(execute, null) - { - } - /// - /// Initializes a new instance of the class - /// with a delegate to be executed and a predicate to determine if it can be executed. + /// Initializes a new instance of the class. /// - /// Async delegate to execute. - /// Predicate to check if the commmand can execute. - public AsyncRelayCommand(Func execute, Predicate canExecute) - { - _execute = execute ?? throw new ArgumentNullException(nameof(execute)); - _canExecute = canExecute; - } - - /// - public event EventHandler CanExecuteChanged - { - add => CommandManager.RequerySuggested += value; - remove => CommandManager.RequerySuggested -= value; - } - - /// - public bool CanExecute(object parameter) - { - return _canExecute?.Invoke((T)parameter) ?? true; - } - - /// - public async void Execute(object parameter) + /// The function to execute. + public AsyncRelayCommand(Func execute) + : base(o => execute()) { - await ExecuteAsync(parameter); } /// - /// Execute the command asynchronously. + /// Initializes a new instance of the class. /// - /// Command paramerter. - /// Task. - public async Task ExecuteAsync(object parameter) + /// The function to execute. + /// The predicate to determine if the command can execute. + public AsyncRelayCommand(Func execute, Func canExecute) + : base(o => execute(), o => canExecute()) { - await _execute((T)parameter); } } } diff --git a/src/AudioBand/Commands/AsyncRelayCommand{T}.cs b/src/AudioBand/Commands/AsyncRelayCommand{T}.cs new file mode 100644 index 00000000..9c8869e6 --- /dev/null +++ b/src/AudioBand/Commands/AsyncRelayCommand{T}.cs @@ -0,0 +1,71 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace AudioBand.Commands +{ + /// + /// Basic async command. + /// + /// Type of the command parameter. + public class AsyncRelayCommand : IAsyncCommand + { + private readonly Func _execute; + private readonly Predicate _canExecute; + + /// + /// Initializes a new instance of the class + /// with a delegate to be executed. + /// + /// Action to execute. + public AsyncRelayCommand(Func execute) + : this(execute, null) + { + } + + /// + /// Initializes a new instance of the class + /// with a delegate to be executed and a predicate to determine if it can be executed. + /// + /// Async delegate to execute. + /// Predicate to check if the command can execute. + public AsyncRelayCommand(Func execute, Predicate canExecute) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute; + } + + /// + public event EventHandler CanExecuteChanged + { + add => CommandManager.RequerySuggested += value; + remove => CommandManager.RequerySuggested -= value; + } + + /// + [DebuggerStepThrough] + public bool CanExecute(object parameter) + { + return _canExecute?.Invoke((T)parameter) ?? true; + } + + /// + [DebuggerStepThrough] + public async void Execute(object parameter) + { + await ExecuteAsync(parameter); + } + + /// + /// Execute the command asynchronously. + /// + /// Command parameter. + /// Task. + [DebuggerStepThrough] + public async Task ExecuteAsync(object parameter) + { + await _execute((T)parameter); + } + } +} diff --git a/src/AudioBand/Commands/RelayCommand.cs b/src/AudioBand/Commands/RelayCommand.cs index 447cc733..6c9c6a0b 100644 --- a/src/AudioBand/Commands/RelayCommand.cs +++ b/src/AudioBand/Commands/RelayCommand.cs @@ -10,8 +10,8 @@ public class RelayCommand : RelayCommand /// with an action to be executed. /// /// Action to execute. - public RelayCommand(Action execute) - : base(execute) + public RelayCommand(Action execute) + : base(o => execute()) { } @@ -21,8 +21,8 @@ public RelayCommand(Action execute) /// /// Action to execute. /// Predicate to check if the command can be executed. - public RelayCommand(Action execute, Predicate canExecute) - : base(execute, canExecute) + public RelayCommand(Action execute, Func canExecute) + : base(o => execute(), o => canExecute()) { } } diff --git a/src/AudioBand/Commands/RelayCommand{T}.cs b/src/AudioBand/Commands/RelayCommand{T}.cs index 0aeb2704..f4f941b3 100644 --- a/src/AudioBand/Commands/RelayCommand{T}.cs +++ b/src/AudioBand/Commands/RelayCommand{T}.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Specialized; using System.ComponentModel; +using System.Diagnostics; using System.Windows.Input; namespace AudioBand.Commands @@ -26,7 +27,7 @@ public RelayCommand(Action execute) /// with an action to be executed and a predicate to determine if it can be executed. /// /// Action to execute. - /// Predicate to check if the commmand can be executed. + /// Predicate to check if the command can be executed. public RelayCommand(Action execute, Predicate canExecute) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); @@ -55,6 +56,7 @@ public void RaiseCanExecuteChanged() } /// + [DebuggerStepThrough] public void Execute(object parameter) { _execute((T)parameter); diff --git a/src/AudioBand/Deskband.cs b/src/AudioBand/Deskband.cs index b6f37f32..60509f52 100644 --- a/src/AudioBand/Deskband.cs +++ b/src/AudioBand/Deskband.cs @@ -16,6 +16,7 @@ using CSDeskBand; using NLog; using SimpleInjector; +using SimpleInjector.Advanced; namespace AudioBand { @@ -105,6 +106,7 @@ private void ConfigureDependencies() _container.Register(Lifestyle.Singleton); _container.Register(Lifestyle.Singleton); _container.Register(Lifestyle.Singleton); + _container.Register(Lifestyle.Singleton); _container.Register(Lifestyle.Singleton); _container.Register(Lifestyle.Singleton); diff --git a/src/AudioBand/Messages/EditEndMessage.cs b/src/AudioBand/Messages/EditEndMessage.cs new file mode 100644 index 00000000..27328f6b --- /dev/null +++ b/src/AudioBand/Messages/EditEndMessage.cs @@ -0,0 +1,18 @@ +namespace AudioBand.Messages +{ + /// + /// Global message that indicates that editing is ending. + /// + public enum EditEndMessage + { + /// + /// User cancelled all current edits. + /// + Cancelled, + + /// + /// User accepted all current edits. + /// + Accepted, + } +} diff --git a/src/AudioBand/Messages/EditStartMessage.cs b/src/AudioBand/Messages/EditStartMessage.cs new file mode 100644 index 00000000..83454626 --- /dev/null +++ b/src/AudioBand/Messages/EditStartMessage.cs @@ -0,0 +1,9 @@ +namespace AudioBand.Messages +{ + /// + /// Global message to mark the start of editing. + /// + public enum EditStartMessage + { + } +} diff --git a/src/AudioBand/Messages/MessageBus.cs b/src/AudioBand/Messages/MessageBus.cs index 14ba82fc..2d134a0a 100644 --- a/src/AudioBand/Messages/MessageBus.cs +++ b/src/AudioBand/Messages/MessageBus.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using AudioBand.Logging; @@ -16,9 +17,10 @@ public class MessageBus : IMessageBus private readonly Dictionary> _handlers = new Dictionary>(); /// + [DebuggerStepThrough] public void Subscribe(Action handler) { - Logger.Debug("{class} registered new handler for {message}", handler.Target.GetType(), typeof(TMessage)); + Logger.Trace("{class} registered new handler for {message}", handler.Target.GetType(), typeof(TMessage)); if (_handlers.ContainsKey(typeof(TMessage))) { @@ -31,9 +33,10 @@ public void Subscribe(Action handler) } /// + [DebuggerStepThrough] public void Unsubscribe(Action handler) { - Logger.Debug("{class} unsubscribed for {message}", handler.Target.GetType(), typeof(TMessage)); + Logger.Trace("{class} unsubscribed for {message}", handler.Target.GetType(), typeof(TMessage)); if (_handlers.TryGetValue(typeof(TMessage), out var handlers)) { @@ -42,6 +45,7 @@ public void Unsubscribe(Action handler) } /// + [DebuggerStepThrough] public void Publish(TMessage message, [CallerMemberName] string caller = "") { if (!_handlers.TryGetValue(typeof(TMessage), out var handlers)) @@ -51,7 +55,7 @@ public void Publish(TMessage message, [CallerMemberName] string caller foreach (var handler in handlers.Cast>()) { - Logger.Debug("Message published {caller} -> {info}", caller, new { Target = handler.Target.GetType(), Handler = handler.Method.Name, Message = message }); + Logger.Trace("Message published {caller} -> {info}", caller, new { Target = handler.Target.GetType(), Handler = handler.Method.Name, Message = message }); handler(message); } } diff --git a/src/AudioBand/Models/AlbumArt.cs b/src/AudioBand/Models/AlbumArt.cs index f488ead9..cf16b051 100644 --- a/src/AudioBand/Models/AlbumArt.cs +++ b/src/AudioBand/Models/AlbumArt.cs @@ -5,8 +5,6 @@ /// public class AlbumArt : LayoutModelBase { - private string _placeholderPath = ""; - /// /// Initializes a new instance of the class. /// @@ -21,10 +19,6 @@ public AlbumArt() /// /// Gets or sets the path of the placeholder image. /// - public string PlaceholderPath - { - get => _placeholderPath; - set => SetProperty(ref _placeholderPath, value); - } + public string PlaceholderPath { get; set; } = ""; } } diff --git a/src/AudioBand/Models/AlbumArtPopup.cs b/src/AudioBand/Models/AlbumArtPopup.cs index 2a55e454..e3e769d5 100644 --- a/src/AudioBand/Models/AlbumArtPopup.cs +++ b/src/AudioBand/Models/AlbumArtPopup.cs @@ -3,57 +3,31 @@ /// /// Model for the album art popup. /// - public class AlbumArtPopup : ModelBase + public class AlbumArtPopup { - private bool _isVisible = true; - private double _width = 250; - private double _height = 250; - private double _xPosition = -110; - private double _margin = -4; - /// /// Gets or sets a value indicating whether the album art popup is visible. /// - public bool IsVisible - { - get => _isVisible; - set => SetProperty(ref _isVisible, value); - } + public bool IsVisible { get; set; } = true; /// /// Gets or sets the width of the album art popup. /// - public double Width - { - get => _width; - set => SetProperty(ref _width, value); - } + public double Width { get; set; } = 250; /// /// Gets or sets the height of the album art popup. /// - public double Height - { - get => _height; - set => SetProperty(ref _height, value); - } + public double Height { get; set; } = 250; /// /// Gets or sets the x position of the album art popup. /// - public double XPosition - { - get => _xPosition; - set => SetProperty(ref _xPosition, value); - } + public double XPosition { get; set; } = -110; /// /// Gets or sets the margin between the album art popup and the taskbar. /// - public double Margin - { - get => _margin; - set => SetProperty(ref _margin, value); - } + public double Margin { get; set; } = 4; } } diff --git a/src/AudioBand/Models/AudioBand.cs b/src/AudioBand/Models/AudioBand.cs index c6f7c634..63e389ef 100644 --- a/src/AudioBand/Models/AudioBand.cs +++ b/src/AudioBand/Models/AudioBand.cs @@ -5,37 +5,21 @@ namespace AudioBand.Models /// /// The model for the toolbar. /// - public class AudioBand : ModelBase + public class AudioBand { - private double _width = 500; - private double _height = 30; - private Color _backgroundColor = Colors.Transparent; - /// /// Gets or sets the width of the toolbar. /// - public double Width - { - get => _width; - set => SetProperty(ref _width, value); - } + public double Width { get; set; } = 500; /// /// Gets or sets the height of the toolbar. /// - public double Height - { - get => _height; - set => SetProperty(ref _height, value); - } + public double Height { get; set; } = 30; /// /// Gets or sets the background color of the toolbar. /// - public Color BackgroundColor - { - get => _backgroundColor; - set => SetProperty(ref _backgroundColor, value); - } + public Color BackgroundColor { get; set; } = Colors.Transparent; } } diff --git a/src/AudioBand/Models/AudioSourceSetting.cs b/src/AudioBand/Models/AudioSourceSetting.cs index 483589c4..6111169d 100644 --- a/src/AudioBand/Models/AudioSourceSetting.cs +++ b/src/AudioBand/Models/AudioSourceSetting.cs @@ -5,19 +5,12 @@ namespace AudioBand.Models /// /// A key / value pair that represents a single setting for an audio source. /// - public class AudioSourceSetting : ModelBase + public class AudioSourceSetting { - private string _name; - private object _value; - /// /// Gets or sets the name of the setting provided by the . /// - public string Name - { - get => _name; - set => SetProperty(ref _name, value); - } + public string Name { get; set; } /// /// Gets or sets the value of the setting. @@ -26,10 +19,6 @@ public string Name /// The value of the setting, either provided by the or the user. /// The default value is set by the . /// - public object Value - { - get => _value; - set => SetProperty(ref _value, value); - } + public object Value { get; set; } } } diff --git a/src/AudioBand/Models/AudioSourceSettings.cs b/src/AudioBand/Models/AudioSourceSettings.cs index 131b93c9..ae6ceb5b 100644 --- a/src/AudioBand/Models/AudioSourceSettings.cs +++ b/src/AudioBand/Models/AudioSourceSettings.cs @@ -5,7 +5,7 @@ namespace AudioBand.Models /// /// Collection of settings for a specific audio source. /// - public class AudioSourceSettings : ModelBase + public class AudioSourceSettings { /// /// Gets or sets the name of the audio source. diff --git a/src/AudioBand/Models/ButtonContent.cs b/src/AudioBand/Models/ButtonContent.cs index 764bc836..4c7ff35b 100644 --- a/src/AudioBand/Models/ButtonContent.cs +++ b/src/AudioBand/Models/ButtonContent.cs @@ -5,97 +5,51 @@ namespace AudioBand.Models /// /// Model for button content, including image or text settings. /// - public class ButtonContent : ModelBase + public class ButtonContent { - private ButtonContentType _contentType = ButtonContentType.Text; - private string _imagePath; - private string _hoveredImagePath; - private string _clickedImagePath; - private string _fontFamily = "Segoe MDL2 Assets"; - private string _text; - private Color _textColor = Colors.White; - private Color _hoveredTextColor = Colors.White; - private Color _clickedTextColor = Colors.White; - /// /// Gets or sets the content type. /// - public ButtonContentType ContentType - { - get => _contentType; - set => SetProperty(ref _contentType, value); - } + public ButtonContentType ContentType { get; set; } = ButtonContentType.Text; /// /// Gets or sets the image path. /// - public string ImagePath - { - get => _imagePath; - set => SetProperty(ref _imagePath, value); - } + public string ImagePath { get; set; } /// /// Gets or sets the hovered image path. /// - public string HoveredImagePath - { - get => _hoveredImagePath; - set => SetProperty(ref _hoveredImagePath, value); - } + public string HoveredImagePath { get; set; } /// /// Gets or sets the clicked image path. /// - public string ClickedImagePath - { - get => _clickedImagePath; - set => SetProperty(ref _clickedImagePath, value); - } + public string ClickedImagePath { get; set; } /// /// Gets or sets the font family. /// - public string FontFamily - { - get => _fontFamily; - set => SetProperty(ref _fontFamily, value); - } + public string FontFamily { get; set; } = "Segoe MDL2 Assets"; /// /// Gets or sets the text. /// - public string Text - { - get => _text; - set => SetProperty(ref _text, value); - } + public string Text { get; set; } /// /// Gets or sets the text color. /// - public Color TextColor - { - get => _textColor; - set => SetProperty(ref _textColor, value); - } + public Color TextColor { get; set; } = Colors.White; /// /// Gets or sets the text color when hovered. /// - public Color HoveredTextColor - { - get => _hoveredTextColor; - set => SetProperty(ref _hoveredTextColor, value); - } + public Color HoveredTextColor { get; set; } = Colors.White; /// /// Gets or sets the text color when clicked. /// - public Color ClickedTextColor - { - get => _clickedTextColor; - set => SetProperty(ref _clickedTextColor, value); - } + public Color ClickedTextColor { get; set; } = Colors.White; } } diff --git a/src/AudioBand/Models/ButtonModelBase.cs b/src/AudioBand/Models/ButtonModelBase.cs index 1278da14..9657945d 100644 --- a/src/AudioBand/Models/ButtonModelBase.cs +++ b/src/AudioBand/Models/ButtonModelBase.cs @@ -7,35 +7,19 @@ namespace AudioBand.Models /// public class ButtonModelBase : LayoutModelBase { - private Color _backgroundColor = Colors.Transparent; - private Color _hoveredBackgroundColor = Color.FromArgb(25, 255, 255, 255); - private Color _clickedBackgroundColor = Color.FromArgb(15, 255, 255, 255); - /// /// Gets or sets the background color. /// - public Color BackgroundColor - { - get => _backgroundColor; - set => SetProperty(ref _backgroundColor, value); - } + public Color BackgroundColor { get; set; } = Colors.Transparent; /// /// Gets or sets the background color when hovered. /// - public Color HoveredBackgroundColor - { - get => _hoveredBackgroundColor; - set => SetProperty(ref _hoveredBackgroundColor, value); - } + public Color HoveredBackgroundColor { get; set; } = Color.FromArgb(25, 255, 255, 255); /// /// Gets or sets the background color when clicked. /// - public Color ClickedBackgroundColor - { - get => _clickedBackgroundColor; - set => SetProperty(ref _clickedBackgroundColor, value); - } + public Color ClickedBackgroundColor { get; set; } = Color.FromArgb(15, 255, 255, 255); } } diff --git a/src/AudioBand/Models/CustomLabel.cs b/src/AudioBand/Models/CustomLabel.cs index d0c21aa8..d83ad798 100644 --- a/src/AudioBand/Models/CustomLabel.cs +++ b/src/AudioBand/Models/CustomLabel.cs @@ -7,19 +7,6 @@ namespace AudioBand.Models /// public class CustomLabel : LayoutModelBase { - private string _fontFamily = "Segoe UI"; - private float _fontSize = 8.5f; - private Color _color = Colors.White; - private string _formatString = "{artist} - {song}"; - private TextAlignment _alignment = TextAlignment.Center; - private string _name = "Now Playing"; - private int _scrollSpeed = 5000; - private TextOverflow _textOverflow = TextOverflow.Scroll; - private ScrollBehavior _scrollBehavior = ScrollBehavior.Always; - private TextFadeEffect _textFadeEffect = TextFadeEffect.OnlyWhenScrolling; - private double _leftFadeOffset = 0.1; - private double _rightFadeOffset = 0.9; - /// /// Initializes a new instance of the class. /// @@ -55,109 +42,61 @@ public enum TextAlignment /// /// Gets or sets the font family of the label. /// - public string FontFamily - { - get => _fontFamily; - set => SetProperty(ref _fontFamily, value); - } + public string FontFamily { get; set; } = "Segoe UI"; /// /// Gets or sets the font size of the label. /// - public float FontSize - { - get => _fontSize; - set => SetProperty(ref _fontSize, value); - } + public float FontSize { get; set; } = 12; /// /// Gets or sets the color of the label. /// - public Color Color - { - get => _color; - set => SetProperty(ref _color, value); - } + public Color Color { get; set; } = Colors.White; /// /// Gets or sets the format for the label. /// - public string FormatString - { - get => _formatString; - set => SetProperty(ref _formatString, value); - } + public string FormatString { get; set; } = "{artist} - {song}"; /// /// Gets or sets the alignment of the text. /// - public TextAlignment Alignment - { - get => _alignment; - set => SetProperty(ref _alignment, value); - } + public TextAlignment Alignment { get; set; } = TextAlignment.Center; /// /// Gets or sets the name of the label. /// - public string Name - { - get => _name; - set => SetProperty(ref _name, value); - } + public string Name { get; set; } = "Now Playing"; /// /// Gets or sets the number to milliseconds to scroll across. /// - public int ScrollSpeed - { - get => _scrollSpeed; - set => SetProperty(ref _scrollSpeed, value); - } + public int ScrollSpeed { get; set; } = 5000; /// /// Gets or sets the text overflow behavior. /// - public TextOverflow TextOverflow - { - get => _textOverflow; - set => SetProperty(ref _textOverflow, value); - } + public TextOverflow TextOverflow { get; set; } = TextOverflow.Scroll; /// /// Gets or sets the scroll behavior. /// - public ScrollBehavior ScrollBehavior - { - get => _scrollBehavior; - set => SetProperty(ref _scrollBehavior, value); - } + public ScrollBehavior ScrollBehavior { get; set; } = ScrollBehavior.Always; /// /// Gets or sets the fade effect. /// - public TextFadeEffect FadeEffect - { - get => _textFadeEffect; - set => SetProperty(ref _textFadeEffect, value); - } + public TextFadeEffect FadeEffect { get; set; } = TextFadeEffect.OnlyWhenScrolling; /// /// Gets or sets the fade offset for the left side. /// - public double LeftFadeOffset - { - get => _leftFadeOffset; - set => SetProperty(ref _leftFadeOffset, value); - } + public double LeftFadeOffset { get; set; } = 0.1; /// /// Gets or sets the fade offset for the right side. /// - public double RightFadeOffset - { - get => _rightFadeOffset; - set => SetProperty(ref _rightFadeOffset, value); - } + public double RightFadeOffset { get; set; } = 0.9; } } diff --git a/src/AudioBand/Models/LayoutModelBase.cs b/src/AudioBand/Models/LayoutModelBase.cs index 2fe85784..5b5b3b6c 100644 --- a/src/AudioBand/Models/LayoutModelBase.cs +++ b/src/AudioBand/Models/LayoutModelBase.cs @@ -3,67 +3,37 @@ /// /// Base model that contains support for layout. /// - public class LayoutModelBase : ModelBase + /// This should probably be a has-a relationship instead of inheriting from this class. + public class LayoutModelBase { - private bool _isVisible = true; - private double _width; - private double _height; - private double _xPosition; - private double _yPosition; - private PositionAnchor _positionAnchor = PositionAnchor.TopLeft; - /// /// Gets or sets a value indicating whether it is visible. /// - public bool IsVisible - { - get => _isVisible; - set => SetProperty(ref _isVisible, value); - } + public bool IsVisible { get; set; } = true; /// /// Gets or sets the width. /// - public double Width - { - get => _width; - set => SetProperty(ref _width, value); - } + public double Width { get; set; } /// /// Gets or sets the height. /// - public double Height - { - get => _height; - set => SetProperty(ref _height, value); - } + public double Height { get; set; } /// /// Gets or sets the x position. /// - public double XPosition - { - get => _xPosition; - set => SetProperty(ref _xPosition, value); - } + public double XPosition { get; set; } /// /// Gets or sets the y position. /// - public double YPosition - { - get => _yPosition; - set => SetProperty(ref _yPosition, value); - } + public double YPosition { get; set; } /// /// Gets or sets the positioning. /// - public PositionAnchor Anchor - { - get => _positionAnchor; - set => SetProperty(ref _positionAnchor, value); - } + public PositionAnchor Anchor { get; set; } = PositionAnchor.TopLeft; } } diff --git a/src/AudioBand/Models/ModelBase.cs b/src/AudioBand/Models/ModelBase.cs deleted file mode 100644 index b71f1e80..00000000 --- a/src/AudioBand/Models/ModelBase.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using AudioBand.Logging; -using NLog; - -namespace AudioBand.Models -{ - /// - /// Base class for models. - /// - public class ModelBase : INotifyPropertyChanged - { - /// - /// Initializes a new instance of the class. - /// - public ModelBase() - { - Logger = AudioBandLogManager.GetLogger(GetType().FullName); - } - - /// - public event PropertyChangedEventHandler PropertyChanged; - - /// - /// Gets the logger for the model. - /// - protected ILogger Logger { get; } - - /// - /// Raises the event. - /// - /// Name of the property that changed. - protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - /// - /// Set property to a new value. - /// - /// Type of the property. - /// Old value. - /// New value. - /// Name of the property that changed. - /// True if the property changed. - protected virtual bool SetProperty(ref T field, T newValue, [CallerMemberName] string propertyName = null) - { - if (EqualityComparer.Default.Equals(field, newValue)) - { - return false; - } - - field = newValue; - RaisePropertyChanged(propertyName); - return true; - } - } -} diff --git a/src/AudioBand/Models/ProgressBar.cs b/src/AudioBand/Models/ProgressBar.cs index 99ae31cc..946956be 100644 --- a/src/AudioBand/Models/ProgressBar.cs +++ b/src/AudioBand/Models/ProgressBar.cs @@ -25,28 +25,16 @@ public ProgressBar() /// /// Gets or sets the foreground color. /// - public Color ForegroundColor - { - get => _foregroundColor; - set => SetProperty(ref _foregroundColor, value); - } + public Color ForegroundColor { get; set; } = Colors.DodgerBlue; /// /// Gets or sets the background color. /// - public Color BackgroundColor - { - get => _backgroundColor; - set => SetProperty(ref _backgroundColor, value); - } + public Color BackgroundColor { get; set; } = Colors.DimGray; /// /// Gets or sets the hover color. /// - public Color HoverColor - { - get => _hoverColor; - set => SetProperty(ref _hoverColor, value); - } + public Color HoverColor { get; set; } = Colors.DeepSkyBlue; } } diff --git a/src/AudioBand/ObservableObject.cs b/src/AudioBand/ObservableObject.cs new file mode 100644 index 00000000..4a21475c --- /dev/null +++ b/src/AudioBand/ObservableObject.cs @@ -0,0 +1,148 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using FastMember; + +namespace AudioBand +{ + /// + /// Base object that implements and provides facilities for . + /// + public abstract class ObservableObject : INotifyPropertyChanged + { + private readonly Dictionary _modelToAccessor = new Dictionary(); + private readonly Dictionary _alsoNotifyMap = new Dictionary(); + + /// + /// Initializes a new instance of the class. + /// + protected ObservableObject() + { + Accessor = TypeAccessor.Create(GetType(), true); + SetupAlsoNotify(); + } + + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Gets the type accessor for this object. + /// + protected TypeAccessor Accessor { get; } + + /// + /// Raises the event. + /// + /// Name of the property that changed. + protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + /// + /// Notifies all properties changed. + /// + protected void RaisePropertyChangedAll() + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty)); + } + + /// + /// Sets the to the if they are different and raise + /// for the property and other properties marked with the . + /// + /// Type of the property. + /// Old value. + /// New value. + /// Name of the property that changed. + /// True if the property changed. + protected bool SetProperty(ref T field, T newValue, [CallerMemberName] string propertyName = null) + { + if (EqualityComparer.Default.Equals(field, newValue)) + { + return false; + } + + OnPropertyChanging(propertyName); + field = newValue; + RaisePropertyChanged(propertyName); + OnPropertyChanged(propertyName); + RaiseAlsoNotify(propertyName); + return true; + } + + /// + /// Sets the property of the to the + /// if they are different and raise for the property and other properties marked with the . + /// + /// The type of the model. + /// The type of the value. + /// The model instance. + /// The property name of the model. + /// The new value to set. + /// The property name. + /// True if the property changed. + protected bool SetProperty(TModel model, string modelPropertyName, TValue newValue, [CallerMemberName] string propertyName = null) + { + if (!_modelToAccessor.ContainsKey(model)) + { + _modelToAccessor.Add(model, ObjectAccessor.Create(model)); + } + + var currentModelValue = (TValue)_modelToAccessor[model][modelPropertyName]; + if (EqualityComparer.Default.Equals(currentModelValue, newValue)) + { + return false; + } + + OnPropertyChanging(propertyName); + _modelToAccessor[model][modelPropertyName] = newValue; + RaisePropertyChanged(propertyName); + OnPropertyChanged(propertyName); + RaiseAlsoNotify(propertyName); + return true; + } + + /// + /// Override this method to handle the event when a property is changing. + /// + /// The name of the property that is changing. + protected virtual void OnPropertyChanging(string propertyName) + { + } + + /// + /// Override this method to handle the event when a property was changed. + /// + /// The name of the property that changed. + protected virtual void OnPropertyChanged(string propertyName) + { + } + + private void SetupAlsoNotify() + { + var alsoNotifyProperties = Accessor.GetMembers().Where(m => m.IsDefined(typeof(AlsoNotifyAttribute))); + foreach (var propertyInfo in alsoNotifyProperties) + { + var attr = (AlsoNotifyAttribute)propertyInfo.GetAttribute(typeof(AlsoNotifyAttribute), true); + _alsoNotifyMap.Add(propertyInfo.Name, attr.AlsoNotify); + } + } + + private void RaiseAlsoNotify(string propertyName) + { + if (!_alsoNotifyMap.TryGetValue(propertyName, out var alsoNotify)) + { + return; + } + + foreach (var alsoNotifyPropertyName in alsoNotify) + { + OnPropertyChanging(alsoNotifyPropertyName); + RaisePropertyChanged(alsoNotifyPropertyName); + OnPropertyChanged(alsoNotifyPropertyName); + } + } + } +} diff --git a/src/AudioBand/Resources/ButtonStyles.xaml b/src/AudioBand/Resources/ButtonStyles.xaml index 8a69c0b5..2270cb46 100644 --- a/src/AudioBand/Resources/ButtonStyles.xaml +++ b/src/AudioBand/Resources/ButtonStyles.xaml @@ -1,49 +1,57 @@  + xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> - + - + - - @@ -189,35 +221,36 @@ - + + Opacity="0" /> + Opacity="1" /> + Width="{TemplateBinding Height}" + Height="{TemplateBinding Height}" + HorizontalAlignment="Left"> + Fill="{theme:ThemeResource SystemBaseHighColor}" /> @@ -241,7 +274,7 @@ - + @@ -250,7 +283,7 @@ - + @@ -258,7 +291,7 @@ - + @@ -272,24 +305,24 @@ - - diff --git a/src/AudioBand/Resources/ComboBoxStyles.xaml b/src/AudioBand/Resources/ComboBoxStyles.xaml index 6a7ae951..9384e96e 100644 --- a/src/AudioBand/Resources/ComboBoxStyles.xaml +++ b/src/AudioBand/Resources/ComboBoxStyles.xaml @@ -4,38 +4,41 @@ xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> - - + + - - - - + + + - + \ No newline at end of file diff --git a/src/AudioBand/Resources/ContextMenuStyles.xaml b/src/AudioBand/Resources/ContextMenuStyles.xaml index 546bf264..47b00804 100644 --- a/src/AudioBand/Resources/ContextMenuStyles.xaml +++ b/src/AudioBand/Resources/ContextMenuStyles.xaml @@ -1,44 +1,56 @@  + xmlns:resources="clr-namespace:AudioBand.Resources" + xmlns:sys="clr-namespace:System;assembly=mscorlib" + xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> - + - + diff --git a/src/AudioBand/Resources/Icons.xaml b/src/AudioBand/Resources/Icons.xaml index 71f04b5d..9ccd6b71 100644 --- a/src/AudioBand/Resources/Icons.xaml +++ b/src/AudioBand/Resources/Icons.xaml @@ -1,7 +1,7 @@  12 @@ -10,15 +10,25 @@ - + - + - + @@ -31,13 +41,21 @@ - + - + @@ -51,7 +69,11 @@ - + @@ -64,13 +86,21 @@ - + - + @@ -84,20 +114,34 @@ - + - + - + - + @@ -110,23 +154,37 @@ - + - + - + - + - + @@ -142,29 +200,47 @@ - + - + - + - + - + - + @@ -178,13 +254,27 @@ - + - + @@ -202,42 +292,70 @@ - + - + - + - + - + - + - + - + @@ -250,12 +368,20 @@ - + - + @@ -268,27 +394,47 @@ - + - + - + - + - + diff --git a/src/AudioBand/Resources/NavigationPaneStyles.xaml b/src/AudioBand/Resources/NavigationPaneStyles.xaml index 6ce96978..406063ab 100644 --- a/src/AudioBand/Resources/NavigationPaneStyles.xaml +++ b/src/AudioBand/Resources/NavigationPaneStyles.xaml @@ -1,73 +1,88 @@  + xmlns:local="clr-namespace:AudioBand.Resources" + xmlns:theme="clr-namespace:AudioBand.Resources.Theming" + xmlns:valueConverters="clr-namespace:AudioBand.ValueConverters"> - + \ No newline at end of file diff --git a/src/AudioBand/Resources/NumericInputStyles.xaml b/src/AudioBand/Resources/NumericInputStyles.xaml index dbadac0b..ee33dd00 100644 --- a/src/AudioBand/Resources/NumericInputStyles.xaml +++ b/src/AudioBand/Resources/NumericInputStyles.xaml @@ -1,34 +1,34 @@  - + - diff --git a/src/AudioBand/Resources/PasswordBoxStyles.xaml b/src/AudioBand/Resources/PasswordBoxStyles.xaml index fbbb3945..1ef1e1d7 100644 --- a/src/AudioBand/Resources/PasswordBoxStyles.xaml +++ b/src/AudioBand/Resources/PasswordBoxStyles.xaml @@ -4,41 +4,46 @@ xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:theming="clr-namespace:AudioBand.Resources.Theming"> - - + + - \ No newline at end of file diff --git a/src/AudioBand/Resources/ScrollbarStyle.xaml b/src/AudioBand/Resources/ScrollbarStyle.xaml index 27ba6fe7..48094ac3 100644 --- a/src/AudioBand/Resources/ScrollbarStyle.xaml +++ b/src/AudioBand/Resources/ScrollbarStyle.xaml @@ -1,8 +1,8 @@  + xmlns:sys="clr-namespace:System;assembly=mscorlib" + xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> 14 0:0:0.1 0:0:0.3 @@ -16,6 +16,12 @@ + @@ -42,9 +48,6 @@ - - @@ -70,23 +73,23 @@ - + - + - + - + - + @@ -98,53 +101,83 @@ - - - + + + - + - + - + - + - + - - - - + + + + - - - - + + + + @@ -160,19 +193,27 @@ - - + + - + - + - + - + diff --git a/src/AudioBand/Resources/SettingsWindowStyle.xaml b/src/AudioBand/Resources/SettingsWindowStyle.xaml index 40b30c29..24a6cf30 100644 --- a/src/AudioBand/Resources/SettingsWindowStyle.xaml +++ b/src/AudioBand/Resources/SettingsWindowStyle.xaml @@ -1,35 +1,35 @@  + xmlns:sys="clr-namespace:System;assembly=mscorlib"> - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - \ No newline at end of file diff --git a/src/AudioBand/Resources/Shared.xaml b/src/AudioBand/Resources/Shared.xaml index 81972fe7..3623125d 100644 --- a/src/AudioBand/Resources/Shared.xaml +++ b/src/AudioBand/Resources/Shared.xaml @@ -1,16 +1,20 @@  + xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> - + 2 - + #88FFFFFF 32 32 @@ -21,61 +25,60 @@ 34 30 18 - + - - - + + + - - - + + + - - + + - + - + - + - + 0.6 - + - - + + - - - + + + - - - + + + diff --git a/src/AudioBand/Resources/Strings.xaml b/src/AudioBand/Resources/Strings.xaml index b537eb93..e6a9b5e5 100644 --- a/src/AudioBand/Resources/Strings.xaml +++ b/src/AudioBand/Resources/Strings.xaml @@ -1,7 +1,7 @@  - + Width Height Visibility @@ -21,14 +21,14 @@ Background color Change the relative positioning of the control - + Play button content Pause button content - + Button content - + Button Image Button image when hovered Button image when clicked @@ -37,16 +37,16 @@ Select the font family for the text Button text - + Repeat off button content Repeat on button content Repeat track button content - + Shuffle off button content Shuffle on button content - + Label name Choose a name for the label Font Family @@ -70,7 +70,8 @@ Placeholders will be substituted with their corresponding values. Placeholders a • song - The title of the current song • album - Album name for the current song • time - Current playback time for the current song -• length - Total length of the current song +• length - Total length of the current song +• remaining - The remaining time left in current song • * - Bolds the placeholder • & - Italicizes the placeholder • _ - Underlines the placeholder @@ -80,7 +81,7 @@ Showing the album name in bold : {*album} Showing the song progress in gray : {time:#A9A9A9} : {length:#A9A9A9} Using style and color : {*artist:#a9a9a9} - + General Playback Controls Play/Pause Button @@ -98,7 +99,7 @@ Using style and color : {*artist:#a9a9a9} Add a new label Delete this label - + Reset Settings Browse Default @@ -118,17 +119,17 @@ Using style and color : {*artist:#a9a9a9} This setting will be saved. Are you sure? Remember - + Colors Foreground color Background color Background color when hovered - + Image Placeholder image - + About AudioBand Delete label Are you sure you want to delete the label '{0}'? @@ -144,7 +145,7 @@ Using style and color : {*artist:#a9a9a9} Delete profile Are you sure you want to delete the profile '{0}' - + New profile Delete the current profile Rename the current profile @@ -152,7 +153,7 @@ Using style and color : {*artist:#a9a9a9} Export profiles Default Profile - + Click here to reset No image selected \ No newline at end of file diff --git a/src/AudioBand/Resources/TextBoxStyles.xaml b/src/AudioBand/Resources/TextBoxStyles.xaml index 50dedff0..3cc1caff 100644 --- a/src/AudioBand/Resources/TextBoxStyles.xaml +++ b/src/AudioBand/Resources/TextBoxStyles.xaml @@ -5,41 +5,46 @@ xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> - - + + - - - - \ No newline at end of file diff --git a/src/AudioBand/Resources/ToolbarButtonStyles.xaml b/src/AudioBand/Resources/ToolbarButtonStyles.xaml index a8d09a04..4d34c0fc 100644 --- a/src/AudioBand/Resources/ToolbarButtonStyles.xaml +++ b/src/AudioBand/Resources/ToolbarButtonStyles.xaml @@ -1,22 +1,32 @@  - - + + - - + + @@ -25,8 +35,7 @@ - + @@ -35,10 +44,9 @@ - + - + @@ -48,10 +56,9 @@ - + - + @@ -61,10 +68,8 @@ - - + + @@ -73,11 +78,13 @@ - - + + - + @@ -88,12 +95,23 @@ - - + + - + @@ -109,11 +127,11 @@ - - - - - + + + + + @@ -122,17 +140,19 @@ - - - - - + + + + + - + @@ -141,12 +161,12 @@ 0:0:0.1 - + - - + + @@ -156,8 +176,8 @@ - - + + @@ -166,8 +186,8 @@ - - + + @@ -176,111 +196,116 @@ - + - + - + - - + + - + - + - + - + - + diff --git a/src/AudioBand/Resources/ToolbarContextMenuStyles.xaml b/src/AudioBand/Resources/ToolbarContextMenuStyles.xaml index e924fa45..64e203e3 100644 --- a/src/AudioBand/Resources/ToolbarContextMenuStyles.xaml +++ b/src/AudioBand/Resources/ToolbarContextMenuStyles.xaml @@ -2,29 +2,34 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:fluentWpf="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"> #44FFFFFF - + #44ffffff - + #AA000000 - + + None diff --git a/src/AudioBand/Resources/ToolbarProgressBarStyle.xaml b/src/AudioBand/Resources/ToolbarProgressBarStyle.xaml index 0a58a863..4196431a 100644 --- a/src/AudioBand/Resources/ToolbarProgressBarStyle.xaml +++ b/src/AudioBand/Resources/ToolbarProgressBarStyle.xaml @@ -1,28 +1,28 @@  - + - + - + Style="{StaticResource SliderRepeatButtonStyle}" /> - + Style="{StaticResource SliderRepeatButtonStyle}" /> - + - + 3 @@ -86,7 +94,7 @@ - + 3 @@ -103,7 +111,9 @@ + From="0" + To="1" + Duration="0:0:0.1" /> @@ -114,7 +124,9 @@ + From="1" + To="0" + Duration="0:0:0.1" /> @@ -127,11 +139,11 @@ - - - - - + + + + + diff --git a/src/AudioBand/Resources/Tooltips.xaml b/src/AudioBand/Resources/Tooltips.xaml index a6b8e039..ee3ea34a 100644 --- a/src/AudioBand/Resources/Tooltips.xaml +++ b/src/AudioBand/Resources/Tooltips.xaml @@ -1,23 +1,26 @@  + xmlns:resources="clr-namespace:AudioBand.Resources" + xmlns:theme="clr-namespace:AudioBand.Resources.Theming"> - + - + - + - @@ -167,13 +191,15 @@ - + - + TextOverflow="{Binding TextOverflow}" /> - - - + - + Opacity="0" + TextAlignment="{Binding TextAlignment, Converter={x:Static converters:Converters.TextAlignment}}" + TextTrimming="None" + TextWrapping="NoWrap" + Visibility="{Binding IsVisible, Converter={x:Static converters:Converters.BoolToVisibility}}" /> diff --git a/src/AudioBand/Views/Dialogs/AboutDialog.xaml b/src/AudioBand/Views/Dialogs/AboutDialog.xaml index 0802041b..40f17494 100644 --- a/src/AudioBand/Views/Dialogs/AboutDialog.xaml +++ b/src/AudioBand/Views/Dialogs/AboutDialog.xaml @@ -1,43 +1,47 @@  + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" + xmlns:behaviors="clr-namespace:AudioBand.Behaviors" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:resources="clr-namespace:AudioBand.Resources" + xmlns:theme="clr-namespace:AudioBand.Resources.Theming" + xmlns:viewmodels="clr-namespace:AudioBand.ViewModels" + Title="About Audio Band" + Width="600" + Height="500" + d:DesignHeight="450" + d:DesignWidth="800" + Background="{theme:ThemeResource SystemAltHighColor}" + Foreground="{theme:ThemeResource SystemBaseHighColor}" + Icon="pack://application:,,,/AudioBand;component/audioband.ico" + WindowStartupLocation="CenterScreen" + mc:Ignorable="d"> - - + + - - + + - + - - + + - + @@ -53,57 +57,77 @@ - - + + - - + + - + - + - - + - - - + + + - - + + - - + + - + - + - + - - diff --git a/src/AudioBand/Views/Settings/CustomLabelSettingsView.xaml b/src/AudioBand/Views/Settings/CustomLabelSettingsView.xaml index c882d5d0..81df32ce 100644 --- a/src/AudioBand/Views/Settings/CustomLabelSettingsView.xaml +++ b/src/AudioBand/Views/Settings/CustomLabelSettingsView.xaml @@ -1,47 +1,54 @@  + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:behaviors="clr-namespace:AudioBand.Behaviors" + xmlns:converters="clr-namespace:AudioBand.ValueConverters" + xmlns:local="clr-namespace:AudioBand.Views.Settings" + xmlns:metro="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:models="clr-namespace:AudioBand.Models" + xmlns:resources="clr-namespace:AudioBand.Resources" + xmlns:theming="clr-namespace:AudioBand.Resources.Theming" + xmlns:viewmodels="clr-namespace:AudioBand.ViewModels"> - - - - - + + + + + - - - - + + + + - - - . + + + + . - + - - + + @@ -51,9 +58,8 @@ - - + + @@ -62,74 +68,116 @@ - - - + + + - + - - - Tags - - Styles - - Colors - - Example formats - + + + Tags + + Styles + + Colors + + Example formats + - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - + - + Style="{StaticResource NavigationPaneRadioButton}"> - - - + + + - - - @@ -201,27 +250,33 @@ - + - + - + - + Style="{StaticResource NavigationPaneRadioButton}"> - - + + - - + + @@ -230,136 +285,162 @@ - - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/AudioBand/Views/Settings/SettingsWindow.xaml.cs b/src/AudioBand/Views/Settings/SettingsWindow.xaml.cs index 9e6fc268..5c966254 100644 --- a/src/AudioBand/Views/Settings/SettingsWindow.xaml.cs +++ b/src/AudioBand/Views/Settings/SettingsWindow.xaml.cs @@ -70,7 +70,7 @@ private void OnActivated(object sender, EventArgs e) _messageBus.Publish(FocusChangedMessage.FocusCaptured); } - private void OpenAboutCommandOnExecute(object o) + private void OpenAboutCommandOnExecute() { _dialogService.ShowAboutDialog(); } diff --git a/src/AudioBand/Views/Settings/ShuffleModeButtonSettingsView.xaml b/src/AudioBand/Views/Settings/ShuffleModeButtonSettingsView.xaml index 79416597..9b589099 100644 --- a/src/AudioBand/Views/Settings/ShuffleModeButtonSettingsView.xaml +++ b/src/AudioBand/Views/Settings/ShuffleModeButtonSettingsView.xaml @@ -1,32 +1,43 @@  + xmlns:resources="clr-namespace:AudioBand.Resources" + xmlns:viewmodels="clr-namespace:AudioBand.ViewModels"> - - - - + + + + - + - - + + - - + + - +