Bring WinUI app to feature/visual parity with WPF, fix drag-and-drop and branding assets
- Restyle Fluent controls (buttons, fields, dialogs, ListView) to match the app's navy dark/light palette and consistent corner radii/sizing - Fix ContentDialog (Settings, exit-confirm, error) styling by binding PrimaryButtonStyle/CloseButtonStyle explicitly via new DialogHelper, since ContentDialog ignores implicit Button styles and forces accent color onto whichever button is DefaultButton - Remove MicaBackdrop and theme the title bar directly so it no longer shows a gray tint mismatched with the app's navy background - Replace placeholder Assets/*.png (unused VS template art) with the real AmiReel logo at all required tile/splash/store sizes - Set explicit default window size (1280x860, matching the old WPF app) with DPI-aware centering and a minimum size, instead of sizing to content - Fix drag-and-drop silently failing: InputList_Drop needs a DragOperationDeferral before the first await or the DataView is torn down before GetStorageItemsAsync completes - Add Preview player path setting (was present in WPF, missing in WinUI) and error handling for preview playback - Accept all ffmpeg-readable video formats (mp4, mov, mkv, webm, ...) for file picker and drag-and-drop, not just .avi - Add exit-confirmation dialog to WinUI, mirroring the WPF app Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ public sealed partial class MainPage : Page
|
||||
EndCardBox.Text = _loadedSettings.EndCardPath;
|
||||
FfmpegPathBox.Text = _loadedSettings.FfmpegPath;
|
||||
FfprobePathBox.Text = _loadedSettings.FfprobePath;
|
||||
PreviewPlayerPathBox.Text = _loadedSettings.PreviewPlayerPath;
|
||||
OutputNameBox.Text = "amigadb_intro";
|
||||
TrimBox.Text = _loadedSettings.TrimStart;
|
||||
FadeBox.Text = _loadedSettings.FadeSeconds;
|
||||
@@ -47,7 +48,8 @@ public sealed partial class MainPage : Page
|
||||
private async void AddInputs_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FileOpenPicker picker = CreateFileOpenPicker();
|
||||
picker.FileTypeFilter.Add(".avi");
|
||||
foreach (string extension in SupportedVideoFormats.Extensions)
|
||||
picker.FileTypeFilter.Add(extension);
|
||||
picker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
|
||||
var files = await picker.PickMultipleFilesAsync();
|
||||
if (files is null) return;
|
||||
@@ -69,12 +71,20 @@ public sealed partial class MainPage : Page
|
||||
{
|
||||
if (!e.DataView.Contains(StandardDataFormats.StorageItems)) return;
|
||||
|
||||
IReadOnlyList<IStorageItem> items = await e.DataView.GetStorageItemsAsync();
|
||||
foreach (string path in items.OfType<StorageFile>()
|
||||
.Select(file => file.Path)
|
||||
.Where(path => string.Equals(Path.GetExtension(path), ".avi", StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(NaturalKey))
|
||||
if (!_inputs.Contains(path, StringComparer.OrdinalIgnoreCase)) _inputs.Add(path);
|
||||
DragOperationDeferral deferral = e.GetDeferral();
|
||||
try
|
||||
{
|
||||
IReadOnlyList<IStorageItem> items = await e.DataView.GetStorageItemsAsync();
|
||||
foreach (string path in items.OfType<StorageFile>()
|
||||
.Select(file => file.Path)
|
||||
.Where(SupportedVideoFormats.IsSupported)
|
||||
.OrderBy(NaturalKey))
|
||||
if (!_inputs.Contains(path, StringComparer.OrdinalIgnoreCase)) _inputs.Add(path);
|
||||
}
|
||||
finally
|
||||
{
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private async void BrowseEndCard_Click(object sender, RoutedEventArgs e)
|
||||
@@ -116,6 +126,15 @@ public sealed partial class MainPage : Page
|
||||
FfprobePathBox.Text = file.Path;
|
||||
}
|
||||
|
||||
private async void BrowsePreviewPlayer_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FileOpenPicker picker = CreateFileOpenPicker();
|
||||
picker.FileTypeFilter.Add(".exe");
|
||||
var file = await picker.PickSingleFileAsync();
|
||||
if (file is not null)
|
||||
PreviewPlayerPathBox.Text = file.Path;
|
||||
}
|
||||
|
||||
private async void OpenSettings_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SettingsDialog.XamlRoot = XamlRoot;
|
||||
@@ -171,16 +190,16 @@ public sealed partial class MainPage : Page
|
||||
Process.Start(new ProcessStartInfo("explorer.exe", OutputFolderBox.Text) { UseShellExecute = true });
|
||||
}
|
||||
|
||||
private void PreviewSource_Click(object sender, RoutedEventArgs e)
|
||||
private async void PreviewSource_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (InputList.SelectedItem is string path)
|
||||
OpenPreview(path);
|
||||
await OpenPreviewAsync(path);
|
||||
}
|
||||
|
||||
private void PreviewRendered_Click(object sender, RoutedEventArgs e)
|
||||
private async void PreviewRendered_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_lastRenderedFile) && File.Exists(_lastRenderedFile))
|
||||
OpenPreview(_lastRenderedFile);
|
||||
await OpenPreviewAsync(_lastRenderedFile);
|
||||
}
|
||||
|
||||
private void ThemeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
@@ -241,12 +260,39 @@ public sealed partial class MainPage : Page
|
||||
StatusText.Text = value.Message;
|
||||
}
|
||||
|
||||
private void OpenPreview(string mediaPath)
|
||||
private async Task OpenPreviewAsync(string mediaPath)
|
||||
{
|
||||
if (!File.Exists(mediaPath))
|
||||
{
|
||||
await ShowMessageAsync("Preview unavailable", "The selected media file was not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo(mediaPath) { UseShellExecute = true });
|
||||
string playerPath = PreviewPlayerPathBox.Text.Trim();
|
||||
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(playerPath))
|
||||
{
|
||||
if (!File.Exists(playerPath))
|
||||
throw new FileNotFoundException("Configured preview player was not found.", playerPath);
|
||||
|
||||
ProcessStartInfo customPlayer = new()
|
||||
{
|
||||
FileName = playerPath,
|
||||
UseShellExecute = false
|
||||
};
|
||||
customPlayer.ArgumentList.Add(mediaPath);
|
||||
Process.Start(customPlayer);
|
||||
return;
|
||||
}
|
||||
|
||||
Process.Start(new ProcessStartInfo(mediaPath) { UseShellExecute = true });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
await ShowMessageAsync("Preview failed", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string line)
|
||||
@@ -285,7 +331,7 @@ public sealed partial class MainPage : Page
|
||||
EndCardBox.Text.Trim(),
|
||||
FfmpegPathBox.Text.Trim(),
|
||||
FfprobePathBox.Text.Trim(),
|
||||
_loadedSettings.PreviewPlayerPath,
|
||||
PreviewPlayerPathBox.Text.Trim(),
|
||||
SelectedTheme(),
|
||||
SelectedEncoder(),
|
||||
TrimBox.Text.Trim(),
|
||||
@@ -334,9 +380,8 @@ public sealed partial class MainPage : Page
|
||||
|
||||
private void ApplyTheme(string theme)
|
||||
{
|
||||
RequestedTheme = string.Equals(theme, "Light", StringComparison.OrdinalIgnoreCase)
|
||||
? ElementTheme.Light
|
||||
: ElementTheme.Dark;
|
||||
bool isDark = !string.Equals(theme, "Light", StringComparison.OrdinalIgnoreCase);
|
||||
App.MainWindowInstance?.ApplyTheme(isDark);
|
||||
}
|
||||
|
||||
private FileOpenPicker CreateFileOpenPicker()
|
||||
@@ -365,13 +410,10 @@ public sealed partial class MainPage : Page
|
||||
|
||||
private async Task ShowMessageAsync(string title, string message)
|
||||
{
|
||||
ContentDialog dialog = new()
|
||||
{
|
||||
Title = title,
|
||||
Content = message,
|
||||
CloseButtonText = "OK",
|
||||
XamlRoot = XamlRoot
|
||||
};
|
||||
ContentDialog dialog = DialogHelper.CreateStyled(XamlRoot, ActualTheme);
|
||||
dialog.Title = title;
|
||||
dialog.Content = message;
|
||||
dialog.CloseButtonText = "OK";
|
||||
await dialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user