From 98c36a1fdf3abcd60173433e2d251aac034507bc Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Thu, 24 Sep 2026 11:28:16 +0200 Subject: [PATCH 01/67] Update AudioCuesheetEditor.csproj --- AudioCuesheetEditor/AudioCuesheetEditor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index 0ee729b8..ff3606aa 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -7,7 +7,7 @@ enable https://github.com/NeoCoderMatrix86/AudioCuesheetEditor Latest - 13.1.0 + 13.2.0 false true true From d36a2aa4dd682e50bf0d97a8a30ffe240e47a68e Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Thu, 24 Sep 2026 11:33:21 +0200 Subject: [PATCH 02/67] update libraries --- .../AudioCuesheetEditor.End2EndTests.csproj | 2 +- AudioCuesheetEditor/AudioCuesheetEditor.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj b/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj index a7d3d6c0..6b8d48c1 100644 --- a/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj +++ b/AudioCuesheetEditor.End2EndTests/AudioCuesheetEditor.End2EndTests.csproj @@ -24,7 +24,7 @@ - + diff --git a/AudioCuesheetEditor/AudioCuesheetEditor.csproj b/AudioCuesheetEditor/AudioCuesheetEditor.csproj index ff3606aa..757d9745 100644 --- a/AudioCuesheetEditor/AudioCuesheetEditor.csproj +++ b/AudioCuesheetEditor/AudioCuesheetEditor.csproj @@ -33,7 +33,7 @@ - + From 0bdd3ef1ff0cb9ccd2546194cbdaa024509b143c Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Fri, 25 Sep 2026 14:54:43 +0200 Subject: [PATCH 03/67] Update Audiofiles.razor --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 29222814..a267201a 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -64,6 +64,7 @@ along with Foobar. If not, see @code { + //TODO: Redesign title content [Parameter] [EditorRequired] public Cuesheet? Cuesheet { get; set; } From 08f56c80d59485c1f7e3ac4ae8fd0fe1910257f1 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 28 Sep 2026 09:08:01 +0200 Subject: [PATCH 04/67] moved clearing to seperate method --- .../AudioCuesheet/AudiofileManagerTests.cs | 12 +++-- .../AudioCuesheet/AudiofileManager.cs | 54 ++++++++++--------- .../AudioCuesheet/IAudiofileManager.cs | 8 ++- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs index 73565f58..1349c6d4 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs @@ -78,7 +78,7 @@ public AudiofileManagerTests() } [TestMethod] - public async Task SetPropertiesAsync_EmptyBrowserFile_ShouldClearPropertiesAsync() + public async Task ClearPropertiesAsync_ValidBrowserFile_ShouldClearPropertiesAsync() { // Arrange var audiofile = new Audiofile @@ -98,7 +98,7 @@ public async Task SetPropertiesAsync_EmptyBrowserFile_ShouldClearPropertiesAsync }; var expectedUrl = audiofile.ObjectURL; // Act - await _audiofileManager.SetPropertiesAsync(audiofile, null, string.Empty); + await _audiofileManager.ClearPropertiesAsync(audiofile); // Assert Assert.IsNull(audiofile.AudioCodec); Assert.IsNull(audiofile.Name); @@ -106,6 +106,8 @@ public async Task SetPropertiesAsync_EmptyBrowserFile_ShouldClearPropertiesAsync Assert.IsNull(audiofile.Duration); Assert.IsTrue(audiofileChangedFired); _jsRuntime.Verify(js => js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); } [TestMethod] @@ -201,7 +203,7 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() } [TestMethod] - public async Task SetPropertiesAsync_NullBrowserFile_WithExistingObjectUrl_ShouldRevokeObjectUrl() + public async Task ClearPropertiesAsync_WithExistingObjectUrl_ShouldRevokeObjectUrl() { // Arrange var audiofile = new Audiofile @@ -218,12 +220,14 @@ public async Task SetPropertiesAsync_NullBrowserFile_WithExistingObjectUrl_Shoul } }; // Act - await _audiofileManager.SetPropertiesAsync(audiofile, null, string.Empty); + await _audiofileManager.ClearPropertiesAsync(audiofile); // Assert Assert.IsTrue(audiofileChangedFired); _jsRuntime.Verify(js =>js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)),Times.Once); Assert.IsNull(audiofile.ObjectURL); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); } [TestMethod] diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index 1c0bd31d..a0760fe7 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -17,6 +17,7 @@ using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Services.IO; using AudioCuesheetEditor.Services.UI; +using AudioCuesheetEditor.Shared.Cuesheet; using Microsoft.AspNetCore.Components.Forms; using Microsoft.JSInterop; using System.Linq.Expressions; @@ -36,36 +37,37 @@ public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeMa public event EventHandler? AudiofileChanged; /// - public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId) + public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile, string fileInputId) { _traceChangeManager.BulkEdit = true; - if (browserFile == null) - { - if (string.IsNullOrEmpty(audiofile.ObjectURL) == false) - { - await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); - } - SetValue(audiofile, x => x.AudioCodec, null); - SetValue(audiofile, x => x.Name, null); - SetValue(audiofile, x => x.ObjectURL, null); - SetValue(audiofile, x => x.Duration, null); - } - else + var codec = _fileInputManager.GetAudioCodec(browserFile.ContentType, browserFile.Name); + var objectUrl = await _fileInputManager.GetObjectUrlAsync(fileInputId); + TimeSpan? duration = null; + if (String.IsNullOrEmpty(objectUrl) == false) + { + var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", objectUrl); + duration = TimeSpan.FromSeconds(durationSeconds); + } + SetValue(audiofile, x => x.AudioCodec, codec); + SetValue(audiofile, x => x.Name, browserFile.Name); + SetValue(audiofile, x => x.ObjectURL, objectUrl); + SetValue(audiofile, x => x.Duration, duration); + SetLastTrackEnd(audiofile); + _traceChangeManager.BulkEdit = false; + } + + /// + public async Task ClearPropertiesAsync(Audiofile audiofile) + { + _traceChangeManager.BulkEdit = true; + if (string.IsNullOrEmpty(audiofile.ObjectURL) == false) { - var codec = _fileInputManager.GetAudioCodec(browserFile.ContentType, browserFile.Name); - var objectUrl = await _fileInputManager.GetObjectUrlAsync(fileInputId); - TimeSpan? duration = null; - if (String.IsNullOrEmpty(objectUrl) == false) - { - var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", objectUrl); - duration = TimeSpan.FromSeconds(durationSeconds); - } - SetValue(audiofile, x => x.AudioCodec, codec); - SetValue(audiofile, x => x.Name, browserFile.Name); - SetValue(audiofile, x => x.ObjectURL, objectUrl); - SetValue(audiofile, x => x.Duration, duration); - SetLastTrackEnd(audiofile); + await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); } + SetValue(audiofile, x => x.AudioCodec, null); + SetValue(audiofile, x => x.Name, null); + SetValue(audiofile, x => x.ObjectURL, null); + SetValue(audiofile, x => x.Duration, null); _traceChangeManager.BulkEdit = false; } diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs index 672e938f..512a69f2 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/IAudiofileManager.cs @@ -32,7 +32,13 @@ public interface IAudiofileManager /// /// /// - Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile? browserFile, string fileInputId); + Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile, string fileInputId); + /// + /// Clear properties of an audiofile + /// + /// + /// + Task ClearPropertiesAsync(Audiofile audiofile); /// /// Set property for an audio file /// From 0a86685506f8a6f0dfc99fd43181cd8fbb38b63e Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 28 Sep 2026 09:23:27 +0200 Subject: [PATCH 05/67] refactor audiofiles handling --- .../Shared/Cuesheet/Audiofiles.de.resx | 3 ++ .../Shared/Cuesheet/Audiofiles.razor | 31 +++++++++++++++---- .../Shared/Cuesheet/Audiofiles.resx | 3 ++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx index 1735ab5d..1b75969a 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.de.resx @@ -129,6 +129,9 @@ Neuer Dateiname + + Keine Datei hochgeladen! + Validierungsfehler diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index a267201a..c8ee4a9b 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -46,14 +46,18 @@ along with Foobar. If not, see { - - + + + @GetFileName(file) @{ var fileInputId = $"Audiofile_{Guid.NewGuid()}"; } - x.MimeType))" - FileRenameDisabled="file.Name == null" Error="file.Validate().Status == ValidationStatus.Error" /> + x.MimeType))" FilesChanged="(browserFile) => FileUploaded(browserFile, file)"> + + + + + @@ -64,7 +68,9 @@ along with Foobar. If not, see @code { - //TODO: Redesign title content + //TODO: Alert when file is invalid + //TODO: Rename file + [Parameter] [EditorRequired] public Cuesheet? Cuesheet { get; set; } @@ -82,6 +88,8 @@ along with Foobar. If not, see [Parameter] public EventCallback> SelectedFilesChanged { get; set; } + Dictionary> _fileUploads = new(); + async Task ShowInputDialog(string? initialValue) { var parameters = new DialogParameters @@ -125,4 +133,15 @@ along with Foobar. If not, see } SelectedFilesChanged.InvokeAsync(SelectedFiles); } + + async Task FileUploaded(IBrowserFile browserFile, Audiofile audiofile) + { + var fileInputId = _fileUploads[audiofile].UserAttributes["identifier"]?.ToString(); + await _audiofileManager.SetPropertiesAsync(audiofile, browserFile, fileInputId!); + } + + String GetFileName(Audiofile audiofile) + { + return String.IsNullOrEmpty(audiofile.Name) ? _localizer["No file uploaded!"] : audiofile.Name; + } } diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx index 7c5456d4..7f62ef36 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.resx @@ -129,6 +129,9 @@ New file name + + No file uploaded! + Validation errors From 70b9c915ba226f2727619a5479ef494a6b7e8d0b Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 28 Sep 2026 10:36:41 +0200 Subject: [PATCH 06/67] add alert for validation errors --- .../Model/Entity/ValidationMessage.de.resx | 3 + .../Model/Entity/ValidationMessage.resx | 3 + .../Shared/Cuesheet/Audiofiles.razor | 17 +-- .../Shared/TrackList/TrackList.razor | 11 -- .../Shared/Validation/Alert.de.resx | 123 ++++++++++++++++++ .../Shared/Validation/Alert.razor | 38 ++++++ .../Shared/Validation/Alert.resx | 123 ++++++++++++++++++ AudioCuesheetEditor/_Imports.razor | 1 + 8 files changed, 296 insertions(+), 23 deletions(-) create mode 100644 AudioCuesheetEditor/Shared/Validation/Alert.de.resx create mode 100644 AudioCuesheetEditor/Shared/Validation/Alert.razor create mode 100644 AudioCuesheetEditor/Shared/Validation/Alert.resx diff --git a/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx b/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx index 2f6686f8..fe1d904c 100644 --- a/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx +++ b/AudioCuesheetEditor/Model/Entity/ValidationMessage.de.resx @@ -216,4 +216,7 @@ {0}({1},{2},{3},{4},{5}) überlappt mit {0}({6},{7},{8},{9},{10}). Bitte stellen Sie sicher, dass die Zeitspanne nur einmal genutzt wird! + + Audio codec + \ No newline at end of file diff --git a/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx b/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx index 95e63d1c..6546ba73 100644 --- a/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx +++ b/AudioCuesheetEditor/Model/Entity/ValidationMessage.resx @@ -216,4 +216,7 @@ {0}({1},{2},{3},{4},{5}) is overlapping with {0}({6},{7},{8},{9},{10}). Please make shure the timeinterval is only used once! + + Audio codec + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index c8ee4a9b..8c534c0b 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -27,17 +27,7 @@ along with Foobar. If not, see case ViewMode.DetailView: case ViewMode.ImportView: var validationResult = Cuesheet?.Validate(nameof(Cuesheet.Audiofiles)); - if (validationResult?.Status == ValidationStatus.Error) - { - - @_localizer["Validation errors"] - @foreach (var message in validationResult.ValidationMessages) - { - @message.GetMessageLocalized(_validationMessageLocalizer) - } - -
- } + break; } @@ -46,6 +36,10 @@ along with Foobar. If not, see { + @{ + var validationResult = file.Validate(); + + } @GetFileName(file) @@ -68,7 +62,6 @@ along with Foobar. If not, see @code { - //TODO: Alert when file is invalid //TODO: Rename file [Parameter] diff --git a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor b/AudioCuesheetEditor/Shared/TrackList/TrackList.razor index 1fd92657..f2085a8a 100644 --- a/AudioCuesheetEditor/Shared/TrackList/TrackList.razor +++ b/AudioCuesheetEditor/Shared/TrackList/TrackList.razor @@ -34,17 +34,6 @@ along with Foobar. If not, see { case ViewMode.DetailView: case ViewMode.ImportView: - var validationResult = Audiofile?.Validate(nameof(Audiofile.Tracks)); - if (validationResult?.Status == ValidationStatus.Error) - { - - @_localizer["Validation errors"] - @foreach (var message in validationResult.ValidationMessages) - { - @message.GetMessageLocalized(_validationMessageLocalizer) - } - - }
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Validierungsfehler + + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.razor b/AudioCuesheetEditor/Shared/Validation/Alert.razor new file mode 100644 index 00000000..aea720f2 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Validation/Alert.razor @@ -0,0 +1,38 @@ + +@inherits BaseLocalizedComponent + +@inject IStringLocalizer _localizer +@inject IStringLocalizer _validationMessageLocalizer + +@if (ValidationResult.Status == ValidationStatus.Error) +{ + + @_localizer["Validation errors"] + @foreach (var message in ValidationResult.ValidationMessages) + { + @message.GetMessageLocalized(_validationMessageLocalizer) + } + +} + +@code { + [EditorRequired] + [Parameter] + public ValidationResult ValidationResult { get; set; } +} diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.resx b/AudioCuesheetEditor/Shared/Validation/Alert.resx new file mode 100644 index 00000000..3db25c3d --- /dev/null +++ b/AudioCuesheetEditor/Shared/Validation/Alert.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Validation errors + + \ No newline at end of file diff --git a/AudioCuesheetEditor/_Imports.razor b/AudioCuesheetEditor/_Imports.razor index 41555c08..d815267e 100644 --- a/AudioCuesheetEditor/_Imports.razor +++ b/AudioCuesheetEditor/_Imports.razor @@ -22,6 +22,7 @@ @using AudioCuesheetEditor.Shared.Audio @using AudioCuesheetEditor.Shared.Record @using AudioCuesheetEditor.Shared.Export +@using AudioCuesheetEditor.Shared.Validation @using AudioCuesheetEditor.Model.AudioCuesheet @using AudioCuesheetEditor.Model.IO @using AudioCuesheetEditor.Model.IO.Export From 19ea5eb80925e560185369b6ddf903e4fab75d6f Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 28 Sep 2026 11:55:26 +0200 Subject: [PATCH 07/67] rename files --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 3 ++- AudioCuesheetEditor/Shared/Validation/Alert.razor | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 8c534c0b..22988970 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -51,6 +51,7 @@ along with Foobar. If not, see + @@ -62,7 +63,7 @@ along with Foobar. If not, see @code { - //TODO: Rename file + //TODO: Multiple uploads fail [Parameter] [EditorRequired] diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.razor b/AudioCuesheetEditor/Shared/Validation/Alert.razor index aea720f2..c0c3280e 100644 --- a/AudioCuesheetEditor/Shared/Validation/Alert.razor +++ b/AudioCuesheetEditor/Shared/Validation/Alert.razor @@ -23,12 +23,11 @@ along with Foobar. If not, see @if (ValidationResult.Status == ValidationStatus.Error) { - @_localizer["Validation errors"] @foreach (var message in ValidationResult.ValidationMessages) { - @message.GetMessageLocalized(_validationMessageLocalizer) + @message.GetMessageLocalized(_validationMessageLocalizer) } - + } @code { From d2e63f8c53f7aa24b1cb24ab3787b3f8481f0125 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 28 Sep 2026 14:33:04 +0200 Subject: [PATCH 08/67] reset file before uploading another one --- .../AudioCuesheet/AudiofileManagerTests.cs | 130 ++++++++++++------ .../AudioCuesheet/AudiofileManager.cs | 65 ++++++--- .../AudioCuesheet/IAudiofileManager.cs | 3 +- 3 files changed, 140 insertions(+), 58 deletions(-) diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs index 1349c6d4..fd788824 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs @@ -88,12 +88,12 @@ public async Task ClearPropertiesAsync_ValidBrowserFile_ShouldClearPropertiesAsy ObjectURL = "Just a test", Duration = TimeSpan.FromSeconds(120) }; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate(object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; } }; var expectedUrl = audiofile.ObjectURL; @@ -104,7 +104,7 @@ public async Task ClearPropertiesAsync_ValidBrowserFile_ShouldClearPropertiesAsy Assert.IsNull(audiofile.Name); Assert.IsNull(audiofile.ObjectURL); Assert.IsNull(audiofile.Duration); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); _jsRuntime.Verify(js => js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)), Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); @@ -127,12 +127,13 @@ public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); var audiofile = new Audiofile(); - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act @@ -143,7 +144,7 @@ public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() Assert.AreEqual(filename, audiofile.Name); Assert.AreEqual(objectUrl, audiofile.ObjectURL); Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); _fileInputManager.Verify(f => f.GetAudioCodec("audio/mpeg", filename), Times.Once); _fileInputManager.Verify(f => f.GetObjectUrlAsync(inputId), Times.Once); _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); @@ -179,12 +180,12 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() { Tracks = [track1, track2] }; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; } }; // Act @@ -196,12 +197,56 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() Assert.AreEqual(objectUrl, audiofile.ObjectURL); Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); Assert.AreEqual(TimeSpan.FromSeconds(90), track2.End); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); _fileInputManager.Verify(f => f.GetAudioCodec("audio/mpeg", filename), Times.Once); _fileInputManager.Verify(f => f.GetObjectUrlAsync(inputId), Times.Once); _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); } + [TestMethod] + public async Task SetPropertiesAsync_PreviouslySetAudiofile_ShouldClearFirstAndSetPropertiesAsync() + { + // Arrange + var objectUrl = "blob:123"; + var filename = "song.mp3"; + var inputId = "inputId"; + var browserFile = new Mock(); + browserFile.SetupGet(b => b.ContentType).Returns("audio/mpeg"); + browserFile.SetupGet(b => b.Name).Returns(filename); + + var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); + _fileInputManager.Setup(f => f.GetAudioCodec("audio/mpeg", filename)).Returns(codec); + _fileInputManager.Setup(f => f.GetObjectUrlAsync(inputId)).ReturnsAsync(objectUrl); + _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); + + var audiofile = new Audiofile + { + ObjectURL = "previouslySetObjectUrl" + }; + var audiofileChangedFired = 0; + _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) + { + if (e == audiofile) + { + audiofileChangedFired++; + } + }; + // Act + await _audiofileManager.SetPropertiesAsync(audiofile, browserFile.Object, inputId); + + // Assert + Assert.AreEqual(codec, audiofile.AudioCodec); + Assert.AreEqual(filename, audiofile.Name); + Assert.AreEqual(objectUrl, audiofile.ObjectURL); + Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); + Assert.AreEqual(1, audiofileChangedFired); + _fileInputManager.Verify(f => f.GetAudioCodec("audio/mpeg", filename), Times.Once); + _fileInputManager.Verify(f => f.GetObjectUrlAsync(inputId), Times.Once); + _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); + _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); + } + [TestMethod] public async Task ClearPropertiesAsync_WithExistingObjectUrl_ShouldRevokeObjectUrl() { @@ -211,19 +256,20 @@ public async Task ClearPropertiesAsync_WithExistingObjectUrl_ShouldRevokeObjectU ObjectURL = "just a test" }; var expectedUrl = audiofile.ObjectURL; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act await _audiofileManager.ClearPropertiesAsync(audiofile); // Assert - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); _jsRuntime.Verify(js =>js.InvokeAsync("revokeAudioObjectURL", It.Is(args => args != null && args.Length > 0 && (args[0] as string) == expectedUrl)),Times.Once); Assert.IsNull(audiofile.ObjectURL); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); @@ -238,12 +284,13 @@ public void SetProperty_ChangedName_UpdatesPropertyAndAddsTrace() { Name = "oldname.mp3" }; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act @@ -251,7 +298,7 @@ public void SetProperty_ChangedName_UpdatesPropertyAndAddsTrace() // Assert Assert.AreEqual("newname.mp3", audiofile.Name); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue!.Equals("oldname.mp3") && y.TraceableChange.PropertyName == nameof(Audiofile.Name))), Times.Once); } @@ -263,19 +310,20 @@ public void SetProperty_EqualValue_DoesntChangeProperty() { Name = "oldname.mp3" }; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act _audiofileManager.SetProperty(audiofile, x => x.Name, "oldname.mp3"); // Assert - Assert.IsFalse(audiofileChangedFired); + Assert.AreEqual(0, audiofileChangedFired); _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue!.Equals("oldname.mp3") && y.TraceableChange.PropertyName == nameof(Audiofile.Name))), Times.Never); } @@ -299,12 +347,13 @@ public void SetProperty_DurationChanged_SetsLastTrackEndAlso() Tracks = [track1, track2], }; var duration = new TimeSpan(0, 3, 37, 12); - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act @@ -313,7 +362,7 @@ public void SetProperty_DurationChanged_SetsLastTrackEndAlso() // Assert Assert.AreEqual(duration, audiofile.Duration); Assert.AreEqual(duration, track2.End); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); } [TestMethod] @@ -327,12 +376,13 @@ public void AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties() Audiofiles = [audiofile] }; _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; var track = new Track(); @@ -340,7 +390,7 @@ public void AddTrack_FirstTrack_AddsNewTrackWithCalulatedTrackProperties() _audiofileManager.AddTrack(audiofile, track); // Assert Assert.HasCount(1, audiofile.Tracks); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); Assert.AreEqual(duration, audiofile.Tracks.First().End); @@ -375,12 +425,12 @@ public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackPropertie { IsLinkedToPreviousTrack = true }; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; } }; // Act @@ -392,7 +442,7 @@ public void AddTrack_AddToPreviousTracks_AddsNewTrackWithCalulatedTrackPropertie Assert.AreEqual(duration, audiofile.Tracks.Last().End); Assert.AreEqual(cuesheet, track.Cuesheet); Assert.AreEqual(audiofile, track.Audiofile); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == tracks && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = false, Times.Once); @@ -425,18 +475,19 @@ public void AddTrack_DuringRecording_AddsNewTrackWithCalulatedTrackProperties() { IsLinkedToPreviousTrack = true }; - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act _audiofileManager.AddTrack(audiofile, track); // Assert - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); Assert.HasCount(2, audiofile.Tracks); Assert.AreEqual((ushort)2, audiofile.Tracks.Last().Position); Assert.IsNotNull(audiofile.Tracks.First().End); @@ -460,18 +511,19 @@ public void AddTrack_FirstTrackImporting_AddsNewTrackWithCalulatedTrackPropertie }; _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); var track = new Track(); - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; + } }; // Act _audiofileManager.AddTrack(audiofile, track); // Assert - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); Assert.HasCount(1, audiofile.Tracks); Assert.AreEqual((ushort)1, audiofile.Tracks.First().Position); Assert.AreEqual(TimeSpan.Zero, audiofile.Tracks.First().Begin); @@ -537,12 +589,12 @@ public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainin track4.Cuesheet = cuesheet; track5.Cuesheet = cuesheet; _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(cuesheet); - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; } }; // Act @@ -552,7 +604,7 @@ public void RemoveTracks_WithAttachedTracks_RemovesTracksAndRecalculatesRemainin Assert.Contains(track1, audiofile.Tracks); Assert.Contains(track3, audiofile.Tracks); Assert.Contains(track5, audiofile.Tracks); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); Assert.AreEqual((ushort)1, track1.Position); Assert.AreEqual(TimeSpan.Zero, track1.Begin); Assert.AreEqual(track1.End, track3.Begin); @@ -624,12 +676,12 @@ public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrack track4.Audiofile = audiofile; track5.Audiofile = audiofile; _sessionStateContainer.Setup(x => x.ActiveCuesheet).Returns(importCuesheet); - var audiofileChangedFired = false; + var audiofileChangedFired = 0; _audiofileManager.AudiofileChanged += delegate (object? sender, Audiofile e) { if (e == audiofile) { - audiofileChangedFired = true; + audiofileChangedFired++; } }; // Act @@ -645,7 +697,7 @@ public void RemoveTracks_DuringImport_RemovesTracksAndRecalculatesRemainingTrack Assert.AreEqual((ushort)2, track3.Position); Assert.AreEqual(track5.Begin, track3.End); Assert.AreEqual((ushort)3, track5.Position); - Assert.IsTrue(audiofileChangedFired); + Assert.AreEqual(1, audiofileChangedFired); Assert.AreEqual(duration, track5.End); _traceChangeManager.Verify(x => x.AddChange(It.Is(y => y.TraceableObject == audiofile && y.TraceableChange.PreviousValue == previousValue && y.TraceableChange.PropertyName == nameof(Audiofile.Tracks))), Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index a0760fe7..b13642d1 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -17,7 +17,6 @@ using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Services.IO; using AudioCuesheetEditor.Services.UI; -using AudioCuesheetEditor.Shared.Cuesheet; using Microsoft.AspNetCore.Components.Forms; using Microsoft.JSInterop; using System.Linq.Expressions; @@ -40,6 +39,10 @@ public class AudiofileManager(IFileInputManager fileInputManager, ITraceChangeMa public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFile, string fileInputId) { _traceChangeManager.BulkEdit = true; + if (String.IsNullOrEmpty(audiofile.ObjectURL) == false) + { + await ClearPropertiesAsync(audiofile, false); + } var codec = _fileInputManager.GetAudioCodec(browserFile.ContentType, browserFile.Name); var objectUrl = await _fileInputManager.GetObjectUrlAsync(fileInputId); TimeSpan? duration = null; @@ -48,34 +51,52 @@ public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFi var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", objectUrl); duration = TimeSpan.FromSeconds(durationSeconds); } - SetValue(audiofile, x => x.AudioCodec, codec); - SetValue(audiofile, x => x.Name, browserFile.Name); - SetValue(audiofile, x => x.ObjectURL, objectUrl); - SetValue(audiofile, x => x.Duration, duration); + var codecChanged = SetValue(audiofile, x => x.AudioCodec, codec); + var nameChanged = SetValue(audiofile, x => x.Name, browserFile.Name); + var objectUrlChanged = SetValue(audiofile, x => x.ObjectURL, objectUrl); + var durationChanged = SetValue(audiofile, x => x.Duration, duration); SetLastTrackEnd(audiofile); _traceChangeManager.BulkEdit = false; + if (codecChanged || nameChanged || objectUrlChanged || durationChanged) + { + AudiofileChanged?.Invoke(this, audiofile); + } } /// - public async Task ClearPropertiesAsync(Audiofile audiofile) + public async Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true) { - _traceChangeManager.BulkEdit = true; + if (setTracing) + { + _traceChangeManager.BulkEdit = true; + } if (string.IsNullOrEmpty(audiofile.ObjectURL) == false) { await _jsRuntime.InvokeVoidAsync("revokeAudioObjectURL", audiofile.ObjectURL); } - SetValue(audiofile, x => x.AudioCodec, null); - SetValue(audiofile, x => x.Name, null); - SetValue(audiofile, x => x.ObjectURL, null); - SetValue(audiofile, x => x.Duration, null); - _traceChangeManager.BulkEdit = false; + var codecChanged = SetValue(audiofile, x => x.AudioCodec, null); + var nameChanged = SetValue(audiofile, x => x.Name, null); + var objectUrlChanged = SetValue(audiofile, x => x.ObjectURL, null); + var durationChanged = SetValue(audiofile, x => x.Duration, null); + if (setTracing) + { + _traceChangeManager.BulkEdit = false; + if (codecChanged || nameChanged || objectUrlChanged || durationChanged) + { + AudiofileChanged?.Invoke(this, audiofile); + } + } } /// public void SetProperty(Audiofile audiofile, Expression> propertyExpression, TProperty value) { - SetValue(audiofile, propertyExpression, value); + var changed = SetValue(audiofile, propertyExpression, value); SetLastTrackEnd(audiofile); + if (changed) + { + AudiofileChanged?.Invoke(this, audiofile); + } } /// @@ -101,12 +122,16 @@ public void AddTrack(Audiofile audiofile, Track track, Boolean setTracing = true { track }; - SetValue(audiofile, x => x.Tracks, newValue); + var changed = SetValue(audiofile, x => x.Tracks, newValue); RecalculateTrackProperties(cuesheet!); if (setTracing) { _traceChangeManager.BulkEdit = false; } + if (changed) + { + AudiofileChanged?.Invoke(this, audiofile); + } } /// @@ -123,15 +148,19 @@ public void RemoveTracks(Audiofile audiofile, IEnumerable tracksToRemove, { _traceChangeManager.BulkEdit = true; } - SetValue(audiofile, x => x.Tracks, newValue); + var changed = SetValue(audiofile, x => x.Tracks, newValue); RecalculateTrackProperties(cuesheet!); if (setTracing) { _traceChangeManager.BulkEdit = false; } + if (changed) + { + AudiofileChanged?.Invoke(this, audiofile); + } } - void SetValue(Audiofile audiofile, Expression> propertyExpression, TProperty value) + Boolean SetValue(Audiofile audiofile, Expression> propertyExpression, TProperty value) { if (propertyExpression.Body is not MemberExpression memberExpression) { @@ -146,12 +175,12 @@ void SetValue(Audiofile audiofile, Expression /// + /// Parameter controlling if tracing should be handled by this service or by calling services /// - Task ClearPropertiesAsync(Audiofile audiofile); + Task ClearPropertiesAsync(Audiofile audiofile, Boolean setTracing = true); /// /// Set property for an audio file /// From 13ef198215dd2b9ea34fa006f30353f54fda92fd Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 29 Sep 2026 11:34:34 +0200 Subject: [PATCH 09/67] fix multiple file upload --- .../Shared/Cuesheet/Audiofiles.razor | 25 +++++++++-------- .../wwwroot/scripts/library.js | 28 +++++-------------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 22988970..211321c9 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -43,14 +43,16 @@ along with Foobar. If not, see @GetFileName(file) - @{ - var fileInputId = $"Audiofile_{Guid.NewGuid()}"; + @if (_fileInputIds.TryGetValue(file, out var fileInputId) == false) + { + _fileInputIds[file] = $"Audiofile_{Guid.NewGuid()}"; } - x.MimeType))" FilesChanged="(browserFile) => FileUploaded(browserFile, file)"> - + x.MimeType))" FilesChanged="(browserFile) => FileUploaded(browserFile, file)" Hidden> + + + - @@ -63,8 +65,6 @@ along with Foobar. If not, see @code { - //TODO: Multiple uploads fail - [Parameter] [EditorRequired] public Cuesheet? Cuesheet { get; set; } @@ -82,7 +82,7 @@ along with Foobar. If not, see [Parameter] public EventCallback> SelectedFilesChanged { get; set; } - Dictionary> _fileUploads = new(); + Dictionary _fileInputIds = new(); async Task ShowInputDialog(string? initialValue) { @@ -128,10 +128,13 @@ along with Foobar. If not, see SelectedFilesChanged.InvokeAsync(SelectedFiles); } - async Task FileUploaded(IBrowserFile browserFile, Audiofile audiofile) + async Task FileUploaded(IBrowserFile? browserFile, Audiofile audiofile) { - var fileInputId = _fileUploads[audiofile].UserAttributes["identifier"]?.ToString(); - await _audiofileManager.SetPropertiesAsync(audiofile, browserFile, fileInputId!); + if (browserFile != null) + { + var fileInputId = _fileInputIds[audiofile]; + await _audiofileManager.SetPropertiesAsync(audiofile, browserFile, fileInputId!); + } } String GetFileName(Audiofile audiofile) diff --git a/AudioCuesheetEditor/wwwroot/scripts/library.js b/AudioCuesheetEditor/wwwroot/scripts/library.js index 1e376797..364ddfc9 100644 --- a/AudioCuesheetEditor/wwwroot/scripts/library.js +++ b/AudioCuesheetEditor/wwwroot/scripts/library.js @@ -1,36 +1,22 @@ window.addEventListener('beforeunload', beforeunload); -window._audioObjectURLCache = {}; -window.getObjectURLFromMudFileUpload = function (inputOrFieldId) { - if (window._audioObjectURLCache[inputOrFieldId]) { - return window._audioObjectURLCache[inputOrFieldId]; - } +window.getObjectURLFromMudFileUpload = function (fileInputId) { - let inputElem = inputOrFieldId; - if (typeof inputOrFieldId === "string") { - inputElem = document.getElementById(inputOrFieldId) || - document.querySelector(`input[identifier="${inputOrFieldId}"]`) || - document.querySelector(`input[id="${inputOrFieldId}"]`); - } + const inputElem = document.getElementById(fileInputId) || + document.querySelector(`input[identifier="${fileInputId}"]`) || + document.querySelector(`input[id="${fileInputId}"]`); const files = inputElem.files; for (let i = 0; i < files.length; i++) { - const f = files[i]; - if (f && f.type && f.type.startsWith("audio/")) { - const newObjectURL = URL.createObjectURL(f); - window._audioObjectURLCache[inputOrFieldId] = newObjectURL; - return newObjectURL; + const file = files[i]; + if (file && file.type && file.type.startsWith("audio/")) { + return URL.createObjectURL(file); } } return null; }; window.revokeAudioObjectURL = function (objectUrl) { - Object.keys(window._audioObjectURLCache).forEach(key => { - if (window._audioObjectURLCache[key] === objectUrl) { - delete window._audioObjectURLCache[key]; - } - }); URL.revokeObjectURL(objectUrl); }; From e9bbc786629f54e7c04bb30121a067af9c8cb3ee Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 29 Sep 2026 12:56:44 +0200 Subject: [PATCH 10/67] fix basic tests --- AudioCuesheetEditor.End2EndTests/Models/DetailView.cs | 5 ++--- AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs | 2 +- .../Tests/Smartphone/BasicTest.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs index 6a9cc1dc..4199c03c 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/DetailView.cs @@ -44,7 +44,7 @@ internal async Task AddAudiofileAsync() internal async Task SetAudiofileInputFileAsync(int audiofileIndex, string file) { - await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile" }).Nth(audiofileIndex).Locator("input[type=\"file\"]").SetInputFilesAsync(file); + await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "No file uploaded!" }).Nth(audiofileIndex).Locator("input[type=\"file\"]").SetInputFilesAsync(file); } internal async Task AddTrackAsync(int audiofileIndex) @@ -116,8 +116,7 @@ internal async Task RenameAudiofileAsync(int audiofileIndex, string filename) internal async Task OpenRenameAudiofileDialogAsync(int audiofileIndex) { - await _page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile" }).Nth(audiofileIndex).GetByLabel("More").ClickAsync(); - await _page.GetByText("Rename file").ClickAsync(); + await _page.GetByRole(AriaRole.Button, new() { Name = "Rename file" }).Nth(audiofileIndex).ClickAsync(); } async Task EditTrackFieldAsync(int trackPosition, string dataLabel, string value) diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs index a8b43579..05c131ff 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs @@ -48,7 +48,7 @@ public async Task Audiofile_ShouldBeRenamed_WhenEditingFilename() await detailView.AddAudiofileAsync(); await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); await detailView.RenameAudiofileAsync(0, "Kalimba test 123.mp3"); - await Expect(TestPage.GetByRole(AriaRole.Textbox, new() { Name = "Audiofile" })).ToMatchAriaSnapshotAsync("- textbox \"Audiofile\": Kalimba test 123.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Kalimba test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Kalimba test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } [TestMethod] diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs index 212587fc..d6edfd36 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs @@ -50,7 +50,7 @@ public async Task Audiofile_ShouldBeRenamed_WhenEditingFilename() await detailView.AddAudiofileAsync(); await detailView.SetAudiofileInputFileAsync(0, "Kalimba.mp3"); await detailView.RenameAudiofileAsync(0, "Kalimba test 123.mp3"); - await Expect(TestPage.GetByRole(AriaRole.Textbox, new() { Name = "Audiofile" })).ToMatchAriaSnapshotAsync("- textbox \"Audiofile\": Kalimba test 123.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Kalimba test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Kalimba test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } [TestMethod] From dbd6a95044d24c81861ddd5453c85262bb5965a2 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 29 Sep 2026 16:20:08 +0200 Subject: [PATCH 11/67] fix import tests --- AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs | 5 +++-- .../Tests/Smartphone/ImportTest.cs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs index 6e443a41..351586a2 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs @@ -15,6 +15,7 @@ //. using AudioCuesheetEditor.End2EndTests.Models; using Microsoft.Playwright; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; namespace AudioCuesheetEditor.End2EndTests.Tests.Desktop { @@ -2431,7 +2432,7 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - rowgroup: - row"); await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Audiofiles has invalid Count (0)!" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); } [TestMethod] @@ -2626,7 +2627,7 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - rowgroup: - row"); await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Audiofiles has invalid Count (0)!" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); } [TestMethod] diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs index f5ff4614..22c05e60 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs @@ -2984,7 +2984,7 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Status - button"); await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Audiofiles has invalid Count (0)!" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); } [TestMethod] @@ -3214,7 +3214,7 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - text: Status - button"); await appBar.UndoAsync(); - await Expect(TestPage.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Audiofiles has invalid Count (0)!" })).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Tabpanel, new() { Name = "Detail view" })).ToMatchAriaSnapshotAsync("- text: Audiofiles has invalid count (0)!"); } [TestMethod] From 5d78249a802ac7733732eb0be7da0236b22543a5 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 29 Sep 2026 16:36:13 +0200 Subject: [PATCH 12/67] Update ViewModeImport.razor --- AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor index 8cd09948..3a46ff6c 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor @@ -53,6 +53,7 @@ else } @code { + //TODO: importing an audiofile doesn't set the audio codec string? importText; Boolean fapMenuOpened = false; From bcd544d7b3971d81af6b2511b2274598350b26c9 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 29 Sep 2026 16:36:18 +0200 Subject: [PATCH 13/67] Update Audiofiles.razor --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 211321c9..4d7f3a69 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -26,8 +26,7 @@ along with Foobar. If not, see { case ViewMode.DetailView: case ViewMode.ImportView: - var validationResult = Cuesheet?.Validate(nameof(Cuesheet.Audiofiles)); - + break; } @@ -36,10 +35,7 @@ along with Foobar. If not, see { - @{ - var validationResult = file.Validate(); - - } + @GetFileName(file) From e62cdca1649bd2d77dde080e1066ebbd1bc4c231 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 08:30:44 +0200 Subject: [PATCH 14/67] remove localization --- .../Shared/Validation/Alert.de.resx | 123 ------------------ .../Shared/Validation/Alert.razor | 1 - .../Shared/Validation/Alert.resx | 123 ------------------ 3 files changed, 247 deletions(-) delete mode 100644 AudioCuesheetEditor/Shared/Validation/Alert.de.resx delete mode 100644 AudioCuesheetEditor/Shared/Validation/Alert.resx diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.de.resx b/AudioCuesheetEditor/Shared/Validation/Alert.de.resx deleted file mode 100644 index 28e93047..00000000 --- a/AudioCuesheetEditor/Shared/Validation/Alert.de.resx +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Validierungsfehler - - \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.razor b/AudioCuesheetEditor/Shared/Validation/Alert.razor index c0c3280e..4741d4f2 100644 --- a/AudioCuesheetEditor/Shared/Validation/Alert.razor +++ b/AudioCuesheetEditor/Shared/Validation/Alert.razor @@ -17,7 +17,6 @@ along with Foobar. If not, see --> @inherits BaseLocalizedComponent -@inject IStringLocalizer _localizer @inject IStringLocalizer _validationMessageLocalizer @if (ValidationResult.Status == ValidationStatus.Error) diff --git a/AudioCuesheetEditor/Shared/Validation/Alert.resx b/AudioCuesheetEditor/Shared/Validation/Alert.resx deleted file mode 100644 index 3db25c3d..00000000 --- a/AudioCuesheetEditor/Shared/Validation/Alert.resx +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Validation errors - - \ No newline at end of file From 0124ebca7aeee3fbcf95b97c2f12fb8409a5c4ad Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 08:36:27 +0200 Subject: [PATCH 15/67] Update Audiofiles.razor --- AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor index 4d7f3a69..7ccffe2a 100644 --- a/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor +++ b/AudioCuesheetEditor/Shared/Cuesheet/Audiofiles.razor @@ -26,7 +26,10 @@ along with Foobar. If not, see { case ViewMode.DetailView: case ViewMode.ImportView: - + if (Cuesheet != null) + { + + } break; } From 673f451245c6943246e8b04cbfb245a54a8ae6be Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 08:51:36 +0200 Subject: [PATCH 16/67] set codec during import --- .../Services/IO/FileInputManagerTests.cs | 24 +++++++++++++++---- .../Services/IO/FileInputManager.cs | 10 ++++---- .../Services/IO/IFileInputManager.cs | 4 ++-- .../Services/IO/ImportManager.cs | 1 + 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs index 14022cca..3b920a6d 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs @@ -120,7 +120,7 @@ public void IsValidAudiofile_ReturnsTrue_WithValidAudiocodec() var contentType = "audio/wav"; // Act - var result = _service.IsValidAudiofile(contentType, fileName); + var result = _service.IsValidAudiofile(fileName, contentType); // Assert Assert.IsTrue(result); @@ -134,7 +134,7 @@ public void IsValidAudiofile_ReturnsFalse_WithInvalidAudiocodecAndExtension() var contentType = "just a fantasy"; // Act - var result = _service.IsValidAudiofile(contentType, fileName); + var result = _service.IsValidAudiofile(fileName, contentType); // Assert Assert.IsFalse(result); @@ -148,7 +148,7 @@ public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeMatches() var contentType = "audio/webm"; // Act - var result = _service.GetAudioCodec(contentType, fileName); + var result = _service.GetAudioCodec(fileName, contentType); // Assert Assert.IsNotNull(result); @@ -163,7 +163,7 @@ public void GetAudioCodec_ReturnsAudiocodec_WhenContentTypeAndFileExtensionMatch var contentType = "audio/webm"; // Act - var result = _service.GetAudioCodec(contentType, fileName); + var result = _service.GetAudioCodec(fileName, contentType); // Assert Assert.IsNotNull(result); @@ -178,12 +178,26 @@ public void GetAudioCodec_ReturnsNull_WhenContentTypeAndFileExtensionNotMatch() var contentType = "fantasy stuff"; // Act - var result = _service.GetAudioCodec(contentType, fileName); + var result = _service.GetAudioCodec(fileName, contentType); // Assert Assert.IsNull(result); } + [TestMethod()] + public void GetAudioCodec_ReturnsAudiocodec_WhenFileExtensionMatches() + { + // Arrange + var fileName = "test.mP3"; + + // Act + var result = _service.GetAudioCodec(fileName); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(Audiofile.AudioCodecs.Single(x => x.FileExtension.Equals(".mp3", StringComparison.OrdinalIgnoreCase)), result); + } + [TestMethod()] public void IsValidForImportView_ReturnsTrue_WhenFileIsHtml() { diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 160a7701..656b868a 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -26,7 +26,7 @@ public class FileInputManager(IJSRuntime jsRuntime, ILogger lo private readonly IJSRuntime _jsRuntime = jsRuntime; private readonly ILogger _logger = logger; - public AudioCodec? GetAudioCodec(string? fileContentType, string fileName) + public AudioCodec? GetAudioCodec(string fileName, string? fileContentType = null) { AudioCodec? foundAudioCodec = null; var extension = Path.GetExtension(fileName); @@ -51,9 +51,9 @@ public async Task GetObjectUrlAsync(string fileInputId) return await _jsRuntime.InvokeAsync("getObjectURLFromMudFileUpload", fileInputId); } - public bool IsValidAudiofile(string? fileContentType, string fileName) + public bool IsValidAudiofile(string fileName, string? fileContentType = null) { - return GetAudioCodec(fileContentType, fileName) != null; + return GetAudioCodec(fileName, fileContentType) != null; } public bool CheckFileMimeType(string? fileContentType, string fileName, string mimeType, IEnumerable fileExtensions) @@ -148,11 +148,11 @@ public async Task> CreateFileUploadsAsync(IReadOnlyList< if (CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) || CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) || IsValidForImportView(file.ContentType, file.Name) - || IsValidAudiofile(file.ContentType, file.Name)) + || IsValidAudiofile(file.Name, file.ContentType)) { string? content = null; string? objectUrl = null; - if (IsValidAudiofile(file.ContentType, file.Name)) + if (IsValidAudiofile(file.Name, file.ContentType)) { objectUrl = await _jsRuntime.InvokeAsync("getObjectURLFromMudFileUpload", fileInputId); } diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs index e5f4ff39..ca2a552a 100644 --- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs @@ -23,8 +23,8 @@ namespace AudioCuesheetEditor.Services.IO { public interface IFileInputManager { - bool IsValidAudiofile(string? fileContentType, string fileName); - AudioCodec? GetAudioCodec(string? fileContentType, string fileName); + bool IsValidAudiofile(string fileName, string? fileContentType = null); + AudioCodec? GetAudioCodec(string fileName, string? fileContentType = null); /// /// Get object url from a mud file upload /// diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 6637210f..163ff163 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -220,6 +220,7 @@ void AttachClonedAudiofiles(Cuesheet target, IEnumerable audiofiles) targetAudiofile ??= new Audiofile() { Name = importAudiofile.Name, + AudioCodec = String.IsNullOrEmpty(importAudiofile.Name) == false ? _fileInputManager.GetAudioCodec(importAudiofile.Name) : null }; tracks = importAudiofile.Tracks; } From 6997b5cbcd46a62a6a67a7958a793ebe36d2b496 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 08:56:50 +0200 Subject: [PATCH 17/67] fix import tests --- AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs | 2 +- AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs index 351586a2..00dfb6ef 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs @@ -212,7 +212,7 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button - rowgroup: - row"); - await Expect(TestPage.GetByRole(AriaRole.Textbox, new() { Name = "Audiofile" })).ToHaveValueAsync(@"c:\AudioFile.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "c:\\AudioFile.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"c:\\\\AudioFile.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); await importView.GotoAsync(); await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs index 22c05e60..4bfc7b7a 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTest.cs @@ -248,7 +248,7 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - cell ""Status"": - text: Status - button"); - await Expect(TestPage.GetByRole(AriaRole.Textbox, new() { Name = "Audiofile" })).ToHaveValueAsync(@"c:\AudioFile.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "c:\\AudioFile.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"c:\\\\AudioFile.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); await importView.GotoAsync(); await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); } From c5c2f02cfb355e13e64964ca57ffa27fd1e46fa2 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 09:19:01 +0200 Subject: [PATCH 18/67] Update ViewModeImport.razor --- .../Shared/ViewModes/ViewModeImport.razor | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor b/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor index 3a46ff6c..da6f1522 100644 --- a/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor +++ b/AudioCuesheetEditor/Shared/ViewModes/ViewModeImport.razor @@ -24,7 +24,7 @@ along with Foobar. If not, see @if (IsAnalyzed == false) { - + @@ -40,9 +40,9 @@ else OnClick="ImportData" /> - + - + @@ -53,9 +53,8 @@ else } @code { - //TODO: importing an audiofile doesn't set the audio codec - string? importText; - Boolean fapMenuOpened = false; + string? _importText; + Boolean _fapMenuOpened = false; public Boolean IsAnalyzed { @@ -78,8 +77,8 @@ else void ImportTextChanged(string? newImportText) { - importText = newImportText; - _importManager.ImportData(importText); + _importText = newImportText; + _importManager.ImportData(_importText); } async Task Analyze() @@ -126,7 +125,7 @@ else { if (_sessionStateContainer.Importfile?.FileType == ImportFileType.Textfile) { - importText = _sessionStateContainer.Importfile.FileContent; + _importText = _sessionStateContainer.Importfile.FileContent; StateHasChanged(); } }); From 2c1e4d912f4eacabbbc05d12726d4e20143db67d Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 09:56:01 +0200 Subject: [PATCH 19/67] Update InputTextDialog.razor --- .../Shared/Dialogs/InputTextDialog.razor | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/InputTextDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/InputTextDialog.razor index 6e1a3aa9..6eddbfcb 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/InputTextDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/InputTextDialog.razor @@ -22,7 +22,7 @@ along with Foobar. If not, see - + @_localizer["Ok"] @@ -30,8 +30,8 @@ along with Foobar. If not, see @code { - HotKeysContext? hotKeysContext; - string? inputValue; + HotKeysContext? _hotKeysContext; + string? _inputValue; [CascadingParameter] private IMudDialogInstance? MudDialog { get; set; } @@ -43,36 +43,37 @@ along with Foobar. If not, see public string? Placeholder { get; set; } [Parameter] - public String? InitialValue { get; set; } + public string? InitialValue { get; set; } protected override void OnInitialized() { base.OnInitialized(); - hotKeysContext = _hotKeys.CreateContext().Add(ModKey.None, Key.Enter, CloseDialogOk); + _hotKeysContext = _hotKeys.CreateContext().Add(ModKey.None, Key.Enter, CloseDialogOk); } protected override void Dispose(bool disposing) { base.Dispose(disposing); - hotKeysContext?.DisposeAsync(); + _hotKeysContext?.DisposeAsync(); } protected override void OnParametersSet() { base.OnParametersSet(); - inputValue = InitialValue; + _inputValue = InitialValue; } void TextFieldKeyDown(KeyboardEventArgs args) { if (args.Key == "Enter") { - CloseDialogOk(); + //Use a timer to close the dialog after a short delay to ensure that the keyboard event is fully processed before closing the dialog. + new System.Threading.Timer(CloseDialogOk, null, 0, 10); } } - void CloseDialogOk() + void CloseDialogOk(object? state = null) { - MudDialog?.Close(inputValue); + MudDialog?.Close(_inputValue); } } From 0b1166d0b2df9feaa2d9eaaf0c93a63a910798ae Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 10:01:05 +0200 Subject: [PATCH 20/67] fix basic tests --- AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs | 2 +- AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs index 05c131ff..db93ad22 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs @@ -193,7 +193,7 @@ public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAs await detailView.NewFileNameInput.FillAsync("Test 123"); await TestPage.Keyboard.PressAsync("Enter"); await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await Expect(TestPage.GetByRole(AriaRole.Textbox, new() { Name = "Audiofile" })).ToMatchAriaSnapshotAsync("- textbox \"Audiofile\": Test 123.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs index d6edfd36..b11249d3 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs @@ -192,7 +192,7 @@ public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAs await detailView.NewFileNameInput.FillAsync("Test 123"); await TestPage.Keyboard.PressAsync("Enter"); await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await Expect(TestPage.GetByRole(AriaRole.Textbox, new() { Name = "Audiofile" })).ToMatchAriaSnapshotAsync("- textbox \"Audiofile\": Test 123.mp3"); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } } } From 5fe0f1b72a39692c7469a5d2acf9adcef154f349 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 10:27:00 +0200 Subject: [PATCH 21/67] fix tests --- .../Tests/Desktop/BasicTest.cs | 2 +- .../Tests/Smartphone/BasicTest.cs | 2 +- .../Services/AudioCuesheet/AudiofileManagerTests.cs | 12 ++++++------ .../Services/IO/ImportManagerTests.cs | 2 +- .../Services/AudioCuesheet/AudiofileManager.cs | 2 +- AudioCuesheetEditor/Services/IO/FileInputManager.cs | 2 +- AudioCuesheetEditor/Services/IO/ImportManager.cs | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs index db93ad22..29d0a26f 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs @@ -193,7 +193,7 @@ public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAs await detailView.NewFileNameInput.FillAsync("Test 123"); await TestPage.Keyboard.PressAsync("Enter"); await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs index b11249d3..47ed8465 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTest.cs @@ -192,7 +192,7 @@ public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAs await detailView.NewFileNameInput.FillAsync("Test 123"); await TestPage.Keyboard.PressAsync("Enter"); await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); - await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); + await Expect(TestPage.GetByRole(AriaRole.Group).Filter(new() { HasText = "Test 123.mp3" })).ToMatchAriaSnapshotAsync("- group:\r\n - checkbox\r\n - heading \"Test 123.mp3\" [level=6]\r\n - button \"Upload file\"\r\n - button \"Rename file\"\r\n - button \"Clear file\""); } } } diff --git a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs index fd788824..15a565fa 100644 --- a/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/AudioCuesheet/AudiofileManagerTests.cs @@ -122,7 +122,7 @@ public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() browserFile.SetupGet(b => b.Name).Returns(filename); var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec("audio/mpeg", filename)).Returns(codec); + _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); _fileInputManager.Setup(f => f.GetObjectUrlAsync(inputId)).ReturnsAsync(objectUrl); _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); @@ -145,7 +145,7 @@ public async Task SetPropertiesAsync_WithBrowserFile_ShouldSetPropertiesAsync() Assert.AreEqual(objectUrl, audiofile.ObjectURL); Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); Assert.AreEqual(1, audiofileChangedFired); - _fileInputManager.Verify(f => f.GetAudioCodec("audio/mpeg", filename), Times.Once); + _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); _fileInputManager.Verify(f => f.GetObjectUrlAsync(inputId), Times.Once); _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); } @@ -162,7 +162,7 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() browserFile.SetupGet(b => b.Name).Returns(filename); var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec("audio/mpeg", filename)).Returns(codec); + _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); _fileInputManager.Setup(f => f.GetObjectUrlAsync(inputId)).ReturnsAsync(objectUrl); _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); var track1 = new Track() @@ -198,7 +198,7 @@ public async Task SetProperty_AudiofileWithDuration_SetsLastTrackEndAlsoAsync() Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); Assert.AreEqual(TimeSpan.FromSeconds(90), track2.End); Assert.AreEqual(1, audiofileChangedFired); - _fileInputManager.Verify(f => f.GetAudioCodec("audio/mpeg", filename), Times.Once); + _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); _fileInputManager.Verify(f => f.GetObjectUrlAsync(inputId), Times.Once); _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); } @@ -215,7 +215,7 @@ public async Task SetPropertiesAsync_PreviouslySetAudiofile_ShouldClearFirstAndS browserFile.SetupGet(b => b.Name).Returns(filename); var codec = Audiofile.AudioCodecs.First(x => x.FileExtension == ".mp3"); - _fileInputManager.Setup(f => f.GetAudioCodec("audio/mpeg", filename)).Returns(codec); + _fileInputManager.Setup(f => f.GetAudioCodec(filename, "audio/mpeg")).Returns(codec); _fileInputManager.Setup(f => f.GetObjectUrlAsync(inputId)).ReturnsAsync(objectUrl); _jsRuntime.Setup(js => js.InvokeAsync("getAudioDurationFromFile", It.IsAny())).Returns(new ValueTask(90.0)); @@ -240,7 +240,7 @@ public async Task SetPropertiesAsync_PreviouslySetAudiofile_ShouldClearFirstAndS Assert.AreEqual(objectUrl, audiofile.ObjectURL); Assert.AreEqual(TimeSpan.FromSeconds(90), audiofile.Duration); Assert.AreEqual(1, audiofileChangedFired); - _fileInputManager.Verify(f => f.GetAudioCodec("audio/mpeg", filename), Times.Once); + _fileInputManager.Verify(f => f.GetAudioCodec(filename, "audio/mpeg"), Times.Once); _fileInputManager.Verify(f => f.GetObjectUrlAsync(inputId), Times.Once); _jsRuntime.Verify(js => js.InvokeAsync("getAudioDurationFromFile", It.Is(o => o[0] as string == audiofile.ObjectURL)), Times.Once); _traceChangeManager.VerifySet(t => t.BulkEdit = true, Times.Once); diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index 658d9f32..abfb859b 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -368,7 +368,7 @@ public async Task UploadFilesAsync_WithAudiofile_ImportsCorrectly() _fileInputManagerMock.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); _fileInputManagerMock.Setup(f => f.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); _fileInputManagerMock.Setup(f => f.IsValidForImportView(file.ContentType, file.Name)).Returns(false); - _fileInputManagerMock.Setup(f => f.IsValidAudiofile(file.ContentType, file.Name)).Returns(true); + _fileInputManagerMock.Setup(f => f.IsValidAudiofile(file.Name, file.ContentType)).Returns(true); _fileInputManagerMock.Setup(f => f.CreateAudiofileAsync(It.IsAny())).ReturnsAsync(new Audiofile() { Name = file.Name }); IImportfile? sessionStateContainerImportfile = null; diff --git a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs index b13642d1..e2eeb63f 100644 --- a/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs +++ b/AudioCuesheetEditor/Services/AudioCuesheet/AudiofileManager.cs @@ -43,7 +43,7 @@ public async Task SetPropertiesAsync(Audiofile audiofile, IBrowserFile browserFi { await ClearPropertiesAsync(audiofile, false); } - var codec = _fileInputManager.GetAudioCodec(browserFile.ContentType, browserFile.Name); + var codec = _fileInputManager.GetAudioCodec(browserFile.Name, browserFile.ContentType); var objectUrl = await _fileInputManager.GetObjectUrlAsync(fileInputId); TimeSpan? duration = null; if (String.IsNullOrEmpty(objectUrl) == false) diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 656b868a..ef25fdd5 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -93,7 +93,7 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m if (fileUpload.ObjectUrl != null) { // Check file mime type - var codec = GetAudioCodec(fileUpload.ContentType, fileUpload.Name); + var codec = GetAudioCodec(fileUpload.Name, fileUpload.ContentType); if (codec != null) { TimeSpan? duration = null; diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 163ff163..01ad1937 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -132,7 +132,7 @@ public async Task UploadFilesAsync(IEnumerable files) if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) || _fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) || _fileInputManager.IsValidForImportView(file.ContentType, file.Name) - || _fileInputManager.IsValidAudiofile(file.ContentType, file.Name)) + || _fileInputManager.IsValidAudiofile(file.Name, file.ContentType)) { if (_fileInputManager.CheckFileMimeType(file.ContentType, file.Name, FileMimeTypes.Projectfile, [FileExtensions.Projectfile])) { @@ -161,7 +161,7 @@ public async Task UploadFilesAsync(IEnumerable files) FileType = ImportFileType.Textfile }; } - if (_fileInputManager.IsValidAudiofile(file.ContentType, file.Name)) + if (_fileInputManager.IsValidAudiofile(file.Name, file.ContentType)) { var audioFile = await _fileInputManager.CreateAudiofileAsync(file); if (audioFile != null) From e1933ef1f2514820bdcd381845f2405d60e79e90 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 30 Sep 2026 16:55:20 +0200 Subject: [PATCH 22/67] Update SessionStateContainer.cs --- AudioCuesheetEditor/Services/UI/SessionStateContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index 4e5d6cb7..d173e489 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -79,6 +79,7 @@ public async Task InitializeAsync() public void ResetImport() { Importfile = null; + //TODO: Revoke object url of ImportAudiofiles before removing them ImportAudiofiles = []; ImportCuesheet = null; ImportIsAnalyzed = false; From 207563343fb2995e84104f950c9525de1cecc9f8 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Thu, 1 Oct 2026 17:26:09 +0200 Subject: [PATCH 23/67] Update ImportManager.cs --- AudioCuesheetEditor/Services/IO/ImportManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 01ad1937..47eaf1ac 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -13,7 +13,6 @@ //You should have received a copy of the GNU General Public License //along with Foobar. If not, see //. -using AngleSharp.Media.Dom; using AudioCuesheetEditor.Model.AudioCuesheet; using AudioCuesheetEditor.Model.AudioCuesheet.Import; using AudioCuesheetEditor.Model.IO; @@ -115,6 +114,7 @@ public void ImportCuesheet() _sessionStateContainer.Cuesheet = newCuesheet; _traceChangeManager.AddChange(new TracedChange(_sessionStateContainer, new(previousValue, nameof(SessionStateContainer.Cuesheet)))); } + //TODO: Import Audiofiles before resetting import _sessionStateContainer.ResetImport(); stopwatch.Stop(); if (_logger.IsEnabled(LogLevel.Debug)) From 43bfd929361ca51a3b374461b21c26a1a9373706 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Thu, 1 Oct 2026 17:41:56 +0200 Subject: [PATCH 24/67] Update ImportManager.cs --- AudioCuesheetEditor/Services/IO/ImportManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index 47eaf1ac..abddb251 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -188,10 +188,11 @@ void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) target.Artist = cuesheetToCopy.Artist; target.Title = cuesheetToCopy.Title; target.Cataloguenumber = cuesheetToCopy.Cataloguenumber; + IEnumerable audiofiles = []; if (cuesheetToCopy is Cuesheet originCuesheet) { target.CDTextfile = originCuesheet.CDTextfile; - AttachClonedAudiofiles(target, originCuesheet.Audiofiles); + audiofiles = originCuesheet.Audiofiles; } if (cuesheetToCopy is ImportCuesheet importCuesheet) { @@ -199,8 +200,9 @@ void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy) { target.CDTextfile = new CDTextfile(importCuesheet.CDTextfile); } - AttachClonedAudiofiles(target, importCuesheet.Audiofiles); + audiofiles = importCuesheet.Audiofiles; } + AttachClonedAudiofiles(target, audiofiles); } void AttachClonedAudiofiles(Cuesheet target, IEnumerable audiofiles) From a03251c79f66a64a5d7f762f2a56c3c87839fd3e Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:01:01 +0200 Subject: [PATCH 25/67] first step for importing audiofiles --- AudioCuesheetEditor.sln | 2 +- AudioCuesheetEditor/Pages/Index.razor | 2 + AudioCuesheetEditor/Program.cs | 1 + .../Services/IO/AudioImportService.cs | 50 +++++++ .../Services/IO/IAudioImportService.cs | 29 ++++ .../Dialogs/ImportAudiofilesDialog.de.resx | 126 ++++++++++++++++++ .../Dialogs/ImportAudiofilesDialog.razor | 55 ++++++++ .../Dialogs/ImportAudiofilesDialog.resx | 126 ++++++++++++++++++ 8 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 AudioCuesheetEditor/Services/IO/AudioImportService.cs create mode 100644 AudioCuesheetEditor/Services/IO/IAudioImportService.cs create mode 100644 AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx create mode 100644 AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor create mode 100644 AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx diff --git a/AudioCuesheetEditor.sln b/AudioCuesheetEditor.sln index 40cbf088..73237fb1 100644 --- a/AudioCuesheetEditor.sln +++ b/AudioCuesheetEditor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.3.11512.155 d18.3 +VisualStudioVersion = 18.3.11512.155 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AudioCuesheetEditor", "AudioCuesheetEditor\AudioCuesheetEditor.csproj", "{099AE4DF-4847-460F-BBF2-207B9A35B58D}" EndProject diff --git a/AudioCuesheetEditor/Pages/Index.razor b/AudioCuesheetEditor/Pages/Index.razor index a8b75db0..5eeb904c 100644 --- a/AudioCuesheetEditor/Pages/Index.razor +++ b/AudioCuesheetEditor/Pages/Index.razor @@ -26,6 +26,7 @@ along with Foobar. If not, see @inject DialogManager _dialogManager @inject ISnackbar _snackbar @inject ICuesheetManager _cuesheetManager +@inject IAudioImportService _audioImportService @@ -118,6 +119,7 @@ along with Foobar. If not, see { _dialogManager.HideLoadingDialog(); } + await _audioImportService.MapAudioImportAsync(); }); } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs index 52932a92..3e75dd2d 100644 --- a/AudioCuesheetEditor/Program.cs +++ b/AudioCuesheetEditor/Program.cs @@ -61,6 +61,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddLogging(); // Read out configuration for loglevel diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs new file mode 100644 index 00000000..0c864ff8 --- /dev/null +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -0,0 +1,50 @@ +//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.Model.IO.Audio; +using AudioCuesheetEditor.Services.UI; +using AudioCuesheetEditor.Shared.Dialogs; +using MudBlazor; + +namespace AudioCuesheetEditor.Services.IO +{ + /// + public class AudioImportService(IDialogService dialogService, ISessionStateContainer sessionStateContainer) : IAudioImportService + { + private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; + private readonly IDialogService _dialogService = dialogService; + + /// + public async Task MapAudioImportAsync() + { + //TODO: Tests + var mappedAudiofiles = _sessionStateContainer.ActiveCuesheet!.Audiofiles.ToDictionary(x => x, x => (Audiofile?)null); + //TODO: automatic mapping + var parameters = new DialogParameters + { + { x => x.MappedAudiofiles, mappedAudiofiles }, + { x => x.ImportAudiofiles, _sessionStateContainer.ImportAudiofiles } + }; + var options = new DialogOptions() { BackdropClick = false, FullWidth = true }; + var dialog = await _dialogService.ShowAsync(null, parameters, options); + var result = await dialog.Result; + //TODO: get mapping from dialog and apply it to the cuesheet + //if ((result?.Canceled == false) && (result.Data is Track editedTrack)) + //{ + + //} + } + } +} diff --git a/AudioCuesheetEditor/Services/IO/IAudioImportService.cs b/AudioCuesheetEditor/Services/IO/IAudioImportService.cs new file mode 100644 index 00000000..a481489f --- /dev/null +++ b/AudioCuesheetEditor/Services/IO/IAudioImportService.cs @@ -0,0 +1,29 @@ +//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 +//. +namespace AudioCuesheetEditor.Services.IO +{ + /// + /// Service for importing audio files and matching them to the cuesheet. + /// + public interface IAudioImportService + { + /// + /// Maps the import audio from session state to the active cuesheet. If mapping is not possible automatically the user gets a dialog. + /// + /// + Task MapAudioImportAsync(); + } +} diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx new file mode 100644 index 00000000..ed296166 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Abbrechen + + + Ok + + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor new file mode 100644 index 00000000..02cd697f --- /dev/null +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -0,0 +1,55 @@ + +@inherits BaseLocalizedComponent + +@inject IStringLocalizer _localizer + + + + + + + + + + @_localizer["Ok"] + @_localizer["Abort"] + + + +@code { + [CascadingParameter] + private IMudDialogInstance? _mudDialog { get; set; } + + [Parameter] + [EditorRequired] + public IList ImportAudiofiles { get; set; } + + [Parameter] + [EditorRequired] + public Dictionary MappedAudiofiles { get; set; } + + //TODO: Add posibility to add new audiofiles to the cuesheet + //TODO: Add posibility to move audiofiles up and down in the cuesheet + //TODO: Add posibility to delete audiofiles in the cuesheet + //TODO: Loop over activecuesheet audiofiles and display relation to import audiofiles + //TODO: Title + //TODO: Actions + //TODO: Mapping of import files to current files + +} diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx new file mode 100644 index 00000000..22160cd6 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Abort + + + Ok + + \ No newline at end of file From adbefc3cc19126663d01d44bb28ae61f3732f6e0 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 11:46:07 +0200 Subject: [PATCH 26/67] Update AudioImportService.cs --- .../Services/IO/AudioImportService.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index 0c864ff8..a3a87edb 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -40,11 +40,17 @@ public async Task MapAudioImportAsync() var options = new DialogOptions() { BackdropClick = false, FullWidth = true }; var dialog = await _dialogService.ShowAsync(null, parameters, options); var result = await dialog.Result; - //TODO: get mapping from dialog and apply it to the cuesheet - //if ((result?.Canceled == false) && (result.Data is Track editedTrack)) - //{ - - //} + if (result?.Canceled == false) + { + if (result.Data is Dictionary audiofileMapping) + { + //TODO: Apply mapping to cuesheet + } + } + else + { + _sessionStateContainer.ResetImport(); + } } } } From 31c3f9f2c9e625a531ad2069173b9ae340353429 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:25:15 +0200 Subject: [PATCH 27/67] Update ImportAudiofilesDialog.razor --- .../Shared/Dialogs/ImportAudiofilesDialog.razor | 4 ---- 1 file changed, 4 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index 02cd697f..b0b18db1 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -20,9 +20,6 @@ along with Foobar. If not, see @inject IStringLocalizer _localizer - - - @@ -48,7 +45,6 @@ along with Foobar. If not, see //TODO: Add posibility to move audiofiles up and down in the cuesheet //TODO: Add posibility to delete audiofiles in the cuesheet //TODO: Loop over activecuesheet audiofiles and display relation to import audiofiles - //TODO: Title //TODO: Actions //TODO: Mapping of import files to current files From 813600006837d89681299679fb0c3a6fc5e6b748 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:25:20 +0200 Subject: [PATCH 28/67] Update AudioImportService.cs --- AudioCuesheetEditor/Services/IO/AudioImportService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index a3a87edb..6acfd413 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -38,6 +38,7 @@ public async Task MapAudioImportAsync() { x => x.ImportAudiofiles, _sessionStateContainer.ImportAudiofiles } }; var options = new DialogOptions() { BackdropClick = false, FullWidth = true }; + //TODO: Title var dialog = await _dialogService.ShowAsync(null, parameters, options); var result = await dialog.Result; if (result?.Canceled == false) From b4c7b8689f17175b671a16bad4882e761fdb52c5 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:40:23 +0200 Subject: [PATCH 29/67] fix title --- AudioCuesheetEditor/Services/IO/AudioImportService.cs | 10 ++++++---- .../Services/UI/ISessionStateContainer.cs | 1 + .../Services/UI/SessionStateContainer.cs | 1 + .../Shared/Dialogs/ImportAudiofilesDialog.de.resx | 3 +++ .../Shared/Dialogs/ImportAudiofilesDialog.razor | 5 +++++ .../Shared/Dialogs/ImportAudiofilesDialog.resx | 3 +++ 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index 6acfd413..02fec362 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -29,16 +29,18 @@ public class AudioImportService(IDialogService dialogService, ISessionStateConta /// public async Task MapAudioImportAsync() { - //TODO: Tests - var mappedAudiofiles = _sessionStateContainer.ActiveCuesheet!.Audiofiles.ToDictionary(x => x, x => (Audiofile?)null); + //TODO: Tests + foreach (var audiofile in _sessionStateContainer.ActiveCuesheet!.Audiofiles) + { + _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, null); + } //TODO: automatic mapping var parameters = new DialogParameters { - { x => x.MappedAudiofiles, mappedAudiofiles }, + { x => x.MappedAudiofiles, _sessionStateContainer.ImportAudiofileMapping }, { x => x.ImportAudiofiles, _sessionStateContainer.ImportAudiofiles } }; var options = new DialogOptions() { BackdropClick = false, FullWidth = true }; - //TODO: Title var dialog = await _dialogService.ShowAsync(null, parameters, options); var result = await dialog.Result; if (result?.Canceled == false) diff --git a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs index 0e68b86b..4ec4c1ef 100644 --- a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs @@ -26,6 +26,7 @@ public interface ISessionStateContainer public Cuesheet Cuesheet { get; set; } public Cuesheet? ImportCuesheet { get; set; } public IList ImportAudiofiles { get; set; } + public Dictionary ImportAudiofileMapping { get; set; } public IImportfile? Importfile { get; set; } public Boolean ImportIsAnalyzed { get; set; } public void ResetImport(); diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index d173e489..cbf023fb 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -66,6 +66,7 @@ public Cuesheet? ImportCuesheet } } public IList ImportAudiofiles { get; set; } = []; + public Dictionary ImportAudiofileMapping { get; set; } = []; public IImportfile? Importfile { get; set; } public Boolean ImportIsAnalyzed { get; set; } = false; diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx index ed296166..6bce74ef 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx @@ -120,6 +120,9 @@ Abbrechen + + Dateien zuordnen + Ok diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index b0b18db1..526a69d1 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -20,6 +20,11 @@ along with Foobar. If not, see @inject IStringLocalizer _localizer + + + @_localizer["Assign files"] + + diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx index 22160cd6..c8a23ff1 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx @@ -120,6 +120,9 @@ Abort + + Assign files + Ok From d81c50386ed21616692125b0b29035b6a23eee43 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:41:19 +0200 Subject: [PATCH 30/67] Update ImportAudiofilesDialog.razor --- AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index 526a69d1..8492e963 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -36,7 +36,7 @@ along with Foobar. If not, see @code { [CascadingParameter] - private IMudDialogInstance? _mudDialog { get; set; } + IMudDialogInstance? _mudDialog { get; set; } [Parameter] [EditorRequired] From 34a88077a35a23a8f61bb899d46dbd07cb3e2680 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:42:08 +0200 Subject: [PATCH 31/67] Update SessionStateContainer.cs --- AudioCuesheetEditor/Services/UI/SessionStateContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index cbf023fb..45e04ab1 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -81,6 +81,7 @@ public void ResetImport() { Importfile = null; //TODO: Revoke object url of ImportAudiofiles before removing them + ImportAudiofileMapping = []; ImportAudiofiles = []; ImportCuesheet = null; ImportIsAnalyzed = false; From ede483cdacc2ee87a5e556d016a5978f78c97736 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 13:38:25 +0200 Subject: [PATCH 32/67] dialog for mapping of audiofiles --- .../Services/IO/AudioImportService.cs | 1 + .../Dialogs/ImportAudiofilesDialog.razor | 88 ++++++++++++++++++- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index 02fec362..c22908a5 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -47,6 +47,7 @@ public async Task MapAudioImportAsync() { if (result.Data is Dictionary audiofileMapping) { + _sessionStateContainer.ImportAudiofileMapping = audiofileMapping; //TODO: Apply mapping to cuesheet } } diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index 8492e963..1914224e 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -26,7 +26,27 @@ along with Foobar. If not, see - + + + @_localizer["Files"] + + @foreach (var dropzone in _dropzones) + { + + @GetFileName(dropzone.Value) + + } + + @_localizer["Uploaded files"] + + + + + @context.Name + + + @_localizer["Ok"] @@ -46,11 +66,71 @@ along with Foobar. If not, see [EditorRequired] public Dictionary MappedAudiofiles { get; set; } + List _audiofiles = []; + const string UploadedZoneIdentifier = "uploaded"; + Dictionary _dropzones = []; + string? _sourceZoneIdentifier; + + protected override void OnInitialized() + { + base.OnInitialized(); + _dropzones = MappedAudiofiles.ToDictionary(x => Guid.NewGuid().ToString(), x => x.Key); + SetImportAudiofiles(); + } + + bool ItemsSelector(Audiofile item, string zone) + { + if (zone == UploadedZoneIdentifier) + { + return ImportAudiofiles.Contains(item); + } + var audiofile = _dropzones[zone]; + return MappedAudiofiles[audiofile] == item; + } + + void ItemPicked(MudDragAndDropItemTransaction itemTransaction) + { + _sourceZoneIdentifier = itemTransaction.SourceZoneIdentifier; + } + + void ItemDropped(MudItemDropInfo itemDropInfo) + { + if (_sourceZoneIdentifier != null && _sourceZoneIdentifier != UploadedZoneIdentifier) + { + var sourceAudiofile = _dropzones[_sourceZoneIdentifier]; + var currentlyMapped = MappedAudiofiles[sourceAudiofile]; + if (currentlyMapped != null) + { + ImportAudiofiles.Add(currentlyMapped); + } + MappedAudiofiles[sourceAudiofile] = null; + } + var targetAudiofile = _dropzones[itemDropInfo.DropzoneIdentifier]; + var currentlyMappedFile = MappedAudiofiles[targetAudiofile]; + MappedAudiofiles[targetAudiofile] = itemDropInfo.Item; + ImportAudiofiles.Remove(itemDropInfo.Item!); + if (currentlyMappedFile != null) + { + ImportAudiofiles.Add(currentlyMappedFile); + } + SetImportAudiofiles(); + _sourceZoneIdentifier = null; + } + + String GetFileName(Audiofile audiofile) + { + return String.IsNullOrEmpty(audiofile.Name) ? _localizer["No file uploaded!"] : audiofile.Name; + } + + void SetImportAudiofiles() + { + _audiofiles = [.. ImportAudiofiles, .. MappedAudiofiles.Values.Where(x => x != null).Select(x => x!)]; + } + //TODO: Add posibility to add new audiofiles to the cuesheet //TODO: Add posibility to move audiofiles up and down in the cuesheet //TODO: Add posibility to delete audiofiles in the cuesheet //TODO: Loop over activecuesheet audiofiles and display relation to import audiofiles //TODO: Actions - //TODO: Mapping of import files to current files - -} + //TODO: Disable Ok while not all files are mapped +} \ No newline at end of file From 99bc0aaaabc912e67aaee3c2c4c9a25b77355099 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 13:44:45 +0200 Subject: [PATCH 33/67] Update ImportAudiofilesDialog.razor --- .../Shared/Dialogs/ImportAudiofilesDialog.razor | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index 1914224e..aebe09f5 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -33,7 +33,7 @@ along with Foobar. If not, see @foreach (var dropzone in _dropzones) { - + @GetFileName(dropzone.Value) } @@ -130,7 +130,5 @@ along with Foobar. If not, see //TODO: Add posibility to add new audiofiles to the cuesheet //TODO: Add posibility to move audiofiles up and down in the cuesheet //TODO: Add posibility to delete audiofiles in the cuesheet - //TODO: Loop over activecuesheet audiofiles and display relation to import audiofiles - //TODO: Actions //TODO: Disable Ok while not all files are mapped } \ No newline at end of file From 85883216b9ec4cb1d1e83d1e5585dec18b1b18ea Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 13:46:56 +0200 Subject: [PATCH 34/67] disable ok while not all files are mapped --- .../Shared/Dialogs/ImportAudiofilesDialog.razor | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index aebe09f5..ce86bc9b 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -49,7 +49,7 @@ along with Foobar. If not, see - @_localizer["Ok"] + @_localizer["Ok"] @_localizer["Abort"] @@ -130,5 +130,4 @@ along with Foobar. If not, see //TODO: Add posibility to add new audiofiles to the cuesheet //TODO: Add posibility to move audiofiles up and down in the cuesheet //TODO: Add posibility to delete audiofiles in the cuesheet - //TODO: Disable Ok while not all files are mapped } \ No newline at end of file From db35c4073055d42c661a221f62295ac18a716ea8 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 13:52:00 +0200 Subject: [PATCH 35/67] display track count --- .../Shared/Dialogs/ImportAudiofilesDialog.razor | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index ce86bc9b..6d83b88c 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -34,7 +34,10 @@ along with Foobar. If not, see @foreach (var dropzone in _dropzones) { - @GetFileName(dropzone.Value) + + @GetFileName(dropzone.Value) + @_localizer["Track count: {0}", @dropzone.Value.Tracks.Count] + } From bbe0f7a5cbc91b9102f75727aa36ab7b5d827b07 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 13:56:54 +0200 Subject: [PATCH 36/67] add localization --- .../Shared/Dialogs/ImportAudiofilesDialog.de.resx | 12 ++++++++++++ .../Shared/Dialogs/ImportAudiofilesDialog.razor | 2 +- .../Shared/Dialogs/ImportAudiofilesDialog.resx | 12 ++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx index 6bce74ef..854890d0 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx @@ -123,7 +123,19 @@ Dateien zuordnen + + Dateien + + + Keine Datei hochgeladen! + Ok + + Anzahl Titel: {0} + + + Hochgeladene Dateien + \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index 6d83b88c..2386d00c 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -42,7 +42,7 @@ along with Foobar. If not, see } @_localizer["Uploaded files"] - + diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx index c8a23ff1..e8253d84 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx @@ -123,7 +123,19 @@ Assign files + + Files + + + No file uploaded! + Ok + + Track count: {0} + + + Uploaded files + \ No newline at end of file From 5698eb7bb1aee474900e1d6bb2129adf971a2040 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:20:53 +0200 Subject: [PATCH 37/67] Update AudioImportService.cs --- AudioCuesheetEditor/Services/IO/AudioImportService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index c22908a5..d4d0def6 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -29,7 +29,7 @@ public class AudioImportService(IDialogService dialogService, ISessionStateConta /// public async Task MapAudioImportAsync() { - //TODO: Tests + //TODO: Tests? foreach (var audiofile in _sessionStateContainer.ActiveCuesheet!.Audiofiles) { _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, null); From 66dce518cff2dfa0a79f763c962083ca48b750ab Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:33:04 +0200 Subject: [PATCH 38/67] add and remove files during import --- .../Dialogs/ImportAudiofilesDialog.de.resx | 3 + .../Dialogs/ImportAudiofilesDialog.razor | 67 ++++++++++++++----- .../Dialogs/ImportAudiofilesDialog.resx | 3 + 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx index 854890d0..ef606d12 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.de.resx @@ -120,6 +120,9 @@ Abbrechen + + Datei hinzufügen + Dateien zuordnen diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor index 2386d00c..7228b7f1 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.razor @@ -29,18 +29,34 @@ along with Foobar. If not, see - @_localizer["Files"] - - @foreach (var dropzone in _dropzones) - { - - - @GetFileName(dropzone.Value) - @_localizer["Track count: {0}", @dropzone.Value.Tracks.Count] - - - } - + + + + @_localizer["Files"] + + + + + + + + + + + + @foreach (var dropzone in _dropzones) + { + + + @GetFileName(dropzone.Value) + @_localizer["Track count: {0}", @dropzone.Value.Tracks.Count] + + + + } + + + @_localizer["Uploaded files"] @@ -77,7 +93,7 @@ along with Foobar. If not, see protected override void OnInitialized() { base.OnInitialized(); - _dropzones = MappedAudiofiles.ToDictionary(x => Guid.NewGuid().ToString(), x => x.Key); + SetDropzones(); SetImportAudiofiles(); } @@ -130,7 +146,26 @@ along with Foobar. If not, see _audiofiles = [.. ImportAudiofiles, .. MappedAudiofiles.Values.Where(x => x != null).Select(x => x!)]; } - //TODO: Add posibility to add new audiofiles to the cuesheet - //TODO: Add posibility to move audiofiles up and down in the cuesheet - //TODO: Add posibility to delete audiofiles in the cuesheet + void SetDropzones() + { + _dropzones = MappedAudiofiles.ToDictionary(x => Guid.NewGuid().ToString(), x => x.Key); + } + + void AddButtonClicked() + { + var audiofile = new Audiofile(); + MappedAudiofiles.Add(audiofile, null); + SetDropzones(); + } + + void DeleteButtonClicked(Audiofile audiofile) + { + var currentlyMappedAudiofile = MappedAudiofiles[audiofile]; + if (currentlyMappedAudiofile != null) + { + ImportAudiofiles.Add(currentlyMappedAudiofile); + } + MappedAudiofiles.Remove(audiofile); + SetDropzones(); + } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx index e8253d84..2cd88420 100644 --- a/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx +++ b/AudioCuesheetEditor/Shared/Dialogs/ImportAudiofilesDialog.resx @@ -120,6 +120,9 @@ Abort + + Add file + Assign files From 3f03cd3949239a054ef68b65527a77fd81255d12 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 16:20:24 +0200 Subject: [PATCH 39/67] Update FileInputManager.cs --- .../Services/IO/FileInputManager.cs | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index ef25fdd5..81176be4 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -89,25 +89,22 @@ public bool CheckFileMimeType(string? fileContentType, string fileName, string m public async Task CreateAudiofileAsync(FileUpload fileUpload) { - Audiofile? audiofile = null; - if (fileUpload.ObjectUrl != null) + // Check file mime type + var codec = GetAudioCodec(fileUpload.Name, fileUpload.ContentType); + Audiofile? audiofile; + if (codec != null) { - // Check file mime type - var codec = GetAudioCodec(fileUpload.Name, fileUpload.ContentType); - if (codec != null) + TimeSpan? duration = null; + if (String.IsNullOrEmpty(fileUpload.ObjectUrl) == false) { - TimeSpan? duration = null; - if (String.IsNullOrEmpty(fileUpload.ObjectUrl) == false) - { - var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", fileUpload.ObjectUrl); - duration = TimeSpan.FromSeconds(durationSeconds); - } - audiofile = new Audiofile(fileUpload.Name, fileUpload.ObjectUrl, codec, duration); - } - else - { - throw new ArgumentException("The audiofile provided is not of a valid type."); + var durationSeconds = await _jsRuntime.InvokeAsync("getAudioDurationFromFile", fileUpload.ObjectUrl); + duration = TimeSpan.FromSeconds(durationSeconds); } + audiofile = new Audiofile(fileUpload.Name, fileUpload.ObjectUrl, codec, duration); + } + else + { + throw new ArgumentException("The audiofile provided is not of a valid type."); } return audiofile; } @@ -154,6 +151,7 @@ public async Task> CreateFileUploadsAsync(IReadOnlyList< string? objectUrl = null; if (IsValidAudiofile(file.Name, file.ContentType)) { + //TODO: Upload multiple audiofiles at once fails to get correct audio object url because of only one fileInputId objectUrl = await _jsRuntime.InvokeAsync("getObjectURLFromMudFileUpload", fileInputId); } else From 6986f65e9b6bd2b36321f0be09dcbdb1acf65999 Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Tue, 6 Oct 2026 16:38:51 +0200 Subject: [PATCH 40/67] Update AudioImportService.cs --- .../Services/IO/AudioImportService.cs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/AudioCuesheetEditor/Services/IO/AudioImportService.cs b/AudioCuesheetEditor/Services/IO/AudioImportService.cs index d4d0def6..79ae5c00 100644 --- a/AudioCuesheetEditor/Services/IO/AudioImportService.cs +++ b/AudioCuesheetEditor/Services/IO/AudioImportService.cs @@ -14,6 +14,7 @@ //along with Foobar. If not, see //. using AudioCuesheetEditor.Model.IO.Audio; +using AudioCuesheetEditor.Services.AudioCuesheet; using AudioCuesheetEditor.Services.UI; using AudioCuesheetEditor.Shared.Dialogs; using MudBlazor; @@ -21,15 +22,18 @@ namespace AudioCuesheetEditor.Services.IO { /// - public class AudioImportService(IDialogService dialogService, ISessionStateContainer sessionStateContainer) : IAudioImportService + public class AudioImportService(IDialogService dialogService, ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IAudiofileManager audiofileManager) : IAudioImportService { private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; private readonly IDialogService _dialogService = dialogService; + private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; + private readonly IAudiofileManager _audiofileManager = audiofileManager; /// public async Task MapAudioImportAsync() { //TODO: Tests? + _sessionStateContainer.ImportAudiofileMapping.Clear(); foreach (var audiofile in _sessionStateContainer.ActiveCuesheet!.Audiofiles) { _sessionStateContainer.ImportAudiofileMapping.Add(audiofile, null); @@ -48,13 +52,26 @@ public async Task MapAudioImportAsync() if (result.Data is Dictionary audiofileMapping) { _sessionStateContainer.ImportAudiofileMapping = audiofileMapping; - //TODO: Apply mapping to cuesheet + _traceChangeManager.BulkEdit = true; + foreach (var mapping in _sessionStateContainer.ImportAudiofileMapping.Where(x => x.Value != null)) + { + var audiofile = _sessionStateContainer.ActiveCuesheet.Audiofiles.FirstOrDefault(x => x.Equals(mapping.Key)); + if (audiofile != null) + { + _audiofileManager.SetProperty(audiofile, x => x.ObjectURL, mapping.Value!.ObjectURL); + _audiofileManager.SetProperty(audiofile, x => x.AudioCodec, mapping.Value!.AudioCodec); + _audiofileManager.SetProperty(audiofile, x => x.Duration, mapping.Value!.Duration); + _audiofileManager.SetProperty(audiofile, x => x.Name, mapping.Value!.Name); + } + else + { + //TODO: add new audiofile to cuesheet + } + } + _traceChangeManager.BulkEdit = false; } } - else - { - _sessionStateContainer.ResetImport(); - } + _sessionStateContainer.ResetImport(); } } } From f8e3976385a4f42965ea1021781d444d79691d6c Mon Sep 17 00:00:00 2001 From: NeoCodeMatrix86 <40752681+NeoCoderMatrix86@users.noreply.github.com> Date: Wed, 7 Oct 2026 09:27:23 +0200 Subject: [PATCH 41/67] fix audio file upload bug --- .../Services/IO/FileInputManagerTests.cs | 5 ++--- .../Services/IO/FileInputManager.cs | 5 ++--- .../Services/IO/IFileInputManager.cs | 3 +-- .../Shared/Inputs/FileDropOverlay.razor | 6 ++---- .../wwwroot/scripts/library.js | 20 ++++++++++++------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs index 3b920a6d..90d6038e 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/FileInputManagerTests.cs @@ -232,7 +232,6 @@ public async Task CreateFileUploadsAsync_ReturnsFileUploads_WhenFileHasTextConte // Arrange var firstFile = CreateBrowserFile("Test.txt", "text/plain", "Just a test!"); var secondFile = CreateBrowserFile("Test.mp3", "audio/mpeg"); - var fileInputId = nameof(CreateFileUploadsAsync_ReturnsFileUploads_WhenFileHasTextContentAsync); IReadOnlyList browserfiles = [ firstFile, secondFile @@ -240,7 +239,7 @@ public async Task CreateFileUploadsAsync_ReturnsFileUploads_WhenFileHasTextConte var objectUrl = "Some object url!"; _jsRuntimeMock.Setup(js => js.InvokeAsync(It.IsAny(), It.IsAny())).ReturnsAsync(objectUrl); // Act - var result = await _service.CreateFileUploadsAsync(browserfiles, fileInputId); + var result = await _service.CreateFileUploadsAsync(browserfiles); // Assert Assert.HasCount(2, result); Assert.AreEqual(firstFile.Name, result.First().Name); @@ -265,7 +264,7 @@ public async Task CreateFileUploadsAsync_ReturnsEmpty_WhenFilesHaveInvalidMimeTy // Act var result = await _service.CreateFileUploadsAsync(browserfiles); // Assert - Assert.HasCount(0, result); + Assert.IsEmpty(result); } static IBrowserFile CreateBrowserFile(string name, string contentType, string? content = null) diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 81176be4..033f3693 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -137,7 +137,7 @@ public async Task ReadFileContentAsync(IBrowserFile browserFile) } /// - public async Task> CreateFileUploadsAsync(IReadOnlyList browserFiles, string? fileInputId = null) + public async Task> CreateFileUploadsAsync(IReadOnlyList browserFiles) { List fileUploads = []; foreach (var file in browserFiles) @@ -151,8 +151,7 @@ public async Task> CreateFileUploadsAsync(IReadOnlyList< string? objectUrl = null; if (IsValidAudiofile(file.Name, file.ContentType)) { - //TODO: Upload multiple audiofiles at once fails to get correct audio object url because of only one fileInputId - objectUrl = await _jsRuntime.InvokeAsync("getObjectURLFromMudFileUpload", fileInputId); + objectUrl = await _jsRuntime.InvokeAsync("getObjectURLFromMudFileUpload", file.Name, file.Size, file.ContentType, file.LastModified.ToUnixTimeMilliseconds()); } else { diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs index ca2a552a..dc00ba32 100644 --- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs @@ -58,8 +58,7 @@ public interface IFileInputManager /// Generates file upload references for files /// /// - /// /// - Task> CreateFileUploadsAsync(IReadOnlyList browserFiles, string? fileInputId = null); + Task> CreateFileUploadsAsync(IReadOnlyList browserFiles); } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor index deb044b1..9f381fd2 100644 --- a/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor +++ b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor @@ -26,7 +26,7 @@ along with Foobar. If not, see @inject IFileInputManager _fileInputManager -