diff --git a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs index b493ce82..6129ffd9 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/AppBar.cs @@ -63,8 +63,7 @@ internal async Task RedoAsync() internal async Task OpenFileAsync(string file) { await OpenFileDialogAsync(); - await _page.Locator("#dropFileInputId_SelectFileDialog").GetByRole(AriaRole.Button, new() { Name = "Choose File" }).ClickAsync(); - await _page.Locator("#dropFileInputId_SelectFileDialog").GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync(file); + await _page.GetByLabel("Open file upload").SetInputFilesAsync(file); } internal async Task OpenFileDialogAsync() diff --git a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs index 409df545..f6d65aa7 100644 --- a/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs +++ b/AudioCuesheetEditor.End2EndTests/Models/ImportView.cs @@ -18,7 +18,7 @@ namespace AudioCuesheetEditor.End2EndTests.Models { - partial class ImportView(IPage page) + partial class ImportView(IPage page, bool mobile) { [GeneratedRegex("^Scheme common data$")] private static partial Regex SchemeCommonData(); @@ -26,6 +26,7 @@ partial class ImportView(IPage page) internal const string BaseUrl = "http://localhost:5132/"; private readonly IPage _page = page; + private readonly bool _isMobile = mobile; internal ILocator CuesheetArtistInput => _page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" }); @@ -43,12 +44,30 @@ internal async Task GotoAsync() internal async Task ImportFileAsync(string filepath) { - await _page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync(filepath); + await _page.GetByLabel("TextField file upload").SetInputFilesAsync(filepath); + } + + internal async Task ImportTextAsync(string text) + { + await _page.GetByRole(AriaRole.Textbox, new() { Name = "Please enter text or upload a" }).FillAsync(text); + } + + internal async Task Analyze() + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Analyze" }).ClickAsync(); } internal async Task CompleteImportAsync() { - await _page.GetByRole(AriaRole.Button, new() { Name = "Complete" }).ClickAsync(); + if (_isMobile) + { + await _page.Locator(".mud-button-root.mud-fab").ClickAsync(); + await _page.GetByText("Import data").ClickAsync(); + } + else + { + await _page.GetByRole(AriaRole.Button, new() { Name = "Import data" }).ClickAsync(); + } } internal async Task SelectTracksAsync(IEnumerable trackTablePositions, Boolean uncheck = false) diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs index f20ee029..c307daf9 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/BasicTest.cs @@ -110,9 +110,6 @@ public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAs var bar = new AppBar(TestPage); var detailView = new DetailView(TestPage, DeviceName != null); await detailView.GotoAsync(); - await bar.OpenFileDialogAsync(); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.Keyboard.PressAsync("Escape"); await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); await bar.OpenExportDialogAsync("Cuesheet"); await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs index 7d49da1c..5554c20b 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/ImportTest.cs @@ -24,10 +24,11 @@ public class ImportTest : PlaywrightTestBase [TestMethod] public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); var detailView = new DetailView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); await importView.CompleteImportAsync(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: @@ -247,15 +248,16 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - row"); await Expect(detailView.AudiofileInput).ToBeEmptyAsync(); await importView.GotoAsync(); - await Expect(TestPage.GetByText("PreviousNext")).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); } [TestMethod] public async Task Import_ShouldBeEditable_WhenEditingTrack() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); await importView.SelectTracksAsync([5]); await importView.EditTracksModalAsync("Sample Title Edited 5"); await importView.CompleteImportAsync(); @@ -480,20 +482,22 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta [TestMethod] public async Task Import_ShouldImportTracks_WithSpecialTextfile() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Textimport-Bug-#54.txt"); await importView.SwitchImportProfileAsync("Textfile (just track data)"); + await importView.Analyze(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync("- table:\n - rowgroup:\n - row \"# Sort Column options Artist Sort Column options Title Sort Column options Begin Sort Column options End Sort Column options Length Sort Column options\":\n - columnheader:\n - checkbox\n - columnheader \"# Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Artist Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Title Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Begin Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"End Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - columnheader \"Length Sort Column options\":\n - button \"Sort\"\n - button \"Column options\"\n - rowgroup:\n - row /Increment Decrement Adriatique Clear X\\. Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"1\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Adriatique Clear\":\n - textbox: Adriatique\n - button \"Clear\"\n - button\n - cell \"X. Clear\":\n - textbox: X.\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Third Harmony Clear Fears And Dreams \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"2\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Third Harmony Clear\":\n - textbox: Third Harmony\n - button \"Clear\"\n - button\n - cell \"Fears And Dreams (Original Mix) Clear\":\n - textbox: Fears And Dreams (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Dele Sosimi Afrobeat Orchestra Clear Too Much Information \\(Laolu Remix; Edit\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"3\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Dele Sosimi Afrobeat Orchestra Clear\":\n - textbox: Dele Sosimi Afrobeat Orchestra\n - button \"Clear\"\n - button\n - cell \"Too Much Information (Laolu Remix; Edit) Clear\":\n - textbox: Too Much Information (Laolu Remix; Edit)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Edem, Govan Clear Ankh \\(Onetwo MX Remix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"4\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Edem, Govan Clear\":\n - textbox: Edem, Govan\n - button \"Clear\"\n - button\n - cell \"Ankh (Onetwo MX Remix) Clear\":\n - textbox: Ankh (Onetwo MX Remix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Jody Wisternoff Clear For All Time \\(feat\\. Hendrik Burkhard\\) \\(Extended Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"5\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Jody Wisternoff Clear\":\n - textbox: Jody Wisternoff\n - button \"Clear\"\n - button\n - cell \"For All Time (feat. Hendrik Burkhard) (Extended Mix) Clear\":\n - textbox: For All Time (feat. Hendrik Burkhard) (Extended Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Einmusik Clear Bead \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"6\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Einmusik Clear\":\n - textbox: Einmusik\n - button \"Clear\"\n - button\n - cell \"Bead (Original Mix) Clear\":\n - textbox: Bead (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Sebastien Leger Clear La Danse du Scorpion Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"7\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Sebastien Leger Clear\":\n - textbox: Sebastien Leger\n - button \"Clear\"\n - button\n - cell \"La Danse du Scorpion Clear\":\n - textbox: La Danse du Scorpion\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Paul Thomas & Solid Stone Clear La Bombo \\(Solid Stone Remix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"8\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Paul Thomas & Solid Stone Clear\":\n - textbox: Paul Thomas & Solid Stone\n - button \"Clear\"\n - button\n - cell \"La Bombo (Solid Stone Remix) Clear\":\n - textbox: La Bombo (Solid Stone Remix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement GusGus Clear Crossfade \\(Maceo Plex Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: \"9\"\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"GusGus Clear\":\n - textbox: GusGus\n - button \"Clear\"\n - button\n - cell \"Crossfade (Maceo Plex Mix) Clear\":\n - textbox: Crossfade (Maceo Plex Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Klangkarussell Clear Time \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Klangkarussell Clear\":\n - textbox: Klangkarussell\n - button \"Clear\"\n - button\n - cell \"Time (Original Mix) Clear\":\n - textbox: Time (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Anysense & Un:said Clear Missing Path \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Anysense & Un:said Clear\":\n - textbox: Anysense & Un:said\n - button \"Clear\"\n - button\n - cell \"Missing Path (Original Mix) Clear\":\n - textbox: Missing Path (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Space Food Clear Bombay Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Space Food Clear\":\n - textbox: Space Food\n - button \"Clear\"\n - button\n - cell \"Bombay Clear\":\n - textbox: Bombay\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement SHDW & Obscure Shape Clear Wächter der Nacht \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"SHDW & Obscure Shape Clear\":\n - textbox: SHDW & Obscure Shape\n - button \"Clear\"\n - button\n - cell \"Wächter der Nacht (Original Mix) Clear\":\n - textbox: Wächter der Nacht (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement HOSH Clear Karma Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"HOSH Clear\":\n - textbox: HOSH\n - button \"Clear\"\n - button\n - cell \"Karma Clear\":\n - textbox: Karma\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Alexey Union Clear Olympia \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Alexey Union Clear\":\n - textbox: Alexey Union\n - button \"Clear\"\n - button\n - cell \"Olympia (Original Mix) Clear\":\n - textbox: Olympia (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Paul Taylor Clear Afterglow Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Paul Taylor Clear\":\n - textbox: Paul Taylor\n - button \"Clear\"\n - button\n - cell \"Afterglow Clear\":\n - textbox: Afterglow\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Philter Clear Stranger Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Philter Clear\":\n - textbox: Philter\n - button \"Clear\"\n - button\n - cell \"Stranger Clear\":\n - textbox: Stranger\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Skizologic Clear Hypersphere \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Skizologic Clear\":\n - textbox: Skizologic\n - button \"Clear\"\n - button\n - cell \"Hypersphere (Original Mix) Clear\":\n - textbox: Hypersphere (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Thomas Schumacher, Caitlin Clear All of You \\(Remix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Thomas Schumacher, Caitlin Clear\":\n - textbox: Thomas Schumacher, Caitlin\n - button \"Clear\"\n - button\n - cell \"All of You (Remix) Clear\":\n - textbox: All of You (Remix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement A\\. Skomoroh Clear White Horse Conquest \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"A. Skomoroh Clear\":\n - textbox: A. Skomoroh\n - button \"Clear\"\n - button\n - cell \"White Horse Conquest (Original Mix) Clear\":\n - textbox: White Horse Conquest (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Patrik Berg Clear Bright \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Patrik Berg Clear\":\n - textbox: Patrik Berg\n - button \"Clear\"\n - button\n - cell \"Bright (Original Mix) Clear\":\n - textbox: Bright (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Hidden Empire Clear Bengal Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Hidden Empire Clear\":\n - textbox: Hidden Empire\n - button \"Clear\"\n - button\n - cell \"Bengal Clear\":\n - textbox: Bengal\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Mario Ochoa Clear Levitate Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Mario Ochoa Clear\":\n - textbox: Mario Ochoa\n - button \"Clear\"\n - button\n - cell \"Levitate Clear\":\n - textbox: Levitate\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Raul Facio Clear Eyes Wide Shut \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Raul Facio Clear\":\n - textbox: Raul Facio\n - button \"Clear\"\n - button\n - cell \"Eyes Wide Shut (Original Mix) Clear\":\n - textbox: Eyes Wide Shut (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Soolver Clear Regular \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Soolver Clear\":\n - textbox: Soolver\n - button \"Clear\"\n - button\n - cell \"Regular (Original Mix) Clear\":\n - textbox: Regular (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Weska Clear EQ64 \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Weska Clear\":\n - textbox: Weska\n - button \"Clear\"\n - button\n - cell \"EQ64 (Original Mix) Clear\":\n - textbox: EQ64 (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Tempo Giusto Clear The Fall \\(Extended Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Tempo Giusto Clear\":\n - textbox: Tempo Giusto\n - button \"Clear\"\n - button\n - cell \"The Fall (Extended Mix) Clear\":\n - textbox: The Fall (Extended Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Vlind & Asteroid & Gary Leroy Clear Trinity \\(Extended Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Vlind & Asteroid & Gary Leroy Clear\":\n - textbox: Vlind & Asteroid & Gary Leroy\n - button \"Clear\"\n - button\n - cell \"Trinity (Extended Mix) Clear\":\n - textbox: Trinity (Extended Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Astral Legacy Clear Vaveyla \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Astral Legacy Clear\":\n - textbox: Astral Legacy\n - button \"Clear\"\n - button\n - cell \"Vaveyla (Original Mix) Clear\":\n - textbox: Vaveyla (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Gerrox Clear Chakra \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Gerrox Clear\":\n - textbox: Gerrox\n - button \"Clear\"\n - button\n - cell \"Chakra (Original Mix) Clear\":\n - textbox: Chakra (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Charlotte De Witte Clear Pattern Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Charlotte De Witte Clear\":\n - textbox: Charlotte De Witte\n - button \"Clear\"\n - button\n - cell \"Pattern Clear\":\n - textbox: Pattern\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Space Food Clear Amabey Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Space Food Clear\":\n - textbox: Space Food\n - button \"Clear\"\n - button\n - cell \"Amabey Clear\":\n - textbox: Amabey\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement ARTBAT Clear Papilion \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"ARTBAT Clear\":\n - textbox: ARTBAT\n - button \"Clear\"\n - button\n - cell \"Papilion (Original Mix) Clear\":\n - textbox: Papilion (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement PETER PAHN Clear Enjoy Infinity \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"PETER PAHN Clear\":\n - textbox: PETER PAHN\n - button \"Clear\"\n - button\n - cell \"Enjoy Infinity (Original Mix) Clear\":\n - textbox: Enjoy Infinity (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Solitek Clear Instinct \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Solitek Clear\":\n - textbox: Solitek\n - button \"Clear\"\n - button\n - cell \"Instinct (Original Mix) Clear\":\n - textbox: Instinct (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Veerus Clear Heavy Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Veerus Clear\":\n - textbox: Veerus\n - button \"Clear\"\n - button\n - cell \"Heavy Clear\":\n - textbox: Heavy\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Secret Cinema & Reinier Zonneveld Clear Pain Thing \\(Original Mix\\) Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Secret Cinema & Reinier Zonneveld Clear\":\n - textbox: Secret Cinema & Reinier Zonneveld\n - button \"Clear\"\n - button\n - cell \"Pain Thing (Original Mix) Clear\":\n - textbox: Pain Thing (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Amelie Lens Clear Hypnotized Clear \\d+:\\d+:\\d+ \\d+:\\d+:\\d+ \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Amelie Lens Clear\":\n - textbox: Amelie Lens\n - button \"Clear\"\n - button\n - cell \"Hypnotized Clear\":\n - textbox: Hypnotized\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - row /Increment Decrement Nikolay Kirov Clear Chasing the Sun \\(Original Mix\\) Clear \\d+:\\d+:\\d+/:\n - cell:\n - checkbox\n - cell \"Increment Decrement\":\n - spinbutton: /\\d+/\n - button \"Increment\"\n - button \"Decrement\"\n - cell \"Nikolay Kirov Clear\":\n - textbox: Nikolay Kirov\n - button \"Clear\"\n - button\n - cell \"Chasing the Sun (Original Mix) Clear\":\n - textbox: Chasing the Sun (Original Mix)\n - button \"Clear\"\n - button\n - cell /\\d+:\\d+:\\d+/:\n - textbox: /\\d+:\\d+:\\d+/\n - cell:\n - textbox\n - cell:\n - textbox\n - rowgroup:\n - row"); } [TestMethod] public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile2() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Sample_Inputfile2.txt"); await importView.ClearSchemeCommonDataAsync(); + await importView.Analyze(); await Expect(importView.CuesheetArtistInput).ToBeEmptyAsync(); await Expect(importView.CuesheetTitleInput).ToBeEmptyAsync(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: @@ -701,10 +705,11 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta [TestMethod] public async Task Import_ShouldImportTracks_WithTraktorOutput() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Traktor Export.html"); await importView.SwitchImportProfileAsync("Traktor history"); + await importView.Analyze(); await importView.CompleteImportAsync(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: @@ -2139,5 +2144,233 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta await appBar.UndoAsync(); await Expect(TestPage.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Tracks has invalid Count (0)!" })).ToBeVisibleAsync(); } + + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingText() + { + var importView = new ImportView(TestPage, DeviceName != null); + var detailView = new DetailView(TestPage, DeviceName != null); + await importView.GotoAsync(); + var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); + await importView.ImportTextAsync(text); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + - rowgroup: + - row ""# Sort Column options Artist Sort Column options Title Sort Column options Begin Sort Column options End Sort Column options Length Sort Column options Status"": + - columnheader: + - checkbox + - columnheader ""# Sort Column options"": + - text: ""#"" + - button ""Sort"" + - button ""Column options"" + - columnheader ""Artist Sort Column options"": + - text: Artist + - button ""Sort"" + - button ""Column options"" + - columnheader ""Title Sort Column options"": + - text: Title + - button ""Sort"" + - button ""Column options"" + - columnheader ""Begin Sort Column options"": + - text: Begin + - button ""Sort"" + - button ""Column options"" + - columnheader ""End Sort Column options"": + - text: End + - button ""Sort"" + - button ""Column options"" + - columnheader ""Length Sort Column options"": + - text: Length + - button ""Sort"" + - button ""Column options"" + - columnheader ""Status"" + - rowgroup: + - row ""Increment Decrement Sample Artist 1 Clear Sample Title 1 Clear 00:00:00 00:05:00 00:05:00"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""1"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 1 Clear"": + - textbox: Sample Artist 1 + - button ""Clear"" + - button + - cell ""Sample Title 1 Clear"": + - textbox: Sample Title 1 + - button ""Clear"" + - button + - cell ""00:00:00"": + - textbox: 00:00:00 + - cell ""00:05:00"": + - textbox: 00:05:00 + - cell ""00:05:00"": + - textbox: 00:05:00 + - cell + - row ""Increment Decrement Sample Artist 2 Clear Sample Title 2 Clear 00:05:00 00:09:23 00:04:23"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""2"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 2 Clear"": + - textbox: Sample Artist 2 + - button ""Clear"" + - button + - cell ""Sample Title 2 Clear"": + - textbox: Sample Title 2 + - button ""Clear"" + - button + - cell ""00:05:00"": + - textbox: 00:05:00 + - cell ""00:09:23"": + - textbox: 00:09:23 + - cell ""00:04:23"": + - textbox: 00:04:23 + - cell: + - button + - row ""Increment Decrement Sample Artist 3 Clear Sample Title 3 Clear 00:09:23 00:15:54 00:06:31"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""3"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 3 Clear"": + - textbox: Sample Artist 3 + - button ""Clear"" + - button + - cell ""Sample Title 3 Clear"": + - textbox: Sample Title 3 + - button ""Clear"" + - button + - cell ""00:09:23"": + - textbox: 00:09:23 + - cell ""00:15:54"": + - textbox: 00:15:54 + - cell ""00:06:31"": + - textbox: 00:06:31 + - cell: + - button + - row ""Increment Decrement Sample Artist 4 Clear Sample Title 4 Clear 00:15:54 00:20:13 00:04:19"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""4"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 4 Clear"": + - textbox: Sample Artist 4 + - button ""Clear"" + - button + - cell ""Sample Title 4 Clear"": + - textbox: Sample Title 4 + - button ""Clear"" + - button + - cell ""00:15:54"": + - textbox: 00:15:54 + - cell ""00:20:13"": + - textbox: 00:20:13 + - cell ""00:04:19"": + - textbox: 00:04:19 + - cell: + - button + - row ""Increment Decrement Sample Artist 5 Clear Sample Title 5 Clear 00:20:13 00:24:54 00:04:41"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""5"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 5 Clear"": + - textbox: Sample Artist 5 + - button ""Clear"" + - button + - cell ""Sample Title 5 Clear"": + - textbox: Sample Title 5 + - button ""Clear"" + - button + - cell ""00:20:13"": + - textbox: 00:20:13 + - cell ""00:24:54"": + - textbox: 00:24:54 + - cell ""00:04:41"": + - textbox: 00:04:41 + - cell: + - button + - row ""Increment Decrement Sample Artist 6 Clear Sample Title 6 Clear 00:24:54 00:31:54 00:07:00"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""6"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 6 Clear"": + - textbox: Sample Artist 6 + - button ""Clear"" + - button + - cell ""Sample Title 6 Clear"": + - textbox: Sample Title 6 + - button ""Clear"" + - button + - cell ""00:24:54"": + - textbox: 00:24:54 + - cell ""00:31:54"": + - textbox: 00:31:54 + - cell ""00:07:00"": + - textbox: 00:07:00 + - cell: + - button + - row ""Increment Decrement Sample Artist 7 Clear Sample Title 7 Clear 00:31:54 00:45:54 00:14:00"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""7"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 7 Clear"": + - textbox: Sample Artist 7 + - button ""Clear"" + - button + - cell ""Sample Title 7 Clear"": + - textbox: Sample Title 7 + - button ""Clear"" + - button + - cell ""00:31:54"": + - textbox: 00:31:54 + - cell ""00:45:54"": + - textbox: 00:45:54 + - cell ""00:14:00"": + - textbox: 00:14:00 + - cell: + - button + - row ""Increment Decrement Sample Artist 8 Clear Sample Title 8 Clear 00:45:54 01:15:54 00:30:00"": + - cell: + - checkbox + - cell ""Increment Decrement"": + - spinbutton: ""8"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Sample Artist 8 Clear"": + - textbox: Sample Artist 8 + - button ""Clear"" + - button + - cell ""Sample Title 8 Clear"": + - textbox: Sample Title 8 + - button ""Clear"" + - button + - cell ""00:45:54"": + - textbox: 00:45:54 + - cell ""01:15:54"": + - textbox: 01:15:54 + - cell ""00:30:00"": + - textbox: 00:30:00 + - cell: + - button + - rowgroup: + - row"); + } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs index cab69387..94359479 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Desktop/TracingTest.cs @@ -423,11 +423,12 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta public async Task UndoRedo_ShouldRestoreCuesheet_WhenUsingImport() { var bar = new AppBar(TestPage); - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Textimport with Cuesheetdata.txt"); await importView.SetSchemeCommonDataAsync("Artist - Title - "); await importView.SelectSchemeCommonDataPlaceholderAsync("Cataloguenumber"); + await importView.Analyze(); await Expect(bar.UndoButton).ToBeDisabledAsync(); await Expect(bar.RedoButton).ToBeDisabledAsync(); await importView.CompleteImportAsync(); diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTestSmartphone.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTestSmartphone.cs index d33dafbc..33b743f5 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTestSmartphone.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/BasicTestSmartphone.cs @@ -109,9 +109,6 @@ public async Task KeyboardCommands_ShouldControlDialogs_WhenUsingEnterOrEscapeAs var bar = new AppBar(TestPage); var detailView = new DetailView(TestPage, DeviceName != null); await detailView.GotoAsync(); - await bar.OpenFileDialogAsync(); - await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); - await TestPage.Keyboard.PressAsync("Escape"); await TestPage.GetByRole(AriaRole.Dialog).WaitForAsync(new() { State = WaitForSelectorState.Detached }); await bar.OpenExportDialogAsync("Cuesheet"); await Expect(TestPage.GetByRole(AriaRole.Dialog)).ToBeVisibleAsync(); diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTestSmartphone.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTestSmartphone.cs index 93a01384..5b538dd2 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTestSmartphone.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/ImportTestSmartphone.cs @@ -26,10 +26,11 @@ public class ImportTestSmartphone : PlaywrightTestBase [TestMethod] public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); var detailView = new DetailView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); await importView.CompleteImportAsync(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: @@ -273,15 +274,16 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta - button"); await Expect(detailView.AudiofileInput).ToBeEmptyAsync(); await importView.GotoAsync(); - await Expect(TestPage.GetByText("PreviousNext")).ToBeVisibleAsync(); + await Expect(TestPage.GetByRole(AriaRole.Button, new() { Name = "Analyze" })).ToBeVisibleAsync(); } [TestMethod] public async Task Import_ShouldBeEditable_WhenEditingTrack() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Sample_Inputfile.txt"); + await importView.Analyze(); await importView.SelectTracksAsync([5]); await importView.EditTracksModalAsync("Sample Title Edited 5"); await importView.CompleteImportAsync(); @@ -530,10 +532,11 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta [TestMethod] public async Task Import_ShouldImportTracks_WithSpecialTextfile() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Textimport-Bug-#54.txt"); await importView.SwitchImportProfileAsync("Textfile (just track data)"); + await importView.Analyze(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: - row ""# Increment Decrement Artist Adriatique Clear Title X. Clear Begin 00:00:00 End 00:05:24 Length 00:05:24"": @@ -1594,10 +1597,11 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta [TestMethod] public async Task Import_ShouldImportTracks_WhenUsingSampleInputfile2() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Sample_Inputfile2.txt"); await importView.ClearSchemeCommonDataAsync(); + await importView.Analyze(); await Expect(importView.CuesheetArtistInput).ToBeEmptyAsync(); await Expect(importView.CuesheetTitleInput).ToBeEmptyAsync(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: @@ -1823,10 +1827,11 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta [TestMethod] public async Task Import_ShouldImportTracks_WithTraktorOutput() { - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Traktor Export.html"); await importView.SwitchImportProfileAsync("Traktor history"); + await importView.Analyze(); await importView.CompleteImportAsync(); await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: - rowgroup: @@ -3564,5 +3569,257 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta await appBar.UndoAsync(); await Expect(TestPage.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Tracks has invalid Count (0)!" })).ToBeVisibleAsync(); } + + [TestMethod] + public async Task Import_ShouldImportTracks_WhenUsingText() + { + var importView = new ImportView(TestPage, DeviceName != null); + var detailView = new DetailView(TestPage, DeviceName != null); + await importView.GotoAsync(); + var text = String.Join(Environment.NewLine, File.ReadAllLines("Sample_Inputfile.txt")); + await importView.ImportTextAsync(text); + await importView.Analyze(); + await importView.CompleteImportAsync(); + await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- table: + - rowgroup: + - row ""# Increment Decrement Artist Sample Artist 1 Clear Title Sample Title 1 Clear Begin 00:00:00 End 00:05:00 Length 00:05:00 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""1"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 1 Clear"": + - text: Artist + - textbox: Sample Artist 1 + - button ""Clear"" + - button + - cell ""Title Sample Title 1 Clear"": + - text: Title + - textbox: Sample Title 1 + - button ""Clear"" + - button + - cell ""Begin 00:00:00"": + - text: Begin + - textbox: 00:00:00 + - cell ""End 00:05:00"": + - text: End + - textbox: 00:05:00 + - cell ""Length 00:05:00"": + - text: Length + - textbox: 00:05:00 + - cell ""Status"" + - row ""# Increment Decrement Artist Sample Artist 2 Clear Title Sample Title 2 Clear Begin 00:05:00 End 00:09:23 Length 00:04:23 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""2"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 2 Clear"": + - text: Artist + - textbox: Sample Artist 2 + - button ""Clear"" + - button + - cell ""Title Sample Title 2 Clear"": + - text: Title + - textbox: Sample Title 2 + - button ""Clear"" + - button + - cell ""Begin 00:05:00"": + - text: Begin + - textbox: 00:05:00 + - cell ""End 00:09:23"": + - text: End + - textbox: 00:09:23 + - cell ""Length 00:04:23"": + - text: Length + - textbox: 00:04:23 + - cell ""Status"": + - text: Status + - button + - row ""# Increment Decrement Artist Sample Artist 3 Clear Title Sample Title 3 Clear Begin 00:09:23 End 00:15:54 Length 00:06:31 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""3"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 3 Clear"": + - text: Artist + - textbox: Sample Artist 3 + - button ""Clear"" + - button + - cell ""Title Sample Title 3 Clear"": + - text: Title + - textbox: Sample Title 3 + - button ""Clear"" + - button + - cell ""Begin 00:09:23"": + - text: Begin + - textbox: 00:09:23 + - cell ""End 00:15:54"": + - text: End + - textbox: 00:15:54 + - cell ""Length 00:06:31"": + - text: Length + - textbox: 00:06:31 + - cell ""Status"": + - text: Status + - button + - row ""# Increment Decrement Artist Sample Artist 4 Clear Title Sample Title 4 Clear Begin 00:15:54 End 00:20:13 Length 00:04:19 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""4"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 4 Clear"": + - text: Artist + - textbox: Sample Artist 4 + - button ""Clear"" + - button + - cell ""Title Sample Title 4 Clear"": + - text: Title + - textbox: Sample Title 4 + - button ""Clear"" + - button + - cell ""Begin 00:15:54"": + - text: Begin + - textbox: 00:15:54 + - cell ""End 00:20:13"": + - text: End + - textbox: 00:20:13 + - cell ""Length 00:04:19"": + - text: Length + - textbox: 00:04:19 + - cell ""Status"": + - text: Status + - button + - row ""# Increment Decrement Artist Sample Artist 5 Clear Title Sample Title 5 Clear Begin 00:20:13 End 00:24:54 Length 00:04:41 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""5"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 5 Clear"": + - text: Artist + - textbox: Sample Artist 5 + - button ""Clear"" + - button + - cell ""Title Sample Title 5 Clear"": + - text: Title + - textbox: Sample Title 5 + - button ""Clear"" + - button + - cell ""Begin 00:20:13"": + - text: Begin + - textbox: 00:20:13 + - cell ""End 00:24:54"": + - text: End + - textbox: 00:24:54 + - cell ""Length 00:04:41"": + - text: Length + - textbox: 00:04:41 + - cell ""Status"": + - text: Status + - button + - row ""# Increment Decrement Artist Sample Artist 6 Clear Title Sample Title 6 Clear Begin 00:24:54 End 00:31:54 Length 00:07:00 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""6"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 6 Clear"": + - text: Artist + - textbox: Sample Artist 6 + - button ""Clear"" + - button + - cell ""Title Sample Title 6 Clear"": + - text: Title + - textbox: Sample Title 6 + - button ""Clear"" + - button + - cell ""Begin 00:24:54"": + - text: Begin + - textbox: 00:24:54 + - cell ""End 00:31:54"": + - text: End + - textbox: 00:31:54 + - cell ""Length 00:07:00"": + - text: Length + - textbox: 00:07:00 + - cell ""Status"": + - text: Status + - button + - row ""# Increment Decrement Artist Sample Artist 7 Clear Title Sample Title 7 Clear Begin 00:31:54 End 00:45:54 Length 00:14:00 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""7"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 7 Clear"": + - text: Artist + - textbox: Sample Artist 7 + - button ""Clear"" + - button + - cell ""Title Sample Title 7 Clear"": + - text: Title + - textbox: Sample Title 7 + - button ""Clear"" + - button + - cell ""Begin 00:31:54"": + - text: Begin + - textbox: 00:31:54 + - cell ""End 00:45:54"": + - text: End + - textbox: 00:45:54 + - cell ""Length 00:14:00"": + - text: Length + - textbox: 00:14:00 + - cell ""Status"": + - text: Status + - button + - row ""# Increment Decrement Artist Sample Artist 8 Clear Title Sample Title 8 Clear Begin 00:45:54 End 01:15:54 Length 00:30:00 Status"": + - cell: + - checkbox + - cell ""# Increment Decrement"": + - text: ""#"" + - spinbutton: ""8"" + - button ""Increment"" + - button ""Decrement"" + - cell ""Artist Sample Artist 8 Clear"": + - text: Artist + - textbox: Sample Artist 8 + - button ""Clear"" + - button + - cell ""Title Sample Title 8 Clear"": + - text: Title + - textbox: Sample Title 8 + - button ""Clear"" + - button + - cell ""Begin 00:45:54"": + - text: Begin + - textbox: 00:45:54 + - cell ""End 01:15:54"": + - text: End + - textbox: 01:15:54 + - cell ""Length 00:30:00"": + - text: Length + - textbox: 00:30:00 + - cell ""Status"": + - text: Status + - button"); + } } } diff --git a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTestSmartphone.cs b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTestSmartphone.cs index 0ada9314..5ad6a5b6 100644 --- a/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTestSmartphone.cs +++ b/AudioCuesheetEditor.End2EndTests/Tests/Smartphone/TracingTestSmartphone.cs @@ -244,11 +244,12 @@ await Expect(TestPage.GetByRole(AriaRole.Table)).ToMatchAriaSnapshotAsync(@"- ta public async Task UndoRedo_ShouldRestoreCuesheet_WhenUsingImport() { var bar = new AppBar(TestPage); - var importView = new ImportView(TestPage); + var importView = new ImportView(TestPage, DeviceName != null); await importView.GotoAsync(); await importView.ImportFileAsync("Textimport with Cuesheetdata.txt"); await importView.SetSchemeCommonDataAsync("Artist - Title - "); await importView.SelectSchemeCommonDataPlaceholderAsync("Cataloguenumber"); + await importView.Analyze(); await Expect(bar.UndoButton).ToBeDisabledAsync(); await Expect(bar.RedoButton).ToBeDisabledAsync(); await importView.CompleteImportAsync(); diff --git a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs index 38a2ed33..f5893914 100644 --- a/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs +++ b/AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs @@ -131,7 +131,7 @@ public async Task AnalyseImportfile_WithoutAnalysedCuesheet_DoesNothing() } [TestMethod] - public async Task ImportFilesAsync_ProjectFile_ImportsCorrectly() + public async Task UploadFilesAsync_ProjectFile_ImportsCorrectly() { // Arrange var fileContent = "This is the content"; @@ -147,7 +147,7 @@ public async Task ImportFilesAsync_ProjectFile_ImportsCorrectly() var loggerMock = new Mock>(); var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object); // Act - await importManager.ImportFilesAsync([file]); + await importManager.UploadFilesAsync([file]); // Assert Assert.IsNotNull(sessionStateContainer.Importfile); @@ -157,7 +157,7 @@ public async Task ImportFilesAsync_ProjectFile_ImportsCorrectly() } [TestMethod] - public async Task ImportFilesAsync_CuesheetFile_ImportsCorrectly() + public async Task UploadFilesAsync_CuesheetFile_ImportsCorrectly() { // Arrange var fileContent = "Cuesheet file content"; @@ -173,7 +173,7 @@ public async Task ImportFilesAsync_CuesheetFile_ImportsCorrectly() var loggerMock = new Mock>(); var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object); // Act - await importManager.ImportFilesAsync([file]); + await importManager.UploadFilesAsync([file]); // Assert Assert.IsNotNull(sessionStateContainer.Importfile); @@ -183,7 +183,7 @@ public async Task ImportFilesAsync_CuesheetFile_ImportsCorrectly() } [TestMethod] - public async Task ImportFilesAsync_TextFile_ImportsCorrectly() + public async Task UploadFilesAsync_TextFile_ImportsCorrectly() { // Arrange var fileContent = "TextFileContent"; @@ -199,7 +199,7 @@ public async Task ImportFilesAsync_TextFile_ImportsCorrectly() var loggerMock = new Mock>(); var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object); // Act - await importManager.ImportFilesAsync([file]); + await importManager.UploadFilesAsync([file]); // Assert Assert.IsNotNull(sessionStateContainer.Importfile); @@ -208,6 +208,31 @@ public async Task ImportFilesAsync_TextFile_ImportsCorrectly() Assert.AreEqual(ImportFileType.Textfile, sessionStateContainer.Importfile.FileType); } + [TestMethod] + public async Task UploadFilesAsync_WithAudiofile_ImportsCorrectly() + { + // Arrange + var file = CreateBrowserFileMock("test.mp3"); + var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger()); + var sessionStateContainer = new SessionStateContainer(traceChangeManager); + var fileInputManagerMock = new Mock(); + var textImportServiceMock = new Mock(); + fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Projectfile, It.IsAny>())).Returns(false); + fileInputManagerMock.Setup(f => f.CheckFileMimeType(file, FileMimeTypes.Cuesheet, It.IsAny>())).Returns(false); + fileInputManagerMock.Setup(f => f.IsValidForImportView(file)).Returns(false); + fileInputManagerMock.Setup(f => f.IsValidAudiofile(file)).Returns(true); + fileInputManagerMock.Setup(f => f.CreateAudiofileAsync(It.IsAny(), It.IsAny(), It.IsAny>?>())).ReturnsAsync(new AudioCuesheetEditor.Model.IO.Audio.Audiofile(file.Name)); + + var loggerMock = new Mock>(); + var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object); + // Act + await importManager.UploadFilesAsync([file]); + + // Assert + Assert.IsNull(sessionStateContainer.Importfile); + Assert.IsNotNull(sessionStateContainer.ImportAudiofile); + } + [TestMethod] public void ImportCuesheet_WithImportCuesheetAvailable_ImportsCuesheetData() { @@ -252,6 +277,26 @@ public void ImportCuesheet_WithImportCuesheetAvailable_ImportsCuesheetData() traceChangeManagerMock.Verify(x => x.RemoveTracedChanges(It.IsAny>())); } + [TestMethod] + public void ImportData_ValidData_SetsImportfile() + { + // Arrange + var traceChangeManagerMock = new Mock(); + var sessionStateContainer = new SessionStateContainer(traceChangeManagerMock.Object); + var importdata = nameof(ImportData_ValidData_SetsImportfile); + var fileInputManagerMock = new Mock(); + var textImportServiceMock = new Mock(); + var loggerMock = new Mock>(); + var importManager = new ImportManager(sessionStateContainer, traceChangeManagerMock.Object, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object); + // Act + importManager.ImportData(importdata); + // Assert + Assert.IsNotNull(sessionStateContainer.Importfile); + Assert.AreEqual(importdata, sessionStateContainer.Importfile.FileContent); + Assert.AreEqual(importdata, sessionStateContainer.Importfile.FileContentRecognized); + Assert.AreEqual(ImportFileType.Textfile, sessionStateContainer.Importfile.FileType); + } + private static IBrowserFile CreateBrowserFileMock(string name, string content = "TestContent") { var fileMock = new Mock(); diff --git a/AudioCuesheetEditor/App.razor b/AudioCuesheetEditor/App.razor index 6fd3ed1b..9b89a2a6 100644 --- a/AudioCuesheetEditor/App.razor +++ b/AudioCuesheetEditor/App.razor @@ -1,4 +1,16 @@ - +@* Required *@ + + + +@* Needed for dialogs *@ + + +@* Needed for snackbars *@ + + + + + @@ -9,4 +21,4 @@

Sorry, there's nothing at this address.

-
+
\ No newline at end of file diff --git a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs index 5704dbe9..5ad6f513 100644 --- a/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs +++ b/AudioCuesheetEditor/Model/IO/Import/IImportfile.cs @@ -36,6 +36,9 @@ public interface IImportfile /// The cue sheet which was created during analyzing the /// ImportCuesheet? AnalyzedCuesheet { get; set; } + /// + /// Type of file (text, cuesheet, project, etc.) + /// ImportFileType FileType { get; set; } } } diff --git a/AudioCuesheetEditor/Pages/Index.razor b/AudioCuesheetEditor/Pages/Index.razor index 64a3150d..8fe46021 100644 --- a/AudioCuesheetEditor/Pages/Index.razor +++ b/AudioCuesheetEditor/Pages/Index.razor @@ -21,6 +21,10 @@ along with Foobar. If not, see @inherits BaseLocalizedComponent @inject IStringLocalizer _localizer +@inject ImportManager _importManager +@inject ISessionStateContainer _sessionStateContainer +@inject DialogManager _dialogManager +@inject ISnackbar _snackbar @@ -40,12 +44,25 @@ along with Foobar. If not, see ViewOptions? options; ViewMode currentViewmode = ViewMode.DetailView; + public Cuesheet? Cuesheet + { + get + { + if (currentViewmode == ViewMode.ImportView) + { + return _sessionStateContainer.ImportCuesheet; + } + return _sessionStateContainer.Cuesheet; + } + } + protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); options = await base.LocalStorageOptionsProvider.GetOptionsAsync(); currentViewmode = options.ActiveTab; base.LocalStorageOptionsProvider.OptionSaved += LocalStorageOptionsProvider_OptionSaved; + _importManager.UploadFilesFinished += ImportManager_UploadFilesFinished; } protected override void Dispose(bool disposing) @@ -54,6 +71,7 @@ along with Foobar. If not, see if (disposing) { base.LocalStorageOptionsProvider.OptionSaved -= LocalStorageOptionsProvider_OptionSaved; + _importManager.UploadFilesFinished -= ImportManager_UploadFilesFinished; } } @@ -72,4 +90,45 @@ along with Foobar. If not, see StateHasChanged(); } } + + void ImportManager_UploadFilesFinished(object? sender, IEnumerable invalidFiles) + { + InvokeAsync(async () => + { + try + { + if (invalidFiles.Any()) + { + foreach (var file in invalidFiles) + { + string message = _localizer["{0} can not be processed!", file].ToString(); + _snackbar.Add(message, Severity.Warning, config => + { + config.RequireInteraction = true; + }); + } + } + await _dialogManager.ShowLoadingDialogAsync(); + switch (_sessionStateContainer.Importfile?.FileType) + { + case ImportFileType.ProjectFile: + case ImportFileType.Cuesheet: + await _importManager.AnalyseImportfile(); + _sessionStateContainer.ResetImport(); + break; + case ImportFileType.Textfile: + await LocalStorageOptionsProvider.SaveOptionsValueAsync(x => x.ActiveTab, ViewMode.ImportView); + break; + } + if ((Cuesheet != null) && (_sessionStateContainer.ImportAudiofile != null)) + { + Cuesheet.Audiofile = _sessionStateContainer.ImportAudiofile; + } + } + finally + { + _dialogManager.HideLoadingDialog(); + } + }); + } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Program.cs b/AudioCuesheetEditor/Program.cs index 8d470618..dc5ef590 100644 --- a/AudioCuesheetEditor/Program.cs +++ b/AudioCuesheetEditor/Program.cs @@ -37,7 +37,10 @@ builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddLocalization(); -builder.Services.AddMudServices(); +builder.Services.AddMudServices(config => +{ + config.PopoverOptions.OverflowPadding = 0; +}); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/AudioCuesheetEditor/Services/IO/FileInputManager.cs b/AudioCuesheetEditor/Services/IO/FileInputManager.cs index 96129e13..78154ac4 100644 --- a/AudioCuesheetEditor/Services/IO/FileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/FileInputManager.cs @@ -132,5 +132,12 @@ public bool IsValidForImportView(IBrowserFile browserFile) { return CheckFileMimeType(browserFile, FileMimeTypes.Text, [FileExtensions.Text, FileExtensions.HTML]); } + + /// + public async Task ReadFileContentAsync(IBrowserFile browserFile) + { + var fileContent = new StreamContent(browserFile.OpenReadStream()); + return await fileContent.ReadAsStringAsync(); + } } } diff --git a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs index 6bf15fef..e5d00d13 100644 --- a/AudioCuesheetEditor/Services/IO/IFileInputManager.cs +++ b/AudioCuesheetEditor/Services/IO/IFileInputManager.cs @@ -33,5 +33,11 @@ public interface IFileInputManager /// /// bool IsValidForImportView(IBrowserFile browserFile); + /// + /// Reads the browser file and gets the file content as string + /// + /// + /// + Task ReadFileContentAsync(IBrowserFile browserFile); } } \ No newline at end of file diff --git a/AudioCuesheetEditor/Services/IO/ImportManager.cs b/AudioCuesheetEditor/Services/IO/ImportManager.cs index ba80e27c..a1323d13 100644 --- a/AudioCuesheetEditor/Services/IO/ImportManager.cs +++ b/AudioCuesheetEditor/Services/IO/ImportManager.cs @@ -18,7 +18,6 @@ using AudioCuesheetEditor.Model.IO; using AudioCuesheetEditor.Model.IO.Audio; using AudioCuesheetEditor.Model.IO.Import; -using AudioCuesheetEditor.Model.UI; using AudioCuesheetEditor.Services.UI; using Microsoft.AspNetCore.Components.Forms; using System.Diagnostics; @@ -35,59 +34,25 @@ public enum ImportFileType } public class ImportManager(ISessionStateContainer sessionStateContainer, ITraceChangeManager traceChangeManager, IFileInputManager fileInputManager, ITextImportService textImportService, ILogger logger) { + public event EventHandler>? UploadFilesFinished; + private readonly ILogger _logger = logger; private readonly ISessionStateContainer _sessionStateContainer = sessionStateContainer; private readonly ITraceChangeManager _traceChangeManager = traceChangeManager; private readonly IFileInputManager _fileInputManager = fileInputManager; private readonly ITextImportService _textImportService = textImportService; - public async Task ImportFilesAsync(IEnumerable files) + public void ImportData(String? data) { var stopwatch = Stopwatch.StartNew(); - foreach (var file in files) + _sessionStateContainer.Importfile = new Importfile() { - if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Projectfile, [FileExtensions.Projectfile])) - { - var fileContent = await ReadFileContentAsync(file); - fileContent.Position = 0; - using var reader = new StreamReader(fileContent); - var stringFileContent = reader.ReadToEnd(); - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = stringFileContent, - FileContentRecognized = stringFileContent, - FileType = ImportFileType.ProjectFile - }; - } - if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet])) - { - var fileContent = await ReadFileContentAsync(file); - fileContent.Position = 0; - using var reader = new StreamReader(fileContent); - var stringFileContent = reader.ReadToEnd(); - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = stringFileContent, - FileContentRecognized = stringFileContent, - FileType = ImportFileType.Cuesheet - }; - } - if (_fileInputManager.IsValidForImportView(file)) - { - var fileContent = await ReadFileContentAsync(file); - fileContent.Position = 0; - using var reader = new StreamReader(fileContent); - var stringFileContent = reader.ReadToEnd(); - _sessionStateContainer.Importfile = new Importfile() - { - FileContent = stringFileContent, - FileContentRecognized = stringFileContent, - FileType = ImportFileType.Textfile - }; - } - } + FileContent = data, + FileContentRecognized = data, + FileType = ImportFileType.Textfile + }; stopwatch.Stop(); - _logger.LogDebug("ImportFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + _logger.LogDebug("ImportData duration: {stopwatch.Elapsed}", stopwatch.Elapsed); } public async Task AnalyseImportfile() @@ -146,6 +111,72 @@ public void ImportCuesheet() _logger.LogDebug("ImportCuesheet duration: {stopwatch.Elapsed}", stopwatch.Elapsed); } + public async Task UploadFilesAsync(IEnumerable files, String? fileInputId = null) + { + var stopwatch = Stopwatch.StartNew(); + var invalidFiles = new List(); + foreach (var file in files) + { + if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) + || _fileInputManager.CheckFileMimeType(file, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) + || _fileInputManager.IsValidForImportView(file) + || _fileInputManager.IsValidAudiofile(file)) + { + if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Projectfile, [FileExtensions.Projectfile])) + { + var fileContent = await ReadFileContentAsync(file); + fileContent.Position = 0; + using var reader = new StreamReader(fileContent); + var stringFileContent = reader.ReadToEnd(); + _sessionStateContainer.Importfile = new Importfile() + { + FileContent = stringFileContent, + FileContentRecognized = stringFileContent, + FileType = ImportFileType.ProjectFile + }; + } + if (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet])) + { + var fileContent = await ReadFileContentAsync(file); + fileContent.Position = 0; + using var reader = new StreamReader(fileContent); + var stringFileContent = reader.ReadToEnd(); + _sessionStateContainer.Importfile = new Importfile() + { + FileContent = stringFileContent, + FileContentRecognized = stringFileContent, + FileType = ImportFileType.Cuesheet + }; + } + if (_fileInputManager.IsValidForImportView(file)) + { + var fileContent = await ReadFileContentAsync(file); + fileContent.Position = 0; + using var reader = new StreamReader(fileContent); + var stringFileContent = reader.ReadToEnd(); + _sessionStateContainer.Importfile = new Importfile() + { + FileContent = stringFileContent, + FileContentRecognized = stringFileContent, + FileType = ImportFileType.Textfile + }; + } + if (_fileInputManager.IsValidAudiofile(file)) + { + var audioFile = await _fileInputManager.CreateAudiofileAsync(fileInputId, file); + _sessionStateContainer.ImportAudiofile = audioFile; + } + } + else + { + invalidFiles.Add(file.Name); + } + } + UploadFilesFinished?.Invoke(this, invalidFiles); + stopwatch.Stop(); + _logger.LogDebug("UploadFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed); + } + private static async Task ReadFileContentAsync(IBrowserFile file) { var fileContent = new MemoryStream(); diff --git a/AudioCuesheetEditor/Services/UI/DialogManager.cs b/AudioCuesheetEditor/Services/UI/DialogManager.cs index 1ebc1724..f10ac2bb 100644 --- a/AudioCuesheetEditor/Services/UI/DialogManager.cs +++ b/AudioCuesheetEditor/Services/UI/DialogManager.cs @@ -186,6 +186,7 @@ public async Task ShowLoadingDialogAsync() { var options = new DialogOptions() { BackdropClick = false, FullWidth = true, MaxWidth = MaxWidth.ExtraSmall, NoHeader = true }; loadingDialog = await _dialogService.ShowAsync(null, options); + await Task.Delay(1); } } diff --git a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs index 10796b37..4dcd0aca 100644 --- a/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/ISessionStateContainer.cs @@ -28,5 +28,6 @@ public interface ISessionStateContainer public Audiofile? ImportAudiofile { get; set; } public IImportfile? Importfile { get; set; } public void ResetImport(); + public Boolean ImportIsAnalyzed { get; set; } } } diff --git a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs index 494b234e..b1a7b0df 100644 --- a/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs +++ b/AudioCuesheetEditor/Services/UI/SessionStateContainer.cs @@ -77,6 +77,7 @@ public Audiofile? ImportAudiofile } public IImportfile? Importfile{ get; set; } + public Boolean ImportIsAnalyzed { get; set; } = false; public void ResetImport() { diff --git a/AudioCuesheetEditor/Shared/AppBar.razor b/AudioCuesheetEditor/Shared/AppBar.razor index 244e83c7..0bae44a1 100644 --- a/AudioCuesheetEditor/Shared/AppBar.razor +++ b/AudioCuesheetEditor/Shared/AppBar.razor @@ -24,7 +24,6 @@ along with Foobar. If not, see @inject ISessionStateContainer _sessionStateContainer @inject IJSRuntime _jsRuntime @inject HotKeys _hotKeys -@inject DialogManager _dialogManager @inject ImportManager _importManager @@ -47,6 +46,7 @@ along with Foobar. If not, see @if (DisplayFileMenu) { + @_localizer["Open"] @@ -83,6 +83,7 @@ along with Foobar. If not, see @code { HotKeysContext? hotKeysContext; + MudFileUpload? mudFileUpload; protected override void OnInitialized() { @@ -188,17 +189,17 @@ along with Foobar. If not, see async Task OpenFileClicked() { - var options = new DialogOptions() { BackdropClick = false, CloseOnEscapeKey = true, CloseButton = true }; - var dialog = await _dialogService.ShowAsync(_localizer["Select file"], options); - var result = await dialog.Result; - if (result?.Canceled == false) + if (mudFileUpload != null) { - await _dialogManager.ShowLoadingDialogAsync(); - await _importManager.AnalyseImportfile(); - _dialogManager.HideLoadingDialog(); + await mudFileUpload.OpenFilePickerAsync(); } } + async Task FileUploaded(IBrowserFile file) + { + await _importManager.UploadFilesAsync([file]); + } + async Task DisplayHotkeys() { var options = new DialogOptions() { BackdropClick = false, CloseOnEscapeKey = true, CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Large }; diff --git a/AudioCuesheetEditor/Shared/Dialogs/SelectFileDialog.de.resx b/AudioCuesheetEditor/Shared/Dialogs/SelectFileDialog.de.resx deleted file mode 100644 index 24c65e85..00000000 --- a/AudioCuesheetEditor/Shared/Dialogs/SelectFileDialog.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 - - - Sie haben eine ungültige Datei ({0}) hinzugefügt die nicht verarbeitet werden kann. - - \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Dialogs/SelectFileDialog.razor b/AudioCuesheetEditor/Shared/Dialogs/SelectFileDialog.razor deleted file mode 100644 index 8198bb4f..00000000 --- a/AudioCuesheetEditor/Shared/Dialogs/SelectFileDialog.razor +++ /dev/null @@ -1,66 +0,0 @@ - -@inherits BaseLocalizedComponent - -@inject IStringLocalizer _localizer -@inject ImportManager _importManager -@inject IFileInputManager _fileInputManager - - - -
- - - - @foreach (var invalidFileName in invalidDropFileNames) - { - - @String.Format(_localizer["You dropped an invalid file ({0}) that can not be processed."], invalidFileName) - - } - - -
-
-
- -@code { - [CascadingParameter] - private IMudDialogInstance? MudDialog { get; set; } - - string dropFileInputId = "dropFileInputId_SelectFileDialog"; - List invalidDropFileNames = new(); - - async Task InputFilesChanged(IReadOnlyCollection files) - { - invalidDropFileNames.Clear(); - foreach (var file in files) - { - if ((_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Projectfile, [FileExtensions.Projectfile]) == false) - && (_fileInputManager.CheckFileMimeType(file, FileMimeTypes.Cuesheet, [FileExtensions.Cuesheet]) == false)) - { - invalidDropFileNames.Add(file.Name); - } - } - if (invalidDropFileNames.Count == 0) - { - await _importManager.ImportFilesAsync(files); - MudDialog?.Close(); - } - } -} diff --git a/AudioCuesheetEditor/Shared/Import/SelectImportFiles.resx b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.de.resx similarity index 95% rename from AudioCuesheetEditor/Shared/Import/SelectImportFiles.resx rename to AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.de.resx index 062757f8..48c3b602 100644 --- a/AudioCuesheetEditor/Shared/Import/SelectImportFiles.resx +++ b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.de.resx @@ -117,10 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Select files for import + + Allgemeine Informationen - - You dropped an invalid file ({0}) that can not be processed. + + Fehler während des Textimports + + + Titel \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Import/ImportFileContent.razor b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor similarity index 50% rename from AudioCuesheetEditor/Shared/Import/ImportFileContent.razor rename to AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor index 894b9e15..60e287c7 100644 --- a/AudioCuesheetEditor/Shared/Import/ImportFileContent.razor +++ b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.razor @@ -17,34 +17,49 @@ along with Foobar. If not, see --> @inherits BaseLocalizedComponent -@inject IStringLocalizer _localizer +@inject IStringLocalizer _localizer @inject ISessionStateContainer _sessionStateContainer - - - -
-                @if (FileContentRecognized != null)
-                {
-                    @((MarkupString)SanitizeHTML(FileContentRecognized))
-                }
-            
-
-
- - - -
+ +
+        @if (FileContentRecognized != null)
+        {
+            @((MarkupString)SanitizeHTML(FileContentRecognized))
+        }
+    
+
+@if (_sessionStateContainer.Importfile?.AnalyseException != null) +{ + + @_localizer["Error during textimport"] : @_sessionStateContainer.Importfile.AnalyseException.Message + +} +else +{ + + + + @_localizer["Common data"] + + + + + + + + @_localizer["Tracks"] + + + + + + +} @code { - [Parameter] - public EventCallback FileContentChanged { get; set; } - public String? FileContentRecognized => _sessionStateContainer.Importfile?.FileContentRecognized; + Boolean cuesheetDataExpanded = true, cuesheetTracksExpanded = true; - async Task FileContent_TextChangedAsync(string newFileContent) - { - await FileContentChanged.InvokeAsync(newFileContent); - } + public String? FileContentRecognized => _sessionStateContainer.Importfile?.FileContentRecognized; string SanitizeHTML(string input) { diff --git a/AudioCuesheetEditor/Shared/Import/ImportFileContent.de.resx b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.resx similarity index 95% rename from AudioCuesheetEditor/Shared/Import/ImportFileContent.de.resx rename to AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.resx index cb591bb2..f4f133c6 100644 --- a/AudioCuesheetEditor/Shared/Import/ImportFileContent.de.resx +++ b/AudioCuesheetEditor/Shared/Import/DisplayAnalyzedResult.resx @@ -117,10 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Analysierter Dateiinhalt + + Common data - - Bearbeiten + + Error during textimport + + + Tracks \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Import/Importprofiles.de.resx b/AudioCuesheetEditor/Shared/Import/Importprofiles.de.resx index a7736980..56ba6509 100644 --- a/AudioCuesheetEditor/Shared/Import/Importprofiles.de.resx +++ b/AudioCuesheetEditor/Shared/Import/Importprofiles.de.resx @@ -141,6 +141,9 @@ Tage + + Ausgewähltes Profil löschen + Ende @@ -162,9 +165,6 @@ Stunden - - Import Profil - Länge @@ -189,8 +189,14 @@ Vorlücke + + Profildetails + - Profil Name + Profilname + + + Importprofile zurücksetzen Schema Allgemeine Informationen @@ -204,6 +210,9 @@ Sekunden + + Ausgewähltes Profil + Startzeitpunkt diff --git a/AudioCuesheetEditor/Shared/Import/Importprofiles.razor b/AudioCuesheetEditor/Shared/Import/Importprofiles.razor index 57e6a842..5933864f 100644 --- a/AudioCuesheetEditor/Shared/Import/Importprofiles.razor +++ b/AudioCuesheetEditor/Shared/Import/Importprofiles.razor @@ -24,13 +24,14 @@ along with Foobar. If not, see @if (importOptions != null) { - + @foreach (var profile in importOptions.ImportProfiles) { @profile.Name } - + @_localizer["Delete selected profile"] @@ -39,55 +40,55 @@ along with Foobar. If not, see - @_localizer["Reset import schemes"] + @_localizer["Reset import profiles"] - + - - - - - @foreach (var scheme in Importprofile.AvailableSchemeCuesheet) - { - @_localizer[scheme] - } - - - - @foreach (var scheme in Importprofile.AvailableSchemesTrack) - { - @_localizer[scheme] - } - - - - @foreach (var scheme in TimeSpanFormat.AvailableTimespanScheme) - { - @_localizer[scheme] - } - + + + + + + @foreach (var scheme in Importprofile.AvailableSchemeCuesheet) + { + @_localizer[scheme] + } + + + + @foreach (var scheme in Importprofile.AvailableSchemesTrack) + { + @_localizer[scheme] + } + + + + @foreach (var scheme in TimeSpanFormat.AvailableTimespanScheme) + { + @_localizer[scheme] + } + + + } @code { - [Parameter] - public EventCallback ImportprofileChanged { get; set; } - ImportOptions? importOptions; MudMenu? schemeCuesheetMenu, schemeTracksMenu, timeSpanFormatMenu; MudTextField? schemeCuesheetTextField, schemeTracksTextField, timeSpanFormatTextField; @@ -113,25 +114,21 @@ along with Foobar. If not, see async Task SelectedImportProfileChangedAsync(Importprofile? newSelectedProfile) { await LocalStorageOptionsProvider.SaveOptionsValueAsync(x => x.SelectedImportProfile, newSelectedProfile); - await ImportprofileChanged.InvokeAsync(); } async Task UseRegularExpressionChangedAsync(Boolean? newValue) { await LocalStorageOptionsProvider.SaveNestedOptionValueAsync(x => x.SelectedImportProfile, x => x!.UseRegularExpression, newValue!.Value); - await ImportprofileChanged.InvokeAsync(); } async Task SchemeCuesheetChangedAsync(string newScheme) { await LocalStorageOptionsProvider.SaveNestedOptionValueAsync(x => x.SelectedImportProfile, x => x!.SchemeCuesheet, newScheme); - await ImportprofileChanged.InvokeAsync(); } async Task SchemeTracksChangedAsync(string newScheme) { await LocalStorageOptionsProvider.SaveNestedOptionValueAsync(x => x.SelectedImportProfile, x => x!.SchemeTracks, newScheme); - await ImportprofileChanged.InvokeAsync(); } async Task ImportTimeInputFormatChangedAsync(string newScheme) @@ -149,7 +146,6 @@ along with Foobar. If not, see format = new() { Scheme = newScheme }; } await LocalStorageOptionsProvider.SaveOptionsValueAsync(x => x.SelectedImportProfile!.TimeSpanFormat, format); - await ImportprofileChanged.InvokeAsync(); } } @@ -167,7 +163,7 @@ along with Foobar. If not, see return validationErrorMessage; } - async Task ResetSchemes() + async Task ResetProfiles() { var parameters = new DialogParameters { @@ -180,7 +176,6 @@ along with Foobar. If not, see importOptions!.ImportProfiles = ImportOptions.DefaultImportprofiles; importOptions!.SelectedImportProfile = ImportOptions.DefaultSelectedImportprofile; await LocalStorageOptionsProvider.SaveOptionsAsync(importOptions); - await ImportprofileChanged.InvokeAsync(); } } @@ -202,7 +197,6 @@ along with Foobar. If not, see }; importOptions!.SelectedImportProfile = profile; await LocalStorageOptionsProvider.SaveOptionsAsync(importOptions); - await ImportprofileChanged.InvokeAsync(); } async Task DeleteImportprofileClick() diff --git a/AudioCuesheetEditor/Shared/Import/Importprofiles.resx b/AudioCuesheetEditor/Shared/Import/Importprofiles.resx index 5bd62cc2..75f0fce7 100644 --- a/AudioCuesheetEditor/Shared/Import/Importprofiles.resx +++ b/AudioCuesheetEditor/Shared/Import/Importprofiles.resx @@ -141,6 +141,9 @@ Days + + Delete selected profile + End @@ -162,9 +165,6 @@ Hours - - Import profile - Length @@ -189,9 +189,15 @@ PreGap + + Profile details + Profile name + + Reset import profiles + Scheme common data @@ -204,6 +210,9 @@ Seconds + + Selected profile + StartDateTime diff --git a/AudioCuesheetEditor/Shared/Import/SelectImportFiles.de.resx b/AudioCuesheetEditor/Shared/Import/SelectImportFiles.de.resx deleted file mode 100644 index 4fbd4abb..00000000 --- a/AudioCuesheetEditor/Shared/Import/SelectImportFiles.de.resx +++ /dev/null @@ -1,126 +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 - - - Datei für Import auswählen - - - Sie haben eine ungültige Datei ({0}) hinzugefügt die nicht verarbeitet werden kann. - - \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Import/SelectImportFiles.razor b/AudioCuesheetEditor/Shared/Import/SelectImportFiles.razor deleted file mode 100644 index 4c1f617e..00000000 --- a/AudioCuesheetEditor/Shared/Import/SelectImportFiles.razor +++ /dev/null @@ -1,94 +0,0 @@ - -@inherits BaseLocalizedComponent - -@inject IStringLocalizer _localizer -@inject ISessionStateContainer _sessionStateContainer -@inject ImportManager _importManager -@inject IFileInputManager _fileInputManager - - - - - @_localizer["Select files for import"] - - - - - @foreach (var invalidFileName in invalidDropFileNames) - { - - @String.Format(_localizer["You dropped an invalid file ({0}) that can not be processed."], invalidFileName) - - } - - - -@code { - string dropFileInputId = "dropFileInputId"; - List invalidDropFileNames = new(); - - [Parameter] - public EventCallback FilesImported { get; set; } - - [Parameter] - public EventCallback> InvalidFilesChanged { get; set; } - - async Task InputFilesChanged(IReadOnlyCollection files) - { - invalidDropFileNames.Clear(); - foreach (var file in files) - { - if ((_fileInputManager.IsValidForImportView(file) == false) - && (_fileInputManager.IsValidAudiofile(file) == false)) - { - invalidDropFileNames.Add(file.Name); - } - } - if (invalidDropFileNames.Count == 0) - { - await ImportFiles(files); - } - else - { - await InvalidFilesChanged.InvokeAsync(invalidDropFileNames); - } - } - - async Task ImportFiles(IReadOnlyCollection files) - { - _sessionStateContainer.ResetImport(); - await _importManager.ImportFilesAsync(files); - // Audio file is handled seperatly - foreach (var file in files) - { - if (_fileInputManager.IsValidAudiofile(file)) - { - var audiofile = await _fileInputManager.CreateAudiofileAsync(dropFileInputId, file); - _sessionStateContainer.ImportAudiofile = audiofile; - } - } - await FilesImported.InvokeAsync(); - } - - async Task CloseInvalidFileClicked(string invalidFile) - { - invalidDropFileNames.Remove(invalidFile); - await InvalidFilesChanged.InvokeAsync(invalidDropFileNames); - } -} diff --git a/AudioCuesheetEditor/Shared/Inputs/DropFileInput.razor b/AudioCuesheetEditor/Shared/Inputs/DropFileInput.razor deleted file mode 100644 index d96d8a66..00000000 --- a/AudioCuesheetEditor/Shared/Inputs/DropFileInput.razor +++ /dev/null @@ -1,65 +0,0 @@ - -@inherits BaseLocalizedComponent - -@inject IStringLocalizer _localizer - - - -@code { - [Parameter] - public String? Filter { get; set; } - - const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full"; - string dragClass = DefaultDragClass; - - void SetDragClass() => dragClass = $"{DefaultDragClass} mud-border-primary"; - - void ClearDragClass() => dragClass = DefaultDragClass; - - [Parameter] - public EventCallback> OnFilesSelected { get; set; } - - void InputFilesChanged(InputFileChangeEventArgs e) - { - ClearDragClass(); - var files = e.GetMultipleFiles(); - OnFilesSelected.InvokeAsync(files); - } -} diff --git a/AudioCuesheetEditor/Shared/Inputs/DropFileInput.resx b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.de.resx similarity index 97% rename from AudioCuesheetEditor/Shared/Inputs/DropFileInput.resx rename to AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.de.resx index dd3c9c82..5ac78eaf 100644 --- a/AudioCuesheetEditor/Shared/Inputs/DropFileInput.resx +++ b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.de.resx @@ -117,7 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Drag and drop files here or click to choose files + + Dateien hier ablegen um sie hochzuladen \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor new file mode 100644 index 00000000..f36353d9 --- /dev/null +++ b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.razor @@ -0,0 +1,110 @@ + +@inherits BaseLocalizedComponent + +@implements IAsyncDisposable + +@inject IJSRuntime _jsRuntime +@inject IStringLocalizer _localizer +@inject ImportManager _importManager +@inject DialogManager _dialogManager + + + + + +@code { + private DotNetObjectReference? _dotNetRef; + private bool _showOverlay; + private bool _disposed; + private string _dragClass = DefaultDragClass; + + private const string DefaultDragClass = "d-flex align-center justify-center position-relative"; + private readonly string fileUploadId = $"FileDropOverlay_{Guid.NewGuid()}"; + + protected override async Task OnInitializedAsync() + { + _dotNetRef = DotNetObjectReference.Create(this); + await _jsRuntime.InvokeVoidAsync("globalFileDrag.register", _dotNetRef); + } + + [JSInvokable("OnGlobalDragEnter")] + public Task OnGlobalDragEnterAsync() + { + if (!_showOverlay) + { + _showOverlay = true; + StateHasChanged(); + } + return Task.CompletedTask; + } + + [JSInvokable("OnGlobalDragLeave")] + public Task OnGlobalDragLeaveAsync() + { + if (_showOverlay) + { + _showOverlay = false; + ClearDragClass(); + StateHasChanged(); + } + return Task.CompletedTask; + } + + async Task OnInputFileChanged(InputFileChangeEventArgs e) + { + try + { + await _dialogManager.ShowLoadingDialogAsync(); + await _importManager.UploadFilesAsync(e.GetMultipleFiles(), fileUploadId); + + ClearDragClass(); + _showOverlay = false; + await _jsRuntime.InvokeVoidAsync("globalFileDrag.reset", _dotNetRef); + } + finally + { + _dialogManager.HideLoadingDialog(); + } + } + + void SetDragClass() => _dragClass = $"{DefaultDragClass} mud-border-primary"; + + void ClearDragClass() => _dragClass = DefaultDragClass; + + public async ValueTask DisposeAsync() + { + if (_disposed) + { + return; + } + + _disposed = true; + await _jsRuntime.InvokeVoidAsync("globalFileDrag.unregister"); + _dotNetRef?.Dispose(); + } +} diff --git a/AudioCuesheetEditor/Shared/Inputs/DropFileInput.de.resx b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.resx similarity index 97% rename from AudioCuesheetEditor/Shared/Inputs/DropFileInput.de.resx rename to AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.resx index 7c955337..58e4adfe 100644 --- a/AudioCuesheetEditor/Shared/Inputs/DropFileInput.de.resx +++ b/AudioCuesheetEditor/Shared/Inputs/FileDropOverlay.resx @@ -117,7 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Dateien hier ablegen oder klicken um Dateien auszuwählen + + Drop files here to upload \ No newline at end of file diff --git a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor b/AudioCuesheetEditor/Shared/Inputs/FileInput.razor index 495eda69..91ebeb91 100644 --- a/AudioCuesheetEditor/Shared/Inputs/FileInput.razor +++ b/AudioCuesheetEditor/Shared/Inputs/FileInput.razor @@ -18,13 +18,12 @@ along with Foobar. If not, see @inherits BaseLocalizedComponent @inject IStringLocalizer _localizer -@inject IBlazorDownloadFileService _blazorDownloadFileService - -