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)
+
-