diff --git a/Source/LibationAvalonia/Controls/ThemePreviewControl.axaml b/Source/LibationAvalonia/Controls/ThemePreviewControl.axaml
new file mode 100644
index 00000000..244e696b
--- /dev/null
+++ b/Source/LibationAvalonia/Controls/ThemePreviewControl.axaml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/LibationAvalonia/Controls/ThemePreviewControl.axaml.cs b/Source/LibationAvalonia/Controls/ThemePreviewControl.axaml.cs
new file mode 100644
index 00000000..deeaf945
--- /dev/null
+++ b/Source/LibationAvalonia/Controls/ThemePreviewControl.axaml.cs
@@ -0,0 +1,94 @@
+using Avalonia.Controls;
+using Avalonia.Media.Imaging;
+using DataLayer;
+using Dinah.Core.ErrorHandling;
+using LibationAvalonia.ViewModels;
+using LibationFileManager;
+using NPOI.Util.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace LibationAvalonia.Controls;
+
+public partial class ThemePreviewControl : UserControl
+{
+ public ProductsDisplayViewModel ProductsDisplay { get; set; }
+ public string[] ComboBoxItems { get; } = Enumerable.Range(1, 9).Select(n => $"Combo box item {n}").ToArray();
+ public int ComboBoxSelectedIndex { get; set; }
+
+ public ProcessBookViewModel QueuedBook { get; }
+ public ProcessBookViewModel WorkingBook { get; }
+ public ProcessBookViewModel CompletedBook { get; }
+ public ProcessBookViewModel CancelledBook { get; }
+ public ProcessBookViewModel FailedBook { get; }
+ public ThemePreviewControl()
+ {
+ InitializeComponent();
+ List sampleEntries;
+ sampleEntries = CreateMockBooks().ToList();
+
+ if (Design.IsDesignMode)
+ {
+ using var ms1 = new MemoryStream();
+ App.OpenAsset("img-coverart-prod-unavailable_80x80.jpg").CopyTo(ms1);
+ PictureStorage.SetDefaultImage(PictureSize._80x80, ms1.ToArray());
+ }
+
+ QueuedBook = new ProcessBookViewModel(sampleEntries[0], null) { Status = ProcessBookStatus.Queued };
+ WorkingBook = new ProcessBookViewModel(sampleEntries[0], null) { Status = ProcessBookStatus.Working };
+ CompletedBook = new ProcessBookViewModel(sampleEntries[0], null) { Status = ProcessBookStatus.Completed };
+ CancelledBook = new ProcessBookViewModel(sampleEntries[0], null) { Status = ProcessBookStatus.Cancelled };
+ FailedBook = new ProcessBookViewModel(sampleEntries[0], null) { Status = ProcessBookStatus.Failed };
+
+ //Set the current processable so that the empty queue doesn't try to advance.
+ QueuedBook.AddDownloadPdf();
+ WorkingBook.AddDownloadPdf();
+
+ typeof(ProcessBookViewModel).GetProperty(nameof(ProcessBookViewModel.Progress)).SetValue(WorkingBook, 50);
+
+ ProductsDisplay = new ProductsDisplayViewModel();
+ _ = ProductsDisplay.BindToGridAsync(sampleEntries);
+ DataContext = this;
+ }
+
+ private IEnumerable CreateMockBooks()
+ {
+ var author = new Contributor("Some Author", "asin_contributor");
+ var narrator = new Contributor("Some Narrator", "asin_narrator");
+
+ var book1 = new Book(new AudibleProductId("asin_book1"), "Some Book 1", "The Theming", "Demo Book Entry", 525600, ContentType.Product, [author], [narrator], "us");
+ var book2 = new Book(new AudibleProductId("asin_book2"), "Some Book 2", "The Theming", "Demo Book Entry", 525600, ContentType.Product, [author], [narrator], "us");
+ var book3 = new Book(new AudibleProductId("asin_book3"), "Some Book 3", "The Theming", "Demo Book Entry", 525600, ContentType.Product, [author], [narrator], "us");
+ var book4 = new Book(new AudibleProductId("asin_book4"), "Some Book 4", "The Theming", "Demo Book Entry", 525600, ContentType.Product, [author], [narrator], "us");
+ var seriesParent = new Book(new AudibleProductId("asin_series"), "Some Series", "", "Demo Series Entry", 0, ContentType.Parent, [author], [narrator], "us");
+ var episode = new Book(new AudibleProductId("asin_episode"), "Some Episode", "Episode 1", "Demo Episode Entry", 56, ContentType.Episode, [author], [narrator], "us");
+
+ var series = new Series(new AudibleSeriesId(seriesParent.AudibleProductId), seriesParent.Title);
+
+ seriesParent.UpsertSeries(series, "");
+ episode.UpsertSeries(series, "1");
+
+ book1.UserDefinedItem.BookStatus = LiberatedStatus.Liberated;
+ book4.UserDefinedItem.BookStatus = LiberatedStatus.Error;
+ //Set the backing field directly to preserve LiberatedStatus.PartialDownload
+ typeof(UserDefinedItem).GetField("_bookStatus", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(book2.UserDefinedItem, LiberatedStatus.PartialDownload);
+
+ yield return new LibraryBook(book1, System.DateTime.Now.AddDays(4), "someone@email.co");
+ yield return new LibraryBook(book2, System.DateTime.Now.AddDays(3), "someone@email.co");
+ yield return new LibraryBook(book3, System.DateTime.Now.AddDays(2), "someone@email.co") { AbsentFromLastScan = true };
+ yield return new LibraryBook(book4, System.DateTime.Now.AddDays(1), "someone@email.co");
+ yield return new LibraryBook(seriesParent, System.DateTime.Now, "someone@email.co");
+ yield return new LibraryBook(episode, System.DateTime.Now, "someone@email.co");
+ }
+
+ private class MockProcessable : FileLiberator.Processable
+ {
+ public override string Name => nameof(MockProcessable);
+ public override Task ProcessAsync(LibraryBook libraryBook) => Task.FromResult(new StatusHandler());
+ public override bool Validate(LibraryBook libraryBook) => false;
+ }
+}
\ No newline at end of file
diff --git a/Source/LibationAvalonia/Dialogs/ThemePickerDialog.axaml b/Source/LibationAvalonia/Dialogs/ThemePickerDialog.axaml
index f4c4a804..c7bc5cfc 100644
--- a/Source/LibationAvalonia/Dialogs/ThemePickerDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/ThemePickerDialog.axaml
@@ -2,69 +2,74 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="450"
+ mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="850"
Width="450" Height="450"
x:Class="LibationAvalonia.Dialogs.ThemePickerDialog"
+ xmlns:controls="clr-namespace:LibationAvalonia.Controls"
Title="Theme Editor">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+ RowDefinitions="*,Auto">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml b/Source/LibationAvalonia/Views/MainWindow.axaml
index b9242c41..9542b089 100644
--- a/Source/LibationAvalonia/Views/MainWindow.axaml
+++ b/Source/LibationAvalonia/Views/MainWindow.axaml
@@ -221,6 +221,7 @@
Name="productsDisplay"
DataContext="{CompiledBinding ProductsDisplay}"
LiberateClicked="ProductsDisplay_LiberateClicked"
+ TagsButtonClicked="ProductsDisplay_TagsButtonClicked"
LiberateSeriesClicked="ProductsDisplay_LiberateSeriesClicked"
ConvertToMp3Clicked="ProductsDisplay_ConvertToMp3Clicked" />
diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs
index 61eb14f2..1f47c5ef 100644
--- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs
+++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs
@@ -4,6 +4,7 @@ using Avalonia.ReactiveUI;
using Avalonia.Threading;
using DataLayer;
using FileManager;
+using LibationAvalonia.Dialogs;
using LibationAvalonia.ViewModels;
using LibationFileManager;
using LibationUiBase.GridView;
@@ -137,6 +138,18 @@ namespace LibationAvalonia.Views
public void ProductsDisplay_LiberateSeriesClicked(object _, ISeriesEntry series) => ViewModel.LiberateSeriesClicked(series);
public void ProductsDisplay_ConvertToMp3Clicked(object _, LibraryBook libraryBook) => ViewModel.ConvertToMp3Clicked(libraryBook);
+ BookDetailsDialog bookDetailsForm;
+ public void ProductsDisplay_TagsButtonClicked(object _, LibraryBook libraryBook)
+ {
+ if (bookDetailsForm is null || !bookDetailsForm.IsVisible)
+ {
+ bookDetailsForm = new BookDetailsDialog(libraryBook);
+ bookDetailsForm.Show(this);
+ }
+ else
+ bookDetailsForm.LibraryBook = libraryBook;
+ }
+
public async void filterSearchTb_KeyPress(object _, KeyEventArgs e)
{
if (e.Key == Key.Return)
diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
index 7097aa56..fd18d16b 100644
--- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
+++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
@@ -27,6 +27,7 @@ namespace LibationAvalonia.Views
public event EventHandler? LiberateClicked;
public event EventHandler? LiberateSeriesClicked;
public event EventHandler? ConvertToMp3Clicked;
+ public event EventHandler? TagsButtonClicked;
private ProductsDisplayViewModel? _viewModel => DataContext as ProductsDisplayViewModel;
ImageDisplayDialog? imageDisplayDialog;
@@ -103,7 +104,7 @@ namespace LibationAvalonia.Views
if (e.Row.DataContext is LibraryBookEntry entry && entry.Liberate.IsEpisode)
e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SeriesEntryGridBackgroundBrush");
else
- e.Row.Background = Brushes.Transparent;
+ e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SystemRegionColor");
}
private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
@@ -596,21 +597,13 @@ namespace LibationAvalonia.Views
}
}
- BookDetailsDialog? bookDetailsForm;
-
public void OnTagsButtonClick(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var button = args.Source as Button;
- if (button?.DataContext is ILibraryBookEntry lbEntry && VisualRoot is Window window)
+ if (button?.DataContext is ILibraryBookEntry lbEntry)
{
- if (bookDetailsForm is null || !bookDetailsForm.IsVisible)
- {
- bookDetailsForm = new BookDetailsDialog(lbEntry.LibraryBook);
- bookDetailsForm.Show(window);
- }
- else
- bookDetailsForm.LibraryBook = lbEntry.LibraryBook;
+ TagsButtonClicked?.Invoke(this, lbEntry.LibraryBook);
}
}