diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/DescriptionDisplayDialog.axaml b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/DescriptionDisplayDialog.axaml
new file mode 100644
index 00000000..76aeb1d2
--- /dev/null
+++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/DescriptionDisplayDialog.axaml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/DescriptionDisplayDialog.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/DescriptionDisplayDialog.axaml.cs
new file mode 100644
index 00000000..54f7e257
--- /dev/null
+++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/DescriptionDisplayDialog.axaml.cs
@@ -0,0 +1,62 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using System;
+
+namespace LibationWinForms.AvaloniaUI.Views.Dialogs
+{
+ public partial class DescriptionDisplayDialog : Window
+ {
+ public Point SpawnLocation { get; set; }
+ public string DescriptionText { get; init; }
+ public DescriptionDisplayDialog()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ DescriptionTextBox = this.FindControl(nameof(DescriptionTextBox));
+ this.Activated += DescriptionDisplay_Activated;
+ Opened += DescriptionDisplay_Opened;
+ }
+
+ private void DescriptionDisplay_Opened(object sender, EventArgs e)
+ {
+ DescriptionTextBox.Focus();
+ }
+
+ private void DescriptionDisplay_Activated(object sender, EventArgs e)
+ {
+ DataContext = this;
+ var workingHeight = this.Screens.Primary.WorkingArea.Height;
+ DescriptionTextBox.Measure(new Size(DescriptionTextBox.MinWidth, workingHeight * 0.8));
+
+ this.Width = DescriptionTextBox.DesiredSize.Width;
+ this.Height = DescriptionTextBox.DesiredSize.Height;
+ this.MinWidth = this.Width;
+ this.MaxWidth = this.Width;
+ this.MinHeight = this.Height;
+ this.MaxHeight = this.Height;
+
+ DescriptionTextBox.Width = this.Width;
+ DescriptionTextBox.Height = this.Height;
+ DescriptionTextBox.MinWidth = this.Width;
+ DescriptionTextBox.MaxWidth = this.Width;
+ DescriptionTextBox.MinHeight = this.Height;
+ DescriptionTextBox.MaxHeight = this.Height;
+
+ this.Position = new PixelPoint((int)SpawnLocation.X, (int)Math.Min(SpawnLocation.Y, (double)workingHeight - DescriptionTextBox.DesiredSize.Height));
+ }
+
+ private void DescriptionTextBox_LostFocus(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ {
+ Close();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ }
+}
diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml
new file mode 100644
index 00000000..81e87a14
--- /dev/null
+++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs
new file mode 100644
index 00000000..41c62b39
--- /dev/null
+++ b/Source/LibationWinForms/AvaloniaUI/Views/Dialogs/ImageDisplayDialog.axaml.cs
@@ -0,0 +1,84 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using System;
+using System.ComponentModel;
+using System.IO;
+using ReactiveUI;
+
+namespace LibationWinForms.AvaloniaUI.Views.Dialogs
+{
+ public partial class ImageDisplayDialog : DialogWindow, INotifyPropertyChanged
+ {
+ public string PictureFileName { get; set; }
+ public string BookSaveDirectory { get; set; }
+
+ private byte[] _coverBytes;
+ public byte[] CoverBytes
+ {
+ get => _coverBytes;
+ set
+ {
+ _coverBytes = value;
+ var ms = new MemoryStream(_coverBytes);
+ ms.Position = 0;
+ _bitmapHolder.CoverImage = new Bitmap(ms);
+ }
+ }
+
+
+ private readonly BitmapHolder _bitmapHolder = new BitmapHolder();
+
+
+ public ImageDisplayDialog()
+ {
+ InitializeComponent();
+ DataContext = _bitmapHolder;
+ }
+
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public async void SaveImage_Clicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ {
+
+ SaveFileDialog saveFileDialog = new();
+ saveFileDialog.Filters.Add(new FileDialogFilter { Name = "Jpeg", Extensions = new System.Collections.Generic.List() { "jpg" } });
+ saveFileDialog.Directory = Directory.Exists(BookSaveDirectory) ? BookSaveDirectory : Path.GetDirectoryName(BookSaveDirectory);
+ saveFileDialog.InitialFileName = PictureFileName;
+
+ var fileName = await saveFileDialog.ShowAsync(this);
+
+ if (fileName is null)
+ return;
+
+ try
+ {
+ File.WriteAllBytes(fileName, CoverBytes);
+ }
+ catch (Exception ex)
+ {
+ Serilog.Log.Logger.Error(ex, $"Failed to save picture to {fileName}");
+ await MessageBox.Show(this, $"An error was encountered while trying to save the picture\r\n\r\n{ex.Message}", "Failed to save picture", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
+ }
+ }
+
+ public class BitmapHolder : ViewModels.ViewModelBase
+ {
+ private Bitmap _coverImage;
+ public Bitmap CoverImage
+ {
+ get => _coverImage;
+ set
+ {
+ this.RaiseAndSetIfChanged(ref _coverImage, value);
+ }
+ }
+ }
+ }
+}
diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml.cs
index fddeef83..bdd96e90 100644
--- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml.cs
+++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsDisplay2.axaml.cs
@@ -18,7 +18,7 @@ namespace LibationWinForms.AvaloniaUI.Views
public event EventHandler LiberateClicked;
private ProductsDisplayViewModel _viewModel => DataContext as ProductsDisplayViewModel;
- private GridView.ImageDisplay imageDisplay;
+ ImageDisplayDialog imageDisplayDialog;
public ProductsDisplay2()
{
@@ -211,12 +211,18 @@ namespace LibationWinForms.AvaloniaUI.Views
if (sender is not Image tblock || tblock.DataContext is not GridEntry2 gEntry)
return;
+
+ if (imageDisplayDialog is null || !imageDisplayDialog.IsVisible)
+ {
+ imageDisplayDialog = new ImageDisplayDialog();
+ }
+
var picDef = new PictureDefinition(gEntry.LibraryBook.Book.PictureLarge ?? gEntry.LibraryBook.Book.PictureId, PictureSize.Native);
void PictureCached(object sender, PictureCachedEventArgs e)
{
if (e.Definition.PictureId == picDef.PictureId)
- imageDisplay.CoverPicture = e.Picture;
+ imageDisplayDialog.CoverBytes = e.Picture;
PictureStorage.PictureCached -= PictureCached;
}
@@ -224,24 +230,20 @@ namespace LibationWinForms.AvaloniaUI.Views
PictureStorage.PictureCached += PictureCached;
(bool isDefault, byte[] initialImageBts) = PictureStorage.GetPicture(picDef);
+
var windowTitle = $"{gEntry.Title} - Cover";
- if (imageDisplay is null || imageDisplay.IsDisposed || !imageDisplay.Visible)
- {
- imageDisplay = new GridView.ImageDisplay();
- imageDisplay.RestoreSizeAndLocation(Configuration.Instance);
- imageDisplay.FormClosed += (_, _) => imageDisplay.SaveSizeAndLocation(Configuration.Instance);
- }
- imageDisplay.BookSaveDirectory = AudibleFileStorage.Audio.GetDestinationDirectory(gEntry.LibraryBook);
- imageDisplay.PictureFileName = System.IO.Path.GetFileName(AudibleFileStorage.Audio.GetBooksDirectoryFilename(gEntry.LibraryBook, ".jpg"));
- imageDisplay.Text = windowTitle;
- imageDisplay.CoverPicture = initialImageBts;
+ imageDisplayDialog.BookSaveDirectory = AudibleFileStorage.Audio.GetDestinationDirectory(gEntry.LibraryBook);
+ imageDisplayDialog.PictureFileName = System.IO.Path.GetFileName(AudibleFileStorage.Audio.GetBooksDirectoryFilename(gEntry.LibraryBook, ".jpg"));
+ imageDisplayDialog.Title = windowTitle;
+ imageDisplayDialog.CoverBytes = initialImageBts;
+
if (!isDefault)
PictureStorage.PictureCached -= PictureCached;
- if (!imageDisplay.Visible)
- imageDisplay.Show(null);
+ if (!imageDisplayDialog.IsVisible)
+ imageDisplayDialog.Show();
}
public void Description_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
@@ -249,11 +251,10 @@ namespace LibationWinForms.AvaloniaUI.Views
if (sender is TextBlock tblock && tblock.DataContext is GridEntry2 gEntry)
{
var pt = tblock.Parent.PointToScreen(tblock.Parent.Bounds.TopRight);
- var displayWindow = new GridView.DescriptionDisplay
+ var displayWindow = new DescriptionDisplayDialog
{
- SpawnLocation = new System.Drawing.Point(pt.X, pt.Y),
+ SpawnLocation = new Point(pt.X, pt.Y),
DescriptionText = gEntry.LongDescription,
- BorderThickness = 2,
};
void CloseWindow(object o, DataGridRowEventArgs e)
@@ -261,7 +262,7 @@ namespace LibationWinForms.AvaloniaUI.Views
displayWindow.Close();
}
productsGrid.LoadingRow += CloseWindow;
- displayWindow.FormClosed += (_, _) =>
+ displayWindow.Closing += (_, _) =>
{
productsGrid.LoadingRow -= CloseWindow;
};
diff --git a/Source/LibationWinForms/LibationWinForms.csproj b/Source/LibationWinForms/LibationWinForms.csproj
index 0905273d..81ecbe2b 100644
--- a/Source/LibationWinForms/LibationWinForms.csproj
+++ b/Source/LibationWinForms/LibationWinForms.csproj
@@ -109,6 +109,9 @@
+
+ DescriptionDisplayDialog.axaml
+
EditQuickFilters.axaml
@@ -118,6 +121,9 @@
SearchSyntaxDialog.axaml
+
+ ImageDisplayDialog.axaml
+
True
True