diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml index 85355abf..22204a5a 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml @@ -33,7 +33,7 @@ - Toggle _Me0 + diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProcessQueueControl2.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProcessQueueControl2.axaml.cs index fd0d7eb9..9a36b9b4 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProcessQueueControl2.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProcessQueueControl2.axaml.cs @@ -1,16 +1,12 @@ using ApplicationServices; -using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Markup.Xaml; -using Avalonia.Threading; using DataLayer; using LibationWinForms.AvaloniaUI.ViewModels; using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; -using System.Threading.Tasks; namespace LibationWinForms.AvaloniaUI.Views { @@ -20,7 +16,6 @@ namespace LibationWinForms.AvaloniaUI.Views private ItemsRepeater _repeater; private ScrollViewer _scroller; private int _selectedIndex; - private Random _random = new Random(0); private TrackedQueue2 Queue => _viewModel.Items; @@ -101,6 +96,8 @@ namespace LibationWinForms.AvaloniaUI.Views AvaloniaXamlLoader.Load(this); } + #region Add Books to Queue + private bool isBookInQueue(LibraryBook libraryBook) => Queue.Any(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId); @@ -165,6 +162,8 @@ namespace LibationWinForms.AvaloniaUI.Views _viewModel.AddToQueue(procs); } + #endregion + #region Control event handlers private async void ProcessBookControl2_CancelButtonClicked(ProcessBook2 item) diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ColumnCustomization.xaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ColumnCustomization.xaml.cs index 50fe68d2..ddade650 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ColumnCustomization.xaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ColumnCustomization.xaml.cs @@ -1,13 +1,124 @@ -using System; +using Avalonia.Controls; +using LibationFileManager; +using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid { public partial class ProductsDisplay2 { - private void Configure_ColumnCustomization() { } + ContextMenu contextMenuStrip1 = new ContextMenu(); + private void Configure_ColumnCustomization() + { + if (Design.IsDesignMode) return; + + productsGrid.ColumnDisplayIndexChanged += ProductsGrid_ColumnDisplayIndexChanged; + + var config = Configuration.Instance; + var gridColumnsVisibilities = config.GridColumnsVisibilities; + var displayIndices = config.GridColumnsDisplayIndices; + + var contextMenu = new ContextMenu(); + contextMenu.MenuClosed += ContextMenu_MenuClosed; + contextMenu.ContextMenuOpening += ContextMenu_ContextMenuOpening; + List menuItems = new(); + contextMenu.Items = menuItems; + + menuItems.Add(new MenuItem { Header = "Show / Hide Columns" }); + menuItems.Add(new MenuItem { Header = "-" }); + + var HeaderCell_PI = typeof(DataGridColumn).GetProperty("HeaderCell", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + foreach (var column in productsGrid.Columns) + { + var itemName = column.SortMemberPath; + + if (itemName == nameof(ViewModels.GridEntry2.Remove)) + continue; + + menuItems.Add + ( + new MenuItem + { + Header = ((string)column.Header).Replace((char)0xa,' '), + Tag = column, + Margin = new Avalonia.Thickness(6 ,0), + Icon = new CheckBox + { + Width = 50, + } + } + ); + + var headercell = HeaderCell_PI.GetValue(column) as DataGridColumnHeader; + headercell.ContextMenu = contextMenu; + + column.IsVisible = gridColumnsVisibilities.GetValueOrDefault(itemName, true); + } + + //We must set DisplayIndex properties in ascending order + foreach (var itemName in displayIndices.OrderBy(i => i.Value).Select(i => i.Key)) + { + if (!productsGrid.Columns.Any(c => c.SortMemberPath == itemName)) + continue; + + var column = productsGrid.Columns + .Single(c => c.SortMemberPath == itemName); + + column.DisplayIndex = displayIndices.GetValueOrDefault(itemName, productsGrid.Columns.IndexOf(column)); + } + + //Remove column is always first; + removeGVColumn.DisplayIndex = 0; + removeGVColumn.CanUserReorder = false; + } + + private void ContextMenu_ContextMenuOpening(object sender, System.ComponentModel.CancelEventArgs e) + { + var contextMenu = sender as ContextMenu; + foreach (var mi in contextMenu.Items.OfType()) + { + if (mi.Tag is DataGridColumn column) + { + var cbox = mi.Icon as CheckBox; + cbox.IsChecked = column.IsVisible; + } + } + } + + private void ContextMenu_MenuClosed(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var contextMenu = sender as ContextMenu; + var config = Configuration.Instance; + var dictionary = config.GridColumnsVisibilities; + + foreach (var mi in contextMenu.Items.OfType()) + { + if (mi.Tag is DataGridColumn column) + { + var cbox = mi.Icon as CheckBox; + column.IsVisible = cbox.IsChecked == true; + dictionary[column.SortMemberPath] = cbox.IsChecked == true; + } + } + + //If all columns are hidden, register the context menu on the grid so users can unhide. + if (!productsGrid.Columns.Any(c => c.IsVisible)) + productsGrid.ContextMenu = contextMenu; + else + productsGrid.ContextMenu = null; + + config.GridColumnsVisibilities = dictionary; + } + + private void ProductsGrid_ColumnDisplayIndexChanged(object sender, Avalonia.Controls.DataGridColumnEventArgs e) + { + var config = Configuration.Instance; + + var dictionary = config.GridColumnsDisplayIndices; + dictionary[e.Column.SortMemberPath] = e.Column.DisplayIndex; + config.GridColumnsDisplayIndices = dictionary; + } } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Display.xaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Display.xaml.cs index 5fac228a..b255567b 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Display.xaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Display.xaml.cs @@ -25,8 +25,8 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid VisibleCountChanged?.Invoke(this, bindingList.BookEntries().Count()); //Avalonia displays items in the DataConncetion from an internal copy of - //the bound list, not the actual bound list. so we need to reflect to get - //the current display order and set the GridEntry.ListIndex correctly. + //the bound list, not the actual bound list. So we need to reflect to get + //the current display order and set each GridEntry.ListIndex correctly. var DataConnection_PI = typeof(DataGrid).GetProperty("DataConnection", BindingFlags.NonPublic | BindingFlags.Instance); var DataSource_PI = DataConnection_PI.PropertyType.GetProperty("DataSource", BindingFlags.Public | BindingFlags.Instance); @@ -41,7 +41,7 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid }; //Assign the viewmodel after we subscribe to CollectionChanged - //to ensure that out handler executes first. + //so that out handler executes first. productsGrid.DataContext = _viewModel; } else @@ -52,7 +52,6 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid bindingList.Filter = existingFilter; ReSort(); } - } catch (Exception ex) { diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ScanAndRemove.xaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ScanAndRemove.xaml.cs index 025ed866..ce5c8e34 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ScanAndRemove.xaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.ScanAndRemove.xaml.cs @@ -14,8 +14,24 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid { private void Configure_ScanAndRemove() { } + private bool RemoveColumnVisible + { + get => removeGVColumn.IsVisible; + set + { + if (value) + { + foreach (var book in bindingList.AllItems()) + book.Remove = false; + } + + removeGVColumn.DisplayIndex = 0; + removeGVColumn.CanUserReorder = value; + removeGVColumn.IsVisible = value; + } + } public void CloseRemoveBooksColumn() - => removeGVColumn.IsVisible = false; + => RemoveColumnVisible = false; public async Task RemoveCheckedBooksAsync() { @@ -39,6 +55,7 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid RemovableCountChanged?.Invoke(this, GetAllBookEntries().Count(lbe => lbe.Remove is true)); } + public async Task ScanAndRemoveBooksAsync(params Account[] accounts) { RemovableCountChanged?.Invoke(this, 0); diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Sorting.xaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Sorting.xaml.cs index 9e4fe5b5..32837478 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Sorting.xaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.Sorting.xaml.cs @@ -1,38 +1,16 @@ using Avalonia.Controls; using LibationWinForms.AvaloniaUI.ViewModels; using System; -using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid { public partial class ProductsDisplay2 { + private DataGridColumn CurrentSortColumn; private void Configure_Sorting() { } - - private void RegisterCustomColumnComparers() - { - - removeGVColumn.CustomSortComparer = new RowComparer(removeGVColumn); - liberateGVColumn.CustomSortComparer = new RowComparer(liberateGVColumn); - titleGVColumn.CustomSortComparer = new RowComparer(titleGVColumn); - authorsGVColumn.CustomSortComparer = new RowComparer(authorsGVColumn); - narratorsGVColumn.CustomSortComparer = new RowComparer(narratorsGVColumn); - lengthGVColumn.CustomSortComparer = new RowComparer(lengthGVColumn); - seriesGVColumn.CustomSortComparer = new RowComparer(seriesGVColumn); - descriptionGVColumn.CustomSortComparer = new RowComparer(descriptionGVColumn); - categoryGVColumn.CustomSortComparer = new RowComparer(categoryGVColumn); - productRatingGVColumn.CustomSortComparer = new RowComparer(productRatingGVColumn); - purchaseDateGVColumn.CustomSortComparer = new RowComparer(purchaseDateGVColumn); - myRatingGVColumn.CustomSortComparer = new RowComparer(myRatingGVColumn); - miscGVColumn.CustomSortComparer = new RowComparer(miscGVColumn); - tagAndDetailsGVColumn.CustomSortComparer = new RowComparer(tagAndDetailsGVColumn); - } - private void ReSort() { if (CurrentSortColumn is null) @@ -46,11 +24,6 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid } } - - - private DataGridColumn CurrentSortColumn; - - private void ProductsGrid_Sorting(object sender, DataGridColumnEventArgs e) { //Force the comparer to get the current sort order. We can't diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml index 82c68edd..ce1adcbe 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml @@ -7,8 +7,13 @@ mc:Ignorable="d" d:DesignWidth="1560" d:DesignHeight="400" x:Class="LibationWinForms.AvaloniaUI.Views.ProductsGrid.ProductsDisplay2"> - - + + + @@ -26,10 +31,10 @@ - + - + @@ -88,7 +93,7 @@ - + diff --git a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml.cs index 96452776..284f50f9 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/ProductsGrid/ProductsDisplay2.axaml.cs @@ -33,20 +33,6 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid private GridEntryBindingList2 bindingList => _viewModel.GridEntries; DataGridColumn removeGVColumn; - DataGridColumn liberateGVColumn; - DataGridColumn coverGVColumn; - DataGridColumn titleGVColumn; - DataGridColumn authorsGVColumn; - DataGridColumn narratorsGVColumn; - DataGridColumn lengthGVColumn; - DataGridColumn seriesGVColumn; - DataGridColumn descriptionGVColumn; - DataGridColumn categoryGVColumn; - DataGridColumn productRatingGVColumn; - DataGridColumn purchaseDateGVColumn; - DataGridColumn myRatingGVColumn; - DataGridColumn miscGVColumn; - DataGridColumn tagAndDetailsGVColumn; public ProductsDisplay2() { @@ -59,6 +45,11 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid Configure_ScanAndRemove(); Configure_Sorting(); + foreach ( var column in productsGrid.Columns) + { + column.CustomSortComparer = new RowComparer(column); + } + if (Design.IsDesignMode) { using var context = DbContexts.GetContext(); @@ -78,22 +69,6 @@ namespace LibationWinForms.AvaloniaUI.Views.ProductsGrid productsGrid.LoadingRow += ProductsGrid_LoadingRow; removeGVColumn = productsGrid.Columns[0]; - liberateGVColumn = productsGrid.Columns[1]; - coverGVColumn = productsGrid.Columns[2]; - titleGVColumn = productsGrid.Columns[3]; - authorsGVColumn = productsGrid.Columns[4]; - narratorsGVColumn = productsGrid.Columns[5]; - lengthGVColumn = productsGrid.Columns[6]; - seriesGVColumn = productsGrid.Columns[7]; - descriptionGVColumn = productsGrid.Columns[8]; - categoryGVColumn = productsGrid.Columns[9]; - productRatingGVColumn = productsGrid.Columns[10]; - purchaseDateGVColumn = productsGrid.Columns[11]; - myRatingGVColumn = productsGrid.Columns[12]; - miscGVColumn = productsGrid.Columns[13]; - tagAndDetailsGVColumn = productsGrid.Columns[14]; - - RegisterCustomColumnComparers(); } private static object tagObj = new();