diff --git a/AmiReel.WinUI/AmiReel.WinUI.csproj b/AmiReel.WinUI/AmiReel.WinUI.csproj
index 972a551..509b078 100644
--- a/AmiReel.WinUI/AmiReel.WinUI.csproj
+++ b/AmiReel.WinUI/AmiReel.WinUI.csproj
@@ -4,7 +4,8 @@
net10.0-windows10.0.26100.0
10.0.17763.0
AmiReel_WinUI
- AmiReel.WinUI
+ AmiReel
+ ..\assets\AmiReel.ico
app.manifest
x86;x64;ARM64
win-$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant())
@@ -12,6 +13,8 @@
true
false
true
+ None
+ true
enable
enable
@@ -79,6 +82,7 @@
False
True
False
- True
+ False
+ True
diff --git a/AmiReel.WinUI/App.xaml b/AmiReel.WinUI/App.xaml
index a294467..dbae222 100644
--- a/AmiReel.WinUI/App.xaml
+++ b/AmiReel.WinUI/App.xaml
@@ -8,9 +8,97 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AmiReel.WinUI/MainPage.xaml b/AmiReel.WinUI/MainPage.xaml
index 34eddda..58f4fa9 100644
--- a/AmiReel.WinUI/MainPage.xaml
+++ b/AmiReel.WinUI/MainPage.xaml
@@ -7,33 +7,43 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
+
+
-
+
-
-
+
+
@@ -46,63 +56,61 @@
-
-
+
+
-
-
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
+
+
+
+
-
+
@@ -113,9 +121,9 @@
DefaultButton="Primary">
-
+
-
+
@@ -123,9 +131,9 @@
-
+
-
+
@@ -143,22 +151,22 @@
-
+
-
+
-
+
-
+
-
-
+
+
diff --git a/AmiReel.WinUI/MainPage.xaml.cs b/AmiReel.WinUI/MainPage.xaml.cs
index 8ef3eff..9df5d20 100644
--- a/AmiReel.WinUI/MainPage.xaml.cs
+++ b/AmiReel.WinUI/MainPage.xaml.cs
@@ -1,6 +1,7 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
+using System.Text;
using AmigaDB.VideoRenderer.Models;
using AmigaDB.VideoRenderer.Services;
using Microsoft.UI.Xaml;
@@ -15,7 +16,11 @@ public sealed partial class MainPage : Page
{
private readonly ObservableCollection _inputs = [];
private readonly AppSettings _loadedSettings;
+ private readonly StringBuilder _pendingLog = new();
+ private readonly object _logLock = new();
private CancellationTokenSource? _renderCancellation;
+ private string? _lastRenderedFile;
+ private bool _logFlushScheduled;
public MainPage()
{
@@ -107,7 +112,9 @@ public sealed partial class MainPage : Page
_renderCancellation = new CancellationTokenSource();
Progress progress = new(UpdateProgress);
await new RenderPipeline().RenderAsync(settings, progress, AppendLog, _renderCancellation.Token);
+ _lastRenderedFile = Path.Combine(settings.OutputDirectory, settings.OutputName + "_final.mp4");
OpenOutputButton.IsEnabled = true;
+ PreviewRenderedButton.IsEnabled = File.Exists(_lastRenderedFile);
await ShowMessageAsync("Render complete", "The AmiReel render completed successfully.");
}
catch (OperationCanceledException)
@@ -118,7 +125,7 @@ public sealed partial class MainPage : Page
{
AppendLog("ERROR: " + exception);
StageText.Text = "Failed";
- await ShowMessageAsync("Render failed", exception.Message);
+ await ShowMessageAsync("Render failed", UserFacingErrors.Summarize(exception));
}
finally
{
@@ -141,6 +148,18 @@ public sealed partial class MainPage : Page
Process.Start(new ProcessStartInfo("explorer.exe", OutputFolderBox.Text) { UseShellExecute = true });
}
+ private void PreviewSource_Click(object sender, RoutedEventArgs e)
+ {
+ if (InputList.SelectedItem is string path)
+ OpenPreview(path);
+ }
+
+ private void PreviewRendered_Click(object sender, RoutedEventArgs e)
+ {
+ if (!string.IsNullOrWhiteSpace(_lastRenderedFile) && File.Exists(_lastRenderedFile))
+ OpenPreview(_lastRenderedFile);
+ }
+
private void ThemeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!IsLoaded) return;
@@ -191,11 +210,39 @@ public sealed partial class MainPage : Page
StatusText.Text = value.Message;
}
+ private void OpenPreview(string mediaPath)
+ {
+ if (!File.Exists(mediaPath))
+ return;
+
+ Process.Start(new ProcessStartInfo(mediaPath) { UseShellExecute = true });
+ }
+
private void AppendLog(string line)
{
+ lock (_logLock)
+ {
+ _pendingLog.AppendLine(line);
+ if (_logFlushScheduled)
+ return;
+
+ _logFlushScheduled = true;
+ }
+
_ = DispatcherQueue.TryEnqueue(() =>
{
- LogBox.Text += line + Environment.NewLine;
+ string chunk;
+ lock (_logLock)
+ {
+ chunk = _pendingLog.ToString();
+ _pendingLog.Clear();
+ _logFlushScheduled = false;
+ }
+
+ if (chunk.Length == 0)
+ return;
+
+ LogBox.Text += chunk;
LogBox.Select(LogBox.Text.Length, 0);
});
}
@@ -207,7 +254,7 @@ public sealed partial class MainPage : Page
EndCardBox.Text.Trim(),
FfmpegPathBox.Text.Trim(),
FfprobePathBox.Text.Trim(),
- string.Empty,
+ _loadedSettings.PreviewPlayerPath,
SelectedTheme(),
SelectedEncoder(),
TrimBox.Text.Trim(),
@@ -248,6 +295,11 @@ public sealed partial class MainPage : Page
EncoderBox.SelectedIndex = 0;
}
+ private void InputList_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ PreviewSourceButton.IsEnabled = InputList.SelectedItem is string;
+ }
+
private void ApplyTheme(string theme)
{
RequestedTheme = string.Equals(theme, "Light", StringComparison.OrdinalIgnoreCase)
diff --git a/AmiReel.WinUI/MainWindow.xaml b/AmiReel.WinUI/MainWindow.xaml
index b8f0d5d..01e9bd4 100644
--- a/AmiReel.WinUI/MainWindow.xaml
+++ b/AmiReel.WinUI/MainWindow.xaml
@@ -18,11 +18,17 @@
-
-
-
-
-
+
+
+
+
+
+