Add search and quick filters to walkthrough

This commit is contained in:
Mbucari 2023-03-28 12:30:05 -06:00
parent 00cf7693d5
commit 2afb5365dd
8 changed files with 308 additions and 61 deletions

View File

@ -20,7 +20,7 @@ namespace ApplicationServices
public static class LibraryCommands public static class LibraryCommands
{ {
public static event EventHandler<int> ScanBegin; public static event EventHandler<int> ScanBegin;
public static event EventHandler ScanEnd; public static event EventHandler<int> ScanEnd;
public static bool Scanning { get; private set; } public static bool Scanning { get; private set; }
private static object _lock { get; } = new(); private static object _lock { get; } = new();
@ -94,7 +94,7 @@ namespace ApplicationServices
{ {
stop(); stop();
var putBreakPointHere = logOutput; var putBreakPointHere = logOutput;
ScanEnd?.Invoke(null, null); ScanEnd?.Invoke(null, 0);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true); GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
} }
} }
@ -107,6 +107,7 @@ namespace ApplicationServices
if (accounts is null || accounts.Length == 0) if (accounts is null || accounts.Length == 0)
return (0, 0); return (0, 0);
int newCount = 0;
try try
{ {
lock (_lock) lock (_lock)
@ -133,7 +134,7 @@ namespace ApplicationServices
Log.Logger.Information("Begin long-running import"); Log.Logger.Information("Begin long-running import");
logTime($"pre {nameof(importIntoDbAsync)}"); logTime($"pre {nameof(importIntoDbAsync)}");
var newCount = await importIntoDbAsync(importItems); newCount = await importIntoDbAsync(importItems);
logTime($"post {nameof(importIntoDbAsync)}"); logTime($"post {nameof(importIntoDbAsync)}");
Log.Logger.Information($"Import complete. New count {newCount}"); Log.Logger.Information($"Import complete. New count {newCount}");
@ -166,7 +167,7 @@ namespace ApplicationServices
{ {
stop(); stop();
var putBreakPointHere = logOutput; var putBreakPointHere = logOutput;
ScanEnd?.Invoke(null, null); ScanEnd?.Invoke(null, newCount);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true); GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
} }
} }

View File

@ -16,7 +16,7 @@ namespace LibationAvalonia.Views
_viewModel.NumAccountsScanning = accountsLength; _viewModel.NumAccountsScanning = accountsLength;
} }
private void LibraryCommands_ScanEnd(object sender, EventArgs e) private void LibraryCommands_ScanEnd(object sender, int newCount)
{ {
_viewModel.NumAccountsScanning = 0; _viewModel.NumAccountsScanning = 0;
} }

View File

@ -87,7 +87,7 @@
<!-- Quick Filters Menu --> <!-- Quick Filters Menu -->
<MenuItem Header="Quick _Filters" ItemsSource="{Binding QuickFilterMenuItems}" KeyDown="QuickFiltersMenuItem_KeyDown"> <MenuItem Name="quickFiltersToolStripMenuItem" Header="Quick _Filters" ItemsSource="{Binding QuickFilterMenuItems}" KeyDown="QuickFiltersMenuItem_KeyDown">
<!-- Remove height style property for menu item --> <!-- Remove height style property for menu item -->
<MenuItem.Styles> <MenuItem.Styles>
<Style Selector="ItemsPresenter#PART_ItemsPresenter"> <Style Selector="ItemsPresenter#PART_ItemsPresenter">
@ -154,8 +154,8 @@
</Grid.Styles> </Grid.Styles>
<StackPanel Grid.Column="0" Orientation="Horizontal"> <StackPanel Grid.Column="0" Orientation="Horizontal">
<Button Margin="0" Click="filterHelpBtn_Click" Content="?"/> <Button Name="filterHelpBtn" Margin="0" Click="filterHelpBtn_Click" Content="?"/>
<Button Click="addQuickFilterBtn_Click" Content="Add To Quick Filters"/> <Button Name="addQuickFilterBtn" Click="addQuickFilterBtn_Click" Content="Add To Quick Filters"/>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal"> <StackPanel Grid.Column="1" Orientation="Horizontal">
@ -163,10 +163,10 @@
<Button IsVisible="{Binding RemoveButtonsVisible}" Click="doneRemovingBtn_Click" Content="Done Removing Books"/> <Button IsVisible="{Binding RemoveButtonsVisible}" Click="doneRemovingBtn_Click" Content="Done Removing Books"/>
</StackPanel> </StackPanel>
<TextBox Grid.Column="1" Margin="10,0,0,0" IsVisible="{Binding !RemoveButtonsVisible}" Text="{Binding FilterString, Mode=TwoWay}" KeyDown="filterSearchTb_KeyPress" /> <TextBox Grid.Column="1" Margin="10,0,0,0" Name="filterSearchTb" IsVisible="{Binding !RemoveButtonsVisible}" Text="{Binding FilterString, Mode=TwoWay}" KeyDown="filterSearchTb_KeyPress" />
<StackPanel Grid.Column="2" Height="30" Orientation="Horizontal"> <StackPanel Grid.Column="2" Height="30" Orientation="Horizontal">
<Button Click="filterBtn_Click" VerticalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Content="Filter"/> <Button Name="filterBtn" Click="filterBtn_Click" VerticalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Content="Filter"/>
<Button Padding="2,6,2,6" VerticalAlignment="Stretch" Click="ToggleQueueHideBtn_Click"> <Button Padding="2,6,2,6" VerticalAlignment="Stretch" Click="ToggleQueueHideBtn_Click">
<Path Stretch="Uniform" Fill="{DynamicResource IconFill}" Data="{StaticResource LeftArrows}"> <Path Stretch="Uniform" Fill="{DynamicResource IconFill}" Data="{StaticResource LeftArrows}">
<Path.RenderTransform> <Path.RenderTransform>

View File

@ -1,9 +1,14 @@
using AudibleUtilities; using ApplicationServices;
using AudibleUtilities;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading; using Avalonia.Threading;
using Dinah.Core.StepRunner; using Dinah.Core.StepRunner;
using LibationAvalonia.Dialogs; using LibationAvalonia.Dialogs;
using LibationAvalonia.Views; using LibationAvalonia.Views;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -27,41 +32,46 @@ namespace LibationAvalonia
MainForm = mainForm; MainForm = mainForm;
sequence[nameof(ShowAccountDialog)] = ShowAccountDialog; sequence[nameof(ShowAccountDialog)] = ShowAccountDialog;
sequence[nameof(ShowSettingsDialog)] = ShowSettingsDialog; sequence[nameof(ShowSettingsDialog)] = ShowSettingsDialog;
sequence[nameof(ScanAccounts)] = ScanAccounts; sequence[nameof(ShowAccountScanning)] = ShowAccountScanning;
sequence[nameof(ShowSearching)] = ShowSearching;
sequence[nameof(ShowQuickFilters)] = ShowQuickFilters;
} }
public async Task RunAsync() => await sequence.RunAsync(); public async Task RunAsync() => await sequence.RunAsync();
private async Task<bool> ShowAccountDialog() private async Task<bool> ShowAccountDialog()
{ {
var result = await Dispatcher.UIThread.InvokeAsync(() => MessageBox.Show(MainForm, "First, add you Audible account(s).", "Add Accounts", MessageBoxButtons.OKCancel)); if (await OkCancelMessageBox("First, add you Audible account(s).", "Add Accounts") is not DialogResult.OK) return false;
if (result is DialogResult.Cancel) return false;
await Task.Delay(750); await Task.Delay(750);
await Dispatcher.UIThread.InvokeAsync(MainForm.settingsToolStripMenuItem.Open); await flashControlAsync(MainForm.settingsToolStripMenuItem);
await InvokeAsync(MainForm.settingsToolStripMenuItem.Open);
await Task.Delay(500); await Task.Delay(500);
await Dispatcher.UIThread.InvokeAsync(() => MainForm.accountsToolStripMenuItem.IsSelected = true);
await Task.Delay(1000); await flashControlAsync(MainForm.accountsToolStripMenuItem);
var accountSettings = await Dispatcher.UIThread.InvokeAsync(() => new AccountsDialog()); await InvokeAsync(() => MainForm.accountsToolStripMenuItem.IsSelected = true);
accountSettings.Opened += (_, _) => MessageBox.Show(accountSettings, "Add your Audible account(s), then save.", "Add an Account"); await Task.Delay(500);
await Dispatcher.UIThread.InvokeAsync(() => accountSettings.ShowDialog(MainForm));
var accountSettings = await InvokeAsync(() => new AccountsDialog());
accountSettings.Opened += async (_, _) => await MessageBox.Show(accountSettings, "Add your Audible account(s), then save.", "Add an Account");
await InvokeAsync(() => accountSettings.ShowDialog(MainForm));
return true; return true;
} }
private async Task<bool> ShowSettingsDialog() private async Task<bool> ShowSettingsDialog()
{ {
var result = await Dispatcher.UIThread.InvokeAsync(() => MessageBox.Show(MainForm, "Next, adjust Libation's settings", "Change Settings", MessageBoxButtons.OKCancel)); if (await OkCancelMessageBox("Next, adjust Libation's settings", "Change Settings") is not DialogResult.OK) return false;
if (result is DialogResult.Cancel) return false;
await Task.Delay(750); await Task.Delay(750);
await Dispatcher.UIThread.InvokeAsync(MainForm.settingsToolStripMenuItem.Open); await flashControlAsync(MainForm.settingsToolStripMenuItem);
await InvokeAsync(MainForm.settingsToolStripMenuItem.Open);
await Task.Delay(500); await Task.Delay(500);
await Dispatcher.UIThread.InvokeAsync(() => MainForm.basicSettingsToolStripMenuItem.IsSelected = true);
await Task.Delay(1000);
var settingsDialog = await Dispatcher.UIThread.InvokeAsync(() => new SettingsDialog()); await flashControlAsync(MainForm.basicSettingsToolStripMenuItem);
await InvokeAsync(() => MainForm.basicSettingsToolStripMenuItem.IsSelected = true);
await Task.Delay(500);
var settingsDialog = await InvokeAsync(() => new SettingsDialog());
var tabsToVisit = settingsDialog.tabControl.Items.OfType<TabItem>().ToList(); var tabsToVisit = settingsDialog.tabControl.Items.OfType<TabItem>().ToList();
@ -70,7 +80,7 @@ namespace LibationAvalonia
settingsDialog.Closing += SettingsDialog_FormClosing; settingsDialog.Closing += SettingsDialog_FormClosing;
await Dispatcher.UIThread.InvokeAsync(() => settingsDialog.ShowDialog(MainForm)); await InvokeAsync(() => settingsDialog.ShowDialog(MainForm));
return true; return true;
@ -103,31 +113,142 @@ namespace LibationAvalonia
} }
} }
private async Task<bool> ScanAccounts() private async Task<bool> ShowAccountScanning()
{ {
using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
var count = persister.AccountsSettings.Accounts.Count; var count = persister.AccountsSettings.Accounts.Count;
if (count < 1) if (count < 1)
{ {
await Dispatcher.UIThread.InvokeAsync(() => MessageBox.Show(MainForm, "Add an Audible account, then sync your library through the \"Import\" menu", "Add an Audible Account", MessageBoxButtons.OK, MessageBoxIcon.Information)); await InvokeAsync(() => MessageBox.Show(MainForm, "Add an Audible account, then sync your library through the \"Import\" menu", "Add an Audible Account", MessageBoxButtons.OK, MessageBoxIcon.Information));
return false; return false;
} }
var accounts = count > 1 ? "accounts" : "account"; var accounts = count > 1 ? "accounts" : "account";
var library = count > 1 ? "libraries" : "library"; var library = count > 1 ? "libraries" : "library";
var result = await Dispatcher.UIThread.InvokeAsync(() => MessageBox.Show(MainForm, $"Finally, scan your Audible {accounts} to sync your {library} with Libation", $"Scan {accounts}", MessageBoxButtons.OKCancel)); if (await OkCancelMessageBox($"Finally, scan your Audible {accounts} to sync your {library} with Libation", $"Scan {accounts}") is not DialogResult.OK) return false;
if (result is DialogResult.Cancel) return false;
var scanItem = count > 1 ? MainForm.scanLibraryOfAllAccountsToolStripMenuItem : MainForm.scanLibraryToolStripMenuItem;
await Task.Delay(750); await Task.Delay(750);
await Dispatcher.UIThread.InvokeAsync(MainForm.importToolStripMenuItem.Open); await flashControlAsync(MainForm.importToolStripMenuItem);
await InvokeAsync(MainForm.importToolStripMenuItem.Open);
await Task.Delay(500); await Task.Delay(500);
await Dispatcher.UIThread.InvokeAsync(() => (count > 1 ? MainForm.scanLibraryOfAllAccountsToolStripMenuItem : MainForm.scanLibraryToolStripMenuItem).IsSelected = true); await flashControlAsync(scanItem);
await InvokeAsync(() => scanItem.IsSelected = true);
await Task.Delay(500);
await InvokeAsync(() => scanItem.RaiseEvent(new RoutedEventArgs(MenuItem.ClickEvent)));
await InvokeAsync(MainForm.importToolStripMenuItem.Close);
var tcs = new TaskCompletionSource();
LibraryCommands.ScanEnd += LibraryCommands_ScanEnd;
await tcs.Task;
LibraryCommands.ScanEnd -= LibraryCommands_ScanEnd;
MainForm.ViewModel.ProductsDisplay.VisibleCountChanged -= productsDisplay_VisibleCountChanged;
return true;
void LibraryCommands_ScanEnd(object sender, int newCount)
{
//if we imported new books, wait for the grid to update before proceeding.
if (newCount > 0)
MainForm.ViewModel.ProductsDisplay.VisibleCountChanged += productsDisplay_VisibleCountChanged;
else
tcs.SetResult();
}
void productsDisplay_VisibleCountChanged(object sender, int e) => tcs.SetResult();
}
private async Task<bool> ShowSearching()
{
var books = DbContexts.GetLibrary_Flat_NoTracking();
if (books.Count == 0) return true;
var firstAuthor = getFirstAuthor();
if (firstAuthor == null) return true;
if (await OkCancelMessageBox("You can filter the grid entries by searching", "Searching") is not DialogResult.OK) return false;
await flashControlAsync(MainForm.filterSearchTb);
await InvokeAsync(() => MainForm.filterSearchTb.Text = string.Empty);
foreach (var c in firstAuthor)
{
await InvokeAsync(() => MainForm.filterSearchTb.Text += c);
await Task.Delay(200);
}
await flashControlAsync(MainForm.filterBtn);
await InvokeAsync(MainForm.filterBtn.Focus);
await Task.Delay(500);
await InvokeAsync(() => MainForm.filterBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)));
await Task.Delay(1000); await Task.Delay(1000);
await Dispatcher.UIThread.InvokeAsync(() => (count > 1 ? MainForm.scanLibraryOfAllAccountsToolStripMenuItem : MainForm.scanLibraryToolStripMenuItem).RaiseEvent(new Avalonia.Interactivity.RoutedEventArgs(MenuItem.ClickEvent)));
await Dispatcher.UIThread.InvokeAsync(MainForm.importToolStripMenuItem.Close); await MessageBox.Show(MainForm, "Libation provides a built-in cheat sheet for its query language", "Search Cheat Sheet");
await flashControlAsync(MainForm.filterHelpBtn);
var filterHelp = await InvokeAsync(() => new SearchSyntaxDialog());
await InvokeAsync(() => filterHelp.ShowDialog(MainForm));
return true; return true;
} }
private async Task<bool> ShowQuickFilters()
{
var firstAuthor = getFirstAuthor();
if (firstAuthor == null) return true;
if (await OkCancelMessageBox("Queries that you perform regularly can be added to 'Quick Filters'", "Quick Filters") is not DialogResult.OK) return false;
await InvokeAsync(() => MainForm.filterSearchTb.Text = firstAuthor);
await Task.Delay(750);
await flashControlAsync(MainForm.addQuickFilterBtn);
await Task.Delay(750);
await InvokeAsync(() => MainForm.addQuickFilterBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)));
await flashControlAsync(MainForm.quickFiltersToolStripMenuItem);
await InvokeAsync(MainForm.quickFiltersToolStripMenuItem.Open);
await Task.Delay(500);
var editQuickFiltersToolStripMenuItem = MainForm.quickFiltersToolStripMenuItem.ItemsSource.OfType<MenuItem>().ElementAt(1);
await flashControlAsync(editQuickFiltersToolStripMenuItem);
await InvokeAsync(() => editQuickFiltersToolStripMenuItem.IsSelected = true);
await Task.Delay(500);
var editQuickFilters = await InvokeAsync(() => new EditQuickFilters());
editQuickFilters.Opened += async (_, _) => await MessageBox.Show(editQuickFilters, "From here you can edit, delete, and change the order of Quick Filters", "Editing Quick Filters");
await InvokeAsync(() => editQuickFilters.ShowDialog(MainForm));
return true;
}
private string getFirstAuthor()
{
var books = DbContexts.GetLibrary_Flat_NoTracking();
return books.SelectMany(lb => lb.Book.Authors).FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.Name))?.Name;
}
private async Task flashControlAsync(TemplatedControl control, int flashCount = 3)
{
var backColor = await InvokeAsync(() => control.Background);
for (int i = 0; i < flashCount; i++)
{
await InvokeAsync(() => control.Background = Brushes.Firebrick);
await Task.Delay(200);
await InvokeAsync(() => control.Background = backColor);
await Task.Delay(200);
}
}
private Task<T> InvokeAsync<T>(Func<T> func) => Dispatcher.UIThread.InvokeAsync(func);
private Task<T> InvokeAsync<T>(Func<Task<T>> func) => Dispatcher.UIThread.InvokeAsync(func);
private Task InvokeAsync(Func<Task> action) => Dispatcher.UIThread.InvokeAsync(action);
private Task InvokeAsync(Action action) => Dispatcher.UIThread.InvokeAsync(action);
private Task<DialogResult> OkCancelMessageBox(string message, string caption)
=> InvokeAsync(() => MessageBox.Show(MainForm, message, caption, MessageBoxButtons.OKCancel));
} }
} }

View File

@ -192,7 +192,7 @@ namespace LibationFileManager
} }
[Description("Indicates that this is the first time Libation has been run")] [Description("Indicates that this is the first time Libation has been run")]
public bool FirstLaunch { get => GetNonString(defaultValue: true); set => SetNonString(value); } public bool FirstLaunch { get => true; set => SetNonString(value); }
[Description("When liberating books and there is an error, Libation should:")] [Description("When liberating books and there is an error, Libation should:")]
public BadBookAction BadBook { get => GetNonString(defaultValue: BadBookAction.Ask); set => SetNonString(value); } public BadBookAction BadBook { get => GetNonString(defaultValue: BadBookAction.Ask); set => SetNonString(value); }

View File

@ -642,15 +642,15 @@
private System.Windows.Forms.ToolStripStatusLabel backupsCountsLbl; private System.Windows.Forms.ToolStripStatusLabel backupsCountsLbl;
private LibationWinForms.FormattableToolStripMenuItem beginBookBackupsToolStripMenuItem; private LibationWinForms.FormattableToolStripMenuItem beginBookBackupsToolStripMenuItem;
private LibationWinForms.FormattableToolStripMenuItem beginPdfBackupsToolStripMenuItem; private LibationWinForms.FormattableToolStripMenuItem beginPdfBackupsToolStripMenuItem;
private System.Windows.Forms.TextBox filterSearchTb; public System.Windows.Forms.TextBox filterSearchTb;
private System.Windows.Forms.Button filterBtn; public System.Windows.Forms.Button filterBtn;
private System.Windows.Forms.Button filterHelpBtn; public System.Windows.Forms.Button filterHelpBtn;
public System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem; public System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
public System.Windows.Forms.ToolStripMenuItem scanLibraryToolStripMenuItem; public System.Windows.Forms.ToolStripMenuItem scanLibraryToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem quickFiltersToolStripMenuItem; public System.Windows.Forms.ToolStripMenuItem quickFiltersToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem firstFilterIsDefaultToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem firstFilterIsDefaultToolStripMenuItem;
private System.Windows.Forms.Button addQuickFilterBtn; public System.Windows.Forms.Button addQuickFilterBtn;
private System.Windows.Forms.ToolStripMenuItem editQuickFiltersToolStripMenuItem; public System.Windows.Forms.ToolStripMenuItem editQuickFiltersToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
public System.Windows.Forms.ToolStripMenuItem basicSettingsToolStripMenuItem; public System.Windows.Forms.ToolStripMenuItem basicSettingsToolStripMenuItem;
public System.Windows.Forms.ToolStripMenuItem accountsToolStripMenuItem; public System.Windows.Forms.ToolStripMenuItem accountsToolStripMenuItem;
@ -683,7 +683,7 @@
private LibationWinForms.ProcessQueue.ProcessQueueControl processBookQueue1; private LibationWinForms.ProcessQueue.ProcessQueueControl processBookQueue1;
private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Button toggleQueueHideBtn; private System.Windows.Forms.Button toggleQueueHideBtn;
private LibationWinForms.GridView.ProductsDisplay productsDisplay; public LibationWinForms.GridView.ProductsDisplay productsDisplay;
private System.Windows.Forms.Button removeBooksBtn; private System.Windows.Forms.Button removeBooksBtn;
private System.Windows.Forms.Button doneRemovingBtn; private System.Windows.Forms.Button doneRemovingBtn;
private System.Windows.Forms.ToolStripMenuItem setPdfDownloadedManualToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem setPdfDownloadedManualToolStripMenuItem;

View File

@ -28,7 +28,7 @@ namespace LibationWinForms
: $"Scanning {accountsLength} accounts..."; : $"Scanning {accountsLength} accounts...";
} }
private void LibraryCommands_ScanEnd(object sender, EventArgs e) private void LibraryCommands_ScanEnd(object sender, int newCount)
{ {
removeLibraryBooksToolStripMenuItem.Enabled = true; removeLibraryBooksToolStripMenuItem.Enabled = true;
removeAllAccountsToolStripMenuItem.Enabled = true; removeAllAccountsToolStripMenuItem.Enabled = true;

View File

@ -1,9 +1,10 @@
using AudibleUtilities; using ApplicationServices;
using AudibleUtilities;
using Dinah.Core.StepRunner; using Dinah.Core.StepRunner;
using Dinah.Core.WindowsDesktop.Processes;
using LibationWinForms.Dialogs; using LibationWinForms.Dialogs;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -27,21 +28,25 @@ namespace LibationWinForms
MainForm = form1; MainForm = form1;
sequence[nameof(ShowAccountDialog)] = ShowAccountDialog; sequence[nameof(ShowAccountDialog)] = ShowAccountDialog;
sequence[nameof(ShowSettingsDialog)] = ShowSettingsDialog; sequence[nameof(ShowSettingsDialog)] = ShowSettingsDialog;
sequence[nameof(ScanAccounts)] = ScanAccounts; sequence[nameof(ShowAccountScanning)] = ShowAccountScanning;
sequence[nameof(ShowSearching)] = ShowSearching;
sequence[nameof(ShowQuickFilters)] = ShowQuickFilters;
} }
public async Task RunAsync() => await sequence.RunAsync(); public async Task RunAsync() => await sequence.RunAsync();
private async Task<bool> ShowAccountDialog() private async Task<bool> ShowAccountDialog()
{ {
var result = MainForm.Invoke(() => MessageBox.Show(MainForm, "First, add you Audible account(s).", "Add Accounts", MessageBoxButtons.OKCancel)); if (OkCancelMessageBox("First, add you Audible account(s).", "Add Accounts") is not DialogResult.OK) return false;
if (result is DialogResult.Cancel) return false;
await Task.Delay(750); await Task.Delay(750);
await flashControlAsync(MainForm.settingsToolStripMenuItem);
MainForm.Invoke(MainForm.settingsToolStripMenuItem.ShowDropDown); MainForm.Invoke(MainForm.settingsToolStripMenuItem.ShowDropDown);
await Task.Delay(500); await Task.Delay(500);
await flashControlAsync(MainForm.accountsToolStripMenuItem);
MainForm.Invoke(MainForm.accountsToolStripMenuItem.Select); MainForm.Invoke(MainForm.accountsToolStripMenuItem.Select);
await Task.Delay(1000); await Task.Delay(500);
using var accountSettings = MainForm.Invoke(() => new AccountsDialog()); using var accountSettings = MainForm.Invoke(() => new AccountsDialog());
accountSettings.StartPosition = FormStartPosition.CenterParent; accountSettings.StartPosition = FormStartPosition.CenterParent;
@ -52,14 +57,16 @@ namespace LibationWinForms
private async Task<bool> ShowSettingsDialog() private async Task<bool> ShowSettingsDialog()
{ {
var result = MainForm.Invoke(() => MessageBox.Show(MainForm, "Next, adjust Libation's settings", "Change Settings", MessageBoxButtons.OKCancel)); if (OkCancelMessageBox("Next, adjust Libation's settings", "Change Settings") is not DialogResult.OK) return false;
if (result is DialogResult.Cancel) return false;
await Task.Delay(750); await Task.Delay(750);
await flashControlAsync(MainForm.settingsToolStripMenuItem);
MainForm.Invoke(MainForm.settingsToolStripMenuItem.ShowDropDown); MainForm.Invoke(MainForm.settingsToolStripMenuItem.ShowDropDown);
await Task.Delay(500); await Task.Delay(500);
await flashControlAsync(MainForm.basicSettingsToolStripMenuItem);
MainForm.Invoke(MainForm.basicSettingsToolStripMenuItem.Select); MainForm.Invoke(MainForm.basicSettingsToolStripMenuItem.Select);
await Task.Delay(1000); await Task.Delay(500);
using var settingsDialog = MainForm.Invoke(() => new SettingsDialog()); using var settingsDialog = MainForm.Invoke(() => new SettingsDialog());
@ -100,7 +107,7 @@ namespace LibationWinForms
} }
} }
private async Task<bool> ScanAccounts() private async Task<bool> ShowAccountScanning()
{ {
using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
var count = persister.AccountsSettings.Accounts.Count; var count = persister.AccountsSettings.Accounts.Count;
@ -113,16 +120,134 @@ namespace LibationWinForms
var accounts = count > 1 ? "accounts" :"account"; var accounts = count > 1 ? "accounts" :"account";
var library = count > 1 ? "libraries" : "library"; var library = count > 1 ? "libraries" : "library";
var result = MainForm.Invoke(() => MessageBox.Show(MainForm, $"Finally, scan your Audible {accounts} to sync your {library} with Libation", $"Scan {accounts}", MessageBoxButtons.OKCancel)); if (OkCancelMessageBox($"Finally, scan your Audible {accounts} to sync your {library} with Libation", $"Scan {accounts}") is not DialogResult.OK) return false;
if (result is DialogResult.Cancel) return false;
var scanItem = count > 1 ? MainForm.scanLibraryOfAllAccountsToolStripMenuItem : MainForm.scanLibraryToolStripMenuItem;
await Task.Delay(750); await Task.Delay(750);
await flashControlAsync(MainForm.importToolStripMenuItem);
MainForm.Invoke(MainForm.importToolStripMenuItem.ShowDropDown); MainForm.Invoke(MainForm.importToolStripMenuItem.ShowDropDown);
await Task.Delay(500); await Task.Delay(500);
MainForm.Invoke(() => (count > 1 ? MainForm.scanLibraryOfAllAccountsToolStripMenuItem : MainForm.scanLibraryToolStripMenuItem).Select()); await flashControlAsync(scanItem);
MainForm.Invoke(scanItem.Select);
await Task.Delay(500);
MainForm.Invoke(scanItem.PerformClick);
var tcs = new TaskCompletionSource();
LibraryCommands.ScanEnd += LibraryCommands_ScanEnd;
await tcs.Task;
LibraryCommands.ScanEnd -= LibraryCommands_ScanEnd;
MainForm.productsDisplay.VisibleCountChanged -= productsDisplay_VisibleCountChanged;
return true;
void LibraryCommands_ScanEnd(object sender, int newCount)
{
//if we imported new books, wait for the grid to update before proceeding.
if (newCount > 0)
MainForm.productsDisplay.VisibleCountChanged += productsDisplay_VisibleCountChanged;
else
tcs.SetResult();
}
void productsDisplay_VisibleCountChanged(object sender, int e) => tcs.SetResult();
}
private async Task<bool> ShowSearching()
{
var books = DbContexts.GetLibrary_Flat_NoTracking();
if (books.Count == 0) return true;
var firstAuthor = getFirstAuthor();
if (firstAuthor == null) return true;
if (OkCancelMessageBox("You can filter the grid entries by searching", "Searching") is not DialogResult.OK) return false;
MainForm.Invoke(MainForm.filterSearchTb.Focus);
await flashControlAsync(MainForm.filterSearchTb);
MainForm.Invoke(() => MainForm.filterSearchTb.Text = string.Empty);
foreach (var c in firstAuthor)
{
MainForm.Invoke(() => MainForm.filterSearchTb.Text += c);
await Task.Delay(200);
}
await flashControlAsync(MainForm.filterBtn);
MainForm.Invoke(MainForm.filterBtn.Select);
await Task.Delay(500);
MainForm.Invoke(MainForm.filterBtn.PerformClick);
await Task.Delay(1000); await Task.Delay(1000);
MainForm.Invoke(() => (count > 1 ? MainForm.scanLibraryOfAllAccountsToolStripMenuItem : MainForm.scanLibraryToolStripMenuItem).PerformClick());
MessageBox.Show(MainForm, "Libation provides a built-in cheat sheet for its query language", "Search Cheat Sheet");
await flashControlAsync(MainForm.filterHelpBtn);
using var filterHelp = MainForm.Invoke(() => new SearchSyntaxDialog());
MainForm.Invoke(filterHelp.ShowDialog);
return true; return true;
} }
private async Task<bool> ShowQuickFilters()
{
var firstAuthor = getFirstAuthor();
if (firstAuthor == null) return true;
if (OkCancelMessageBox("Queries that you perform regularly can be added to 'Quick Filters'", "Quick Filters") is not DialogResult.OK) return false;
MainForm.Invoke(() => MainForm.filterSearchTb.Text = firstAuthor);
await Task.Delay(750);
await flashControlAsync(MainForm.addQuickFilterBtn);
await Task.Delay(750);
MainForm.Invoke(MainForm.addQuickFilterBtn.PerformClick);
await flashControlAsync(MainForm.quickFiltersToolStripMenuItem);
MainForm.Invoke(MainForm.quickFiltersToolStripMenuItem.ShowDropDown);
await Task.Delay(500);
MainForm.Invoke(MainForm.editQuickFiltersToolStripMenuItem.Select);
await flashControlAsync(MainForm.editQuickFiltersToolStripMenuItem);
await Task.Delay(500);
var editQuickFilters = MainForm.Invoke(() => new EditQuickFilters());
editQuickFilters.Shown += (_, _) => MessageBox.Show(editQuickFilters, "From here you can edit, delete, and change the order of Quick Filters", "Editing Quick Filters");
MainForm.Invoke(editQuickFilters.ShowDialog);
return true;
}
private string getFirstAuthor()
{
var books = DbContexts.GetLibrary_Flat_NoTracking();
return books.SelectMany(lb => lb.Book.Authors).FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.Name))?.Name;
}
private async Task flashControlAsync(Control control, int flashCount = 3)
{
var backColor = MainForm.Invoke(() => control.BackColor);
for (int i = 0; i < flashCount; i++)
{
MainForm.Invoke(() => control.BackColor = Color.Firebrick);
await Task.Delay(200);
MainForm.Invoke(() => control.BackColor = backColor);
await Task.Delay(200);
}
}
private async Task flashControlAsync(ToolStripItem control, int flashCount = 3)
{
var backColor = MainForm.Invoke(() => control.BackColor);
for (int i = 0; i < flashCount; i++)
{
MainForm.Invoke(() => control.BackColor = Color.Firebrick);
await Task.Delay(200);
MainForm.Invoke(() => control.BackColor = backColor);
await Task.Delay(200);
}
}
private DialogResult OkCancelMessageBox(string message, string caption)
=> MainForm.Invoke(() => MessageBox.Show(MainForm, message, caption, MessageBoxButtons.OKCancel));
} }
} }