Add queue log and improve display styles

This commit is contained in:
Michael Bucari-Tovo 2022-07-11 21:43:20 -06:00
parent 3b42b52ff4
commit a66b7a6eab
8 changed files with 114 additions and 56 deletions

View File

@ -1,12 +1,9 @@
using ApplicationServices; using ApplicationServices;
using Dinah.Core.DataBinding;
using LibationSearchEngine; using LibationSearchEngine;
using LibationWinForms.GridView;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq; using System.Linq;
namespace LibationWinForms.AvaloniaUI.ViewModels namespace LibationWinForms.AvaloniaUI.ViewModels

View File

@ -70,7 +70,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
ProcessBookStatus.Cancelled => "Khaki", ProcessBookStatus.Cancelled => "Khaki",
ProcessBookStatus.Completed => "PaleGreen", ProcessBookStatus.Completed => "PaleGreen",
ProcessBookStatus.Failed => "LightCoral", ProcessBookStatus.Failed => "LightCoral",
_ => string.Empty, _ => "White",
}; };
public string StatusText => Result switch public string StatusText => Result switch
{ {

View File

@ -1,6 +1,7 @@
using ReactiveUI; using ReactiveUI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,6 +10,8 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
{ {
public class ProcessQueueViewModel : ViewModelBase public class ProcessQueueViewModel : ViewModelBase
{ {
public string QueueHeader => "this is a header!";
private TrackedQueue2<ProcessBook2> _items = new(); private TrackedQueue2<ProcessBook2> _items = new();
public ProcessQueueViewModel() { } public ProcessQueueViewModel() { }
public TrackedQueue2<ProcessBook2> Items public TrackedQueue2<ProcessBook2> Items
@ -17,6 +20,17 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
set => this.RaiseAndSetIfChanged(ref _items, value); set => this.RaiseAndSetIfChanged(ref _items, value);
} }
public ObservableCollection<LogEntry> LogEntries { get; } = new();
public ProcessBook2 SelectedItem { get; set; } public ProcessBook2 SelectedItem { get; set; }
} }
public class LogEntry
{
public DateTime LogDate { get; init; }
public string LogDateString => LogDate.ToShortTimeString();
public string LogMessage { get; init; }
}
} }

View File

@ -10,7 +10,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
Fisrt, Fisrt,
OneUp, OneUp,
OneDown, OneDown,
Last Last,
} }
/* /*

View File

@ -1,22 +1,17 @@
using Avalonia; using Avalonia;
using System;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using LibationWinForms.AvaloniaUI.ViewModels; using LibationWinForms.AvaloniaUI.ViewModels;
namespace LibationWinForms.AvaloniaUI.Views namespace LibationWinForms.AvaloniaUI.Views
{ {
public enum QueueButton public delegate void QueueItemPositionButtonClicked(ProcessBook2 item, QueuePosition queueButton);
{ public delegate void QueueItemCancelButtonClicked(ProcessBook2 item);
Cancel,
MoveFirst,
MoveUp,
MoveDown,
MoveLast
}
public delegate void QueueItemButtonClicked(ProcessBook2 item, QueueButton queueButton);
public partial class ProcessBookControl2 : UserControl public partial class ProcessBookControl2 : UserControl
{ {
public static event QueueItemButtonClicked ButtonClicked; public static event QueueItemPositionButtonClicked PositionButtonClicked;
public static event QueueItemCancelButtonClicked CancelButtonClicked;
public ProcessBookControl2() public ProcessBookControl2()
{ {
InitializeComponent(); InitializeComponent();
@ -25,15 +20,15 @@ namespace LibationWinForms.AvaloniaUI.Views
private ProcessBook2 DataItem => DataContext is null ? null : DataContext as ProcessBook2; private ProcessBook2 DataItem => DataContext is null ? null : DataContext as ProcessBook2;
public void Cancel_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void Cancel_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> ButtonClicked?.Invoke(DataItem, QueueButton.Cancel); => CancelButtonClicked?.Invoke(DataItem);
public void MoveFirst_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void MoveFirst_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> ButtonClicked?.Invoke(DataItem, QueueButton.MoveFirst); => PositionButtonClicked?.Invoke(DataItem, QueuePosition.Fisrt);
public void MoveUp_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void MoveUp_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> ButtonClicked?.Invoke(DataItem, QueueButton.MoveUp); => PositionButtonClicked?.Invoke(DataItem, QueuePosition.OneUp);
public void MoveDown_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void MoveDown_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> ButtonClicked?.Invoke(DataItem, QueueButton.MoveDown); => PositionButtonClicked?.Invoke(DataItem, QueuePosition.OneDown);
public void MoveLast_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) public void MoveLast_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
=> ButtonClicked?.Invoke(DataItem, QueueButton.MoveLast); => PositionButtonClicked?.Invoke(DataItem, QueuePosition.Last);
private void InitializeComponent() private void InitializeComponent()
{ {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<UserControl <UserControl
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
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"
@ -7,7 +7,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="700" mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="700"
x:Class="LibationWinForms.AvaloniaUI.Views.ProcessQueueControl2"> x:Class="LibationWinForms.AvaloniaUI.Views.ProcessQueueControl2">
<UserControl.Resources> <UserControl.Resources>
<RecyclePool x:Key="RecyclePool" /> <RecyclePool x:Key="RecyclePool" />
<DataTemplate x:Key="odd"> <DataTemplate x:Key="odd">
@ -19,21 +19,66 @@
</RecyclingElementFactory.Templates> </RecyclingElementFactory.Templates>
</RecyclingElementFactory> </RecyclingElementFactory>
</UserControl.Resources> </UserControl.Resources>
<UserControl.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="20"/>
</Style>
</UserControl.Styles>
<Grid RowDefinitions="1*,30"> <Grid RowDefinitions="1*,30">
<TabControl Grid.Row="0"> <TabControl Grid.Row="0">
<!-- Queue Tab --> <!-- Queue Tab -->
<TabItem> <TabItem>
<TabItem.Header> <TabItem.Header>
<TextBlock FontSize="14" Height="15" VerticalAlignment="Center">Process Queue</TextBlock> <TextBlock FontSize="14" VerticalAlignment="Center">Process Queue</TextBlock>
</TabItem.Header> </TabItem.Header>
<Grid ColumnDefinitions="1*" RowDefinitions="1*,40"> <Grid ColumnDefinitions="*" RowDefinitions="*,40">
<ScrollViewer Grid.Column="0" Grid.Row="0" Name="scroller" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible" > <Border Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="Black" Background="WhiteSmoke">
<ItemsRepeater Name="repeater" VerticalCacheLength="1.2" HorizontalCacheLength="1" Background="Transparent" Items="{Binding Items}" ItemTemplate="{StaticResource elementFactory}" /> <ScrollViewer
</ScrollViewer> Name="scroller"
<Grid Grid.Column="0" Grid.Row="1" ColumnDefinitions="2*,1*,2*"> HorizontalScrollBarVisibility="Disabled"
<Button Grid.Column="0" FontSize="13" HorizontalAlignment="Left" Click="CancelAllBtn_Click">Cancel All</Button> VerticalScrollBarVisibility="Auto">
<Button Grid.Column="2" FontSize="13" HorizontalAlignment="Right" Click="ClearFinishedBtn_Click">Clear Finished</Button> <ItemsRepeater IsVisible="True"
Grid.Column="0"
Name="repeater"
VerticalCacheLength="1.2"
HorizontalCacheLength="1"
Background="Transparent"
Items="{Binding Items}"
ItemTemplate="{StaticResource elementFactory}" />
</ScrollViewer>
</Border>
<Grid Grid.Column="0" Grid.Row="1" ColumnDefinitions="*,Auto" Margin="6,0,6,0">
<Button Grid.Column="0" FontSize="12" HorizontalAlignment="Left" Click="CancelAllBtn_Click">Cancel All</Button>
<Button Grid.Column="1" FontSize="12" HorizontalAlignment="Right" Click="ClearFinishedBtn_Click">Clear Finished</Button>
</Grid>
</Grid>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock FontSize="14" VerticalAlignment="Center">Queue Log</TextBlock>
</TabItem.Header>
<Grid ColumnDefinitions="*" RowDefinitions="*,40">
<Border Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="Black" Background="WhiteSmoke">
<DataGrid AutoGenerateColumns="False" Items="{Binding LogEntries}">
<DataGrid.Columns>
<DataGridTextColumn SortMemberPath="LogDate" Header="Timestamp" CanUserSort="True" Binding="{Binding LogDateString}" Width="90"/>
<DataGridTemplateColumn SortMemberPath="LogMessage" Width="*" Header="Message" CanUserSort="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="3">
<TextBlock VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding LogMessage}" />
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Border>
<Grid Grid.Column="0" Grid.Row="1" ColumnDefinitions="*,Auto" Margin="6,0,6,0">
<Button Grid.Column="0" FontSize="12" HorizontalAlignment="Left" Click="LogCopyBtn_Click">Copy Log Entries to Clipboard</Button>
<Button Grid.Column="1" FontSize="12" HorizontalAlignment="Right" Click="ClearLogBtn_Click">Clear Log</Button>
</Grid> </Grid>
</Grid> </Grid>
</TabItem> </TabItem>

View File

@ -7,6 +7,7 @@ using Avalonia.Threading;
using LibationWinForms.AvaloniaUI.ViewModels; using LibationWinForms.AvaloniaUI.ViewModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -65,7 +66,8 @@ namespace LibationWinForms.AvaloniaUI.Views
_repeater.KeyDown += RepeaterOnKeyDown; _repeater.KeyDown += RepeaterOnKeyDown;
DataContext = _viewModel = new ProcessQueueViewModel(); DataContext = _viewModel = new ProcessQueueViewModel();
ProcessBookControl2.ButtonClicked += ProcessBookControl2_ButtonClicked; ProcessBookControl2.PositionButtonClicked += ProcessBookControl2_ButtonClicked;
ProcessBookControl2.CancelButtonClicked += ProcessBookControl2_CancelButtonClicked;
queueNumberLbl_Icon = this.FindControl<Image>(nameof(queueNumberLbl_Icon)); queueNumberLbl_Icon = this.FindControl<Image>(nameof(queueNumberLbl_Icon));
errorNumberLbl_Icon = this.FindControl<Image>(nameof(errorNumberLbl_Icon)); errorNumberLbl_Icon = this.FindControl<Image>(nameof(errorNumberLbl_Icon));
@ -99,29 +101,17 @@ namespace LibationWinForms.AvaloniaUI.Views
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
private async void ProcessBookControl2_ButtonClicked(ProcessBook2 item, QueueButton queueButton) private async void ProcessBookControl2_CancelButtonClicked(ProcessBook2 item)
{
if (item is not null)
await item.CancelAsync();
Queue.RemoveQueued(item);
}
private void ProcessBookControl2_ButtonClicked(ProcessBook2 item, QueuePosition queueButton)
{ {
switch (queueButton) Queue.MoveQueuePosition(item, queueButton);
{ }
case QueueButton.MoveFirst:
Queue.MoveQueuePosition(item, QueuePosition.Fisrt);
break;
case QueueButton.MoveUp:
Queue.MoveQueuePosition(item, QueuePosition.OneUp);
break;
case QueueButton.MoveDown:
Queue.MoveQueuePosition(item, QueuePosition.OneDown);
break;
case QueueButton.MoveLast:
Queue.MoveQueuePosition(item, QueuePosition.Last);
break;
case QueueButton.Cancel:
if (item is not null)
await item.CancelAsync();
Queue.RemoveQueued(item);
break;
}
}
private void RepeaterClick(object sender, PointerPressedEventArgs e) private void RepeaterClick(object sender, PointerPressedEventArgs e)
{ {
@ -154,6 +144,18 @@ namespace LibationWinForms.AvaloniaUI.Views
runningTimeLbl.Text = string.Empty; runningTimeLbl.Text = string.Empty;
} }
public void ClearLogBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
_viewModel.LogEntries.Clear();
}
private void LogCopyBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
string logText = string.Join("\r\n", _viewModel.LogEntries.Select(r => $"{r.LogDate.ToShortDateString()} {r.LogDate.ToShortTimeString()}\t{r.LogMessage}"));
System.Windows.Forms.Clipboard.SetDataObject(logText, false, 5, 150);
}
private bool isBookInQueue(DataLayer.LibraryBook libraryBook) private bool isBookInQueue(DataLayer.LibraryBook libraryBook)
=> Queue.Any(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId); => Queue.Any(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId);
@ -267,7 +269,12 @@ namespace LibationWinForms.AvaloniaUI.Views
public void WriteLine(string text) public void WriteLine(string text)
{ {
Dispatcher.UIThread.Post(() =>
_viewModel.LogEntries.Add(new()
{
LogDate = DateTime.Now,
LogMessage = text.Trim()
}));
} }
#region Control event handlers #region Control event handlers

View File

@ -13,7 +13,7 @@
<DataGrid.Columns> <DataGrid.Columns>
<controls:DataGridCheckBoxColumnExt IsVisible="True" Header="Remove" IsThreeState="True" IsReadOnly="False" CanUserSort="True" Binding="{Binding Remove, Mode=TwoWay}" Width="70" SortMemberPath="Remove"/> <controls:DataGridCheckBoxColumnExt IsVisible="False" Header="Remove" IsThreeState="True" IsReadOnly="False" CanUserSort="True" Binding="{Binding Remove, Mode=TwoWay}" Width="70" SortMemberPath="Remove"/>
<DataGridTemplateColumn CanUserSort="True" Width="75" Header="Liberate" SortMemberPath="Liberate"> <DataGridTemplateColumn CanUserSort="True" Width="75" Header="Liberate" SortMemberPath="Liberate">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>