Add theme preview dialog
This commit is contained in:
parent
9043ea6334
commit
733a091ebd
52
Source/LibationAvalonia/Controls/ThemePreviewControl.axaml
Normal file
52
Source/LibationAvalonia/Controls/ThemePreviewControl.axaml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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="600" d:DesignHeight="650"
|
||||||
|
xmlns:views="clr-namespace:LibationAvalonia.Views"
|
||||||
|
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||||
|
x:Class="LibationAvalonia.Controls.ThemePreviewControl">
|
||||||
|
<Grid RowDefinitions="Auto,Auto,*">
|
||||||
|
<controls:GroupBox>
|
||||||
|
<WrapPanel>
|
||||||
|
<RadioButton Margin="5,0" Content="This is an option" IsChecked="True" />
|
||||||
|
<RadioButton Margin="5,0" Content="This is another option" />
|
||||||
|
<CheckBox Margin="5,0" Content="This is a check box" />
|
||||||
|
<controls:WheelComboBox
|
||||||
|
Margin="5,0"
|
||||||
|
ItemsSource="{Binding ComboBoxItems}"
|
||||||
|
SelectedIndex="{Binding ComboBoxSelectedIndex}" />
|
||||||
|
<TextBox Margin="5,0" Text="This is an editable text box" />
|
||||||
|
<TextBox Margin="5,0" Text="This is a read-only text box" IsReadOnly="True" />
|
||||||
|
<NumericUpDown Margin="5,0" Value="100" />
|
||||||
|
<controls:LinkLabel VerticalAlignment="Center" Margin="5,0" Text="This is an unvisited link" />
|
||||||
|
<controls:LinkLabel VerticalAlignment="Center" Margin="5,0" Text="This is a visited link" Foreground="{DynamicResource HyperlinkVisited}" />
|
||||||
|
<StackPanel Margin="5,0" Height="15" Orientation="Horizontal">
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Style Selector="Path">
|
||||||
|
<Setter Property="Stretch" Value="Uniform" />
|
||||||
|
<Setter Property="Margin" Value="3,0" />
|
||||||
|
<Setter Property="Fill" Value="{DynamicResource IconFill}" />
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
<Path Data="{StaticResource QueuedIcon}" />
|
||||||
|
<Path Data="{StaticResource QueueCompletedIcon}" />
|
||||||
|
<Path Data="{StaticResource QueueErrorIcon}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</WrapPanel>
|
||||||
|
</controls:GroupBox>
|
||||||
|
<WrapPanel Orientation="Horizontal" Grid.Row="1">
|
||||||
|
<views:ProcessBookControl DataContext="{Binding QueuedBook}" ProcessBookStatus="{Binding Status}" />
|
||||||
|
<views:ProcessBookControl DataContext="{Binding WorkingBook}" ProcessBookStatus="{Binding Status}" />
|
||||||
|
<views:ProcessBookControl DataContext="{Binding CompletedBook}" ProcessBookStatus="{Binding Status}" />
|
||||||
|
<views:ProcessBookControl DataContext="{Binding CancelledBook}" ProcessBookStatus="{Binding Status}" />
|
||||||
|
<views:ProcessBookControl DataContext="{Binding FailedBook}" ProcessBookStatus="{Binding Status}" />
|
||||||
|
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
|
<views:ProductsDisplay
|
||||||
|
Grid.Row="2"
|
||||||
|
DataContext="{Binding ProductsDisplay}" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -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<LibraryBook> 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<LibraryBook> 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<StatusHandler> ProcessAsync(LibraryBook libraryBook) => Task.FromResult(new StatusHandler());
|
||||||
|
public override bool Validate(LibraryBook libraryBook) => false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,69 +2,74 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
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"
|
Width="450" Height="450"
|
||||||
x:Class="LibationAvalonia.Dialogs.ThemePickerDialog"
|
x:Class="LibationAvalonia.Dialogs.ThemePickerDialog"
|
||||||
|
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
|
||||||
Title="Theme Editor">
|
Title="Theme Editor">
|
||||||
<Grid
|
|
||||||
RowDefinitions="*,Auto">
|
|
||||||
<DataGrid
|
|
||||||
GridLinesVisibility="All"
|
|
||||||
Margin="5"
|
|
||||||
IsReadOnly="False"
|
|
||||||
ItemsSource="{Binding ThemeColors}">
|
|
||||||
<DataGrid.Columns>
|
|
||||||
|
|
||||||
<DataGridTemplateColumn Width="Auto" Header="Color">
|
<Grid ColumnDefinitions="Auto,*">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<controls:ThemePreviewControl Name="ThemePickerPreviewControl" Margin="5" Grid.Column="1" />
|
||||||
<DataTemplate>
|
|
||||||
<ColorPicker
|
|
||||||
IsHexInputVisible="True"
|
|
||||||
Color="{Binding ThemeColor, Mode=TwoWay}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
|
||||||
</DataGridTemplateColumn>
|
|
||||||
|
|
||||||
<DataGridTextColumn
|
|
||||||
Width="*"
|
|
||||||
Binding="{Binding ThemeItemName, Mode=TwoWay}"
|
|
||||||
Header="Theme Item"/>
|
|
||||||
|
|
||||||
</DataGrid.Columns>
|
|
||||||
|
|
||||||
</DataGrid>
|
|
||||||
<Grid
|
<Grid
|
||||||
Grid.Row="1"
|
RowDefinitions="*,Auto">
|
||||||
ColumnDefinitions="Auto,Auto,Auto,*,Auto">
|
<DataGrid
|
||||||
|
GridLinesVisibility="All"
|
||||||
|
Margin="5"
|
||||||
|
IsReadOnly="False"
|
||||||
|
ItemsSource="{Binding ThemeColors}">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
|
||||||
<Grid.Styles>
|
<DataGridTemplateColumn Width="Auto" Header="Color">
|
||||||
<Style Selector="Button">
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<Setter Property="Height" Value="30" />
|
<DataTemplate>
|
||||||
<Setter Property="Padding" Value="20,0" />
|
<ColorPicker
|
||||||
<Setter Property="Margin" Value="5" />
|
IsHexInputVisible="True"
|
||||||
</Style>
|
Color="{Binding ThemeColor, Mode=TwoWay}" />
|
||||||
</Grid.Styles>
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
|
||||||
<Button
|
<DataGridTextColumn
|
||||||
Grid.Column="0"
|
Width="Auto"
|
||||||
Content="Cancel"
|
Binding="{Binding ThemeItemName, Mode=TwoWay}"
|
||||||
Command="{Binding CancelAndClose}" />
|
Header="Theme Item"/>
|
||||||
|
|
||||||
<Button
|
</DataGrid.Columns>
|
||||||
Grid.Column="1"
|
|
||||||
Content="Reset"
|
|
||||||
Command="{Binding ResetColors}" />
|
|
||||||
|
|
||||||
<Button
|
</DataGrid>
|
||||||
Grid.Column="2"
|
<Grid
|
||||||
Content="Defaults"
|
Grid.Row="1"
|
||||||
Command="{Binding LoadDefaultColors}" />
|
ColumnDefinitions="Auto,Auto,Auto,*,Auto">
|
||||||
|
|
||||||
<Button
|
<Grid.Styles>
|
||||||
Grid.Column="4"
|
<Style Selector="Button">
|
||||||
Content="Save"
|
<Setter Property="Height" Value="30" />
|
||||||
Command="{Binding SaveAndCloseAsync}" />
|
<Setter Property="Padding" Value="20,0" />
|
||||||
|
<Setter Property="Margin" Value="5" />
|
||||||
|
</Style>
|
||||||
|
</Grid.Styles>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Column="0"
|
||||||
|
Content="Cancel"
|
||||||
|
Command="{Binding CancelAndClose}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Column="1"
|
||||||
|
Content="Reset"
|
||||||
|
Command="{Binding ResetColors}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Column="2"
|
||||||
|
Content="Defaults"
|
||||||
|
Command="{Binding LoadDefaultColors}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Column="4"
|
||||||
|
Content="Save"
|
||||||
|
Command="{Binding SaveAndCloseAsync}" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@ -221,6 +221,7 @@
|
|||||||
Name="productsDisplay"
|
Name="productsDisplay"
|
||||||
DataContext="{CompiledBinding ProductsDisplay}"
|
DataContext="{CompiledBinding ProductsDisplay}"
|
||||||
LiberateClicked="ProductsDisplay_LiberateClicked"
|
LiberateClicked="ProductsDisplay_LiberateClicked"
|
||||||
|
TagsButtonClicked="ProductsDisplay_TagsButtonClicked"
|
||||||
LiberateSeriesClicked="ProductsDisplay_LiberateSeriesClicked"
|
LiberateSeriesClicked="ProductsDisplay_LiberateSeriesClicked"
|
||||||
ConvertToMp3Clicked="ProductsDisplay_ConvertToMp3Clicked" />
|
ConvertToMp3Clicked="ProductsDisplay_ConvertToMp3Clicked" />
|
||||||
</SplitView>
|
</SplitView>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using Avalonia.ReactiveUI;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using FileManager;
|
using FileManager;
|
||||||
|
using LibationAvalonia.Dialogs;
|
||||||
using LibationAvalonia.ViewModels;
|
using LibationAvalonia.ViewModels;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationUiBase.GridView;
|
using LibationUiBase.GridView;
|
||||||
@ -137,6 +138,18 @@ namespace LibationAvalonia.Views
|
|||||||
public void ProductsDisplay_LiberateSeriesClicked(object _, ISeriesEntry series) => ViewModel.LiberateSeriesClicked(series);
|
public void ProductsDisplay_LiberateSeriesClicked(object _, ISeriesEntry series) => ViewModel.LiberateSeriesClicked(series);
|
||||||
public void ProductsDisplay_ConvertToMp3Clicked(object _, LibraryBook libraryBook) => ViewModel.ConvertToMp3Clicked(libraryBook);
|
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)
|
public async void filterSearchTb_KeyPress(object _, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Key == Key.Return)
|
if (e.Key == Key.Return)
|
||||||
|
|||||||
@ -27,6 +27,7 @@ namespace LibationAvalonia.Views
|
|||||||
public event EventHandler<LibraryBook>? LiberateClicked;
|
public event EventHandler<LibraryBook>? LiberateClicked;
|
||||||
public event EventHandler<ISeriesEntry>? LiberateSeriesClicked;
|
public event EventHandler<ISeriesEntry>? LiberateSeriesClicked;
|
||||||
public event EventHandler<LibraryBook>? ConvertToMp3Clicked;
|
public event EventHandler<LibraryBook>? ConvertToMp3Clicked;
|
||||||
|
public event EventHandler<LibraryBook>? TagsButtonClicked;
|
||||||
|
|
||||||
private ProductsDisplayViewModel? _viewModel => DataContext as ProductsDisplayViewModel;
|
private ProductsDisplayViewModel? _viewModel => DataContext as ProductsDisplayViewModel;
|
||||||
ImageDisplayDialog? imageDisplayDialog;
|
ImageDisplayDialog? imageDisplayDialog;
|
||||||
@ -103,7 +104,7 @@ namespace LibationAvalonia.Views
|
|||||||
if (e.Row.DataContext is LibraryBookEntry<AvaloniaEntryStatus> entry && entry.Liberate.IsEpisode)
|
if (e.Row.DataContext is LibraryBookEntry<AvaloniaEntryStatus> entry && entry.Liberate.IsEpisode)
|
||||||
e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SeriesEntryGridBackgroundBrush");
|
e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SeriesEntryGridBackgroundBrush");
|
||||||
else
|
else
|
||||||
e.Row.Background = Brushes.Transparent;
|
e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SystemRegionColor");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
|
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)
|
public void OnTagsButtonClick(object sender, Avalonia.Interactivity.RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
var button = args.Source as Button;
|
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)
|
TagsButtonClicked?.Invoke(this, lbEntry.LibraryBook);
|
||||||
{
|
|
||||||
bookDetailsForm = new BookDetailsDialog(lbEntry.LibraryBook);
|
|
||||||
bookDetailsForm.Show(window);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
bookDetailsForm.LibraryBook = lbEntry.LibraryBook;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user