diff --git a/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs new file mode 100644 index 00000000..ed16bb62 --- /dev/null +++ b/AudioCuesheetEditor.Tests/Services/UI/ApplicationOptionsTimeSpanParserTests.cs @@ -0,0 +1,118 @@ +//This file is part of AudioCuesheetEditor. + +//AudioCuesheetEditor is free software: you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. + +//AudioCuesheetEditor is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. + +//You should have received a copy of the GNU General Public License +//along with Foobar. If not, see +//. +using AudioCuesheetEditor.Data.Options; +using AudioCuesheetEditor.Model.AudioCuesheet; +using AudioCuesheetEditor.Model.Options; +using AudioCuesheetEditor.Services.UI; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using System; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace AudioCuesheetEditor.Tests.Services.UI +{ + [TestClass()] + public class ApplicationOptionsTimeSpanParserTests + { + [TestMethod] + public async Task TimespanTextChanged_ValidInput_SetsPropertyCorrectly() + { + // Arrange + var options = new ApplicationOptions() + { + TimeSpanFormat = new() + { + Scheme = "Minutes:Seconds" + } + }; + var mockOptionsProvider = new Mock(); + mockOptionsProvider + .Setup(p => p.GetOptions()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + await Task.Delay(50); + var track = new Track(); + // Act + await parser.TimespanTextChanged(track, x => x.Begin, "92:12"); + // Assert + Assert.AreEqual(new TimeSpan(1, 32, 12), track.Begin); + } + + [TestMethod] + public async Task TimespanTextChanged_InvalidInput_SetsNull() + { + var options = new ApplicationOptions() + { + TimeSpanFormat = new() + { + Scheme = "Minutes:Seconds" + } + }; + var mockOptionsProvider = new Mock(); + mockOptionsProvider + .Setup(p => p.GetOptions()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + await Task.Delay(50); + var track = new Track(); + // Act + await parser.TimespanTextChanged(track, x => x.End, "not a time"); + // Assert + Assert.IsNull(track.End); + } + + [TestMethod()] + public async Task GetTimespanFormatted_ValidFormat_ReturnsCorrectString() + { + // Arrange + var options = new ApplicationOptions() + { + DisplayTimeSpanFormat = @"hh\:mm\:ss" + }; + var mockOptionsProvider = new Mock(); + mockOptionsProvider + .Setup(p => p.GetOptions()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + await Task.Delay(50); + // Act + var result = parser.GetTimespanFormatted(new TimeSpan(0, 1, 30, 27, 200, 103)); + // Assert + Assert.AreEqual("01:30:27", result); + } + + [TestMethod()] + public async Task GetTimespanFormatted_InvalidFormat_FallbackToDefault() + { + // Arrange + var options = new ApplicationOptions() + { + DisplayTimeSpanFormat = "INVALID_FORMAT" + }; + var mockOptionsProvider = new Mock(); + mockOptionsProvider + .Setup(p => p.GetOptions()) + .ReturnsAsync(options); + var parser = new ApplicationOptionsTimeSpanParser(mockOptionsProvider.Object); + await Task.Delay(50); + // Act + var result = parser.GetTimespanFormatted(new TimeSpan(0, 1, 30, 27, 200, 103)); + // Assert + Assert.AreEqual("01:30:27.2001030", result); + } + } +} \ No newline at end of file diff --git a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs index 41fc8618..39ee60c5 100644 --- a/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs +++ b/AudioCuesheetEditor/Model/Options/ApplicationOptions.cs @@ -105,6 +105,7 @@ public String? ProjectFilename public TimeSpanFormat ImportTimeSpanFormat { get; set; } = new(); public uint RecordCountdownTimer { get; set; } = 5; public Boolean FixedTracksTableHeader { get; set; } = false; + public String? DisplayTimeSpanFormat { get; set; } public override ValidationResult Validate(string property) { diff --git a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs index f6b16cd9..75f14604 100644 --- a/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs +++ b/AudioCuesheetEditor/Services/UI/ApplicationOptionsTimeSpanParser.cs @@ -56,6 +56,23 @@ public async Task TimespanTextChanged(T entity, Expression + MultiSelection SelectOnRowClick="false" @bind-SelectedItems="selectedSections"> - + - + @@ -73,7 +73,7 @@ MultiSelection SelectOnRowClick="false" @bind-SelectedItems="selectedSections"> x.MimeType))" - DisplayMenu="false" /> + DisplayMenu="false" /> diff --git a/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.de.resx b/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.de.resx index 96e7a42a..1b166b0f 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.de.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.de.resx @@ -126,6 +126,9 @@ Tage + + Anzeige + Stunden @@ -141,7 +144,13 @@ Sekunden + + Anzeigeformat Zeit + Eingabeformat Zeit + + Benutzt .NET format, bitte prüfen sie die Hilfe für mehr Informationen + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.razor index 01b2f196..79f61efb 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.razor @@ -22,12 +22,13 @@ along with Foobar. If not, see - @_localizer["Input"] - + @_localizer["Input"] + + Clearable Error="String.IsNullOrEmpty(GetValidationErrorMessage(ApplicationOptions?.TimeSpanFormat, nameof(TimeSpanFormat.Scheme))) == false" + ErrorText="@GetValidationErrorMessage(ApplicationOptions?.TimeSpanFormat, nameof(TimeSpanFormat.Scheme))" Variant="Variant.Outlined" /> @foreach(var scheme in TimeSpanFormat.AvailableTimespanScheme) { @@ -35,6 +36,9 @@ along with Foobar. If not, see } + @_localizer["Display"] + @@ -59,6 +63,11 @@ along with Foobar. If not, see await LocalStorageOptionsProvider.SaveOptionsValue(x => x.TimeSpanFormat!, timeSpanFormat); } + async Task DisplayTimeSpanFormatChangedAsync(string newValue) + { + await LocalStorageOptionsProvider.SaveOptionsValue(x => x.DisplayTimeSpanFormat, newValue); + } + void AppendPlaceholderToTimeInputFormatTextField(string placeholder) { timeInputFormatTextField?.SetText($"{timeInputFormatTextField.Text}{placeholder}"); diff --git a/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.resx b/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.resx index 0dbee054..3efb8245 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/OptionsDialog.resx @@ -126,6 +126,9 @@ Days + + Display + Hours @@ -141,7 +144,13 @@ Seconds + + Time display format + Time input format + + Uses .NET format, check help for more information + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor b/AudioCuesheetEditor/Shared/TrackList/TrackList.razor index 975bc9fb..e4ac53c1 100644 --- a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor +++ b/AudioCuesheetEditor/Shared/TrackList/TrackList.razor @@ -115,20 +115,29 @@ along with Foobar. If not, see + + @_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.Begin) + - + + @_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.End) + - + + @_applicationOptionsTimeSpanParser.GetTimespanFormatted(context.Item.Length) + -