diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/MainWindowViewModel.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/MainWindowViewModel.cs index 5da5deb5..3c2ed52b 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/MainWindowViewModel.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/MainWindowViewModel.cs @@ -1,17 +1,236 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using ApplicationServices; +using Dinah.Core; +using LibationFileManager; using ReactiveUI; namespace LibationWinForms.AvaloniaUI.ViewModels { public class MainWindowViewModel : ViewModelBase { + private string _filterString; private string _removeBooksButtonText = "Remove # Books from Libation"; + private bool _autoScanChecked = true; + private bool _firstFilterIsDefault = true; private bool _removeButtonsVisible = true; + private int _numAccountsScanning = 2; + private int _accountsCount = 0; + private bool _queueOpen = true; + private int _visibleCount = 1; + private LibraryCommands.LibraryStats _libraryStats; + private int _visibleNotLiberated = 1; + + /// The Process Queue's viewmodel + public ProcessQueueViewModel ProcessQueueViewModel { get; } = new ProcessQueueViewModel(); + + + /// Library filterting query + public string FilterString { get => _filterString; set => this.RaiseAndSetIfChanged(ref _filterString, value); } + + + /// Display text for the "Remove # Books from Libation" button public string RemoveBooksButtonText { get => _removeBooksButtonText; set => this.RaiseAndSetIfChanged(ref _removeBooksButtonText, value); } - public bool RemoveButtonsVisible { get => _removeButtonsVisible; set => this.RaiseAndSetIfChanged(ref _removeButtonsVisible, value); } + + + /// Auto scanning accounts is enables + public bool AutoScanChecked + { + get => _autoScanChecked; + set + { + if (value != _autoScanChecked) + Configuration.Instance.AutoScan = value; + this.RaiseAndSetIfChanged(ref _autoScanChecked, value); + } + } + + + /// Indicates that the first quick filter is the default filter + public bool FirstFilterIsDefault + { + get => _firstFilterIsDefault; + set + { + if (value != _firstFilterIsDefault) + QuickFilters.UseDefault = value; + this.RaiseAndSetIfChanged(ref _firstFilterIsDefault, value); + } + } + + + /// Indicates if the "Remove # Books from Libation" and "Done Removing" buttons shouls be visible + public bool RemoveButtonsVisible + { + get => _removeButtonsVisible; + set + { + this.RaiseAndSetIfChanged(ref _removeButtonsVisible, value); + this.RaisePropertyChanged(nameof(RemoveMenuItemsEnabled)); + } + } + + + + /// The number of accounts currently being scanned + public int NumAccountsScanning + { + get => _numAccountsScanning; + set + { + this.RaiseAndSetIfChanged(ref _numAccountsScanning, value); + this.RaisePropertyChanged(nameof(ActivelyScanning)); + this.RaisePropertyChanged(nameof(RemoveMenuItemsEnabled)); + this.RaisePropertyChanged(nameof(ScanningText)); + } + } + + /// Indicates that Libation is currently scanning account(s) + public bool ActivelyScanning => _numAccountsScanning > 0; + /// Indicates if the "Remove Books" menu items are enabled + public bool RemoveMenuItemsEnabled => !RemoveButtonsVisible && !ActivelyScanning; + /// The library scanning status text + public string ScanningText => _numAccountsScanning == 1 ? "Scanning..." : $"Scanning {_numAccountsScanning} accounts..."; + + + + /// The number of accounts added to Libation + public int AccountsCount + { + get => _accountsCount; + set + { + this.RaiseAndSetIfChanged(ref _accountsCount, value); + this.RaisePropertyChanged(nameof(ZeroAccounts)); + this.RaisePropertyChanged(nameof(AnyAccounts)); + this.RaisePropertyChanged(nameof(OneAccount)); + this.RaisePropertyChanged(nameof(MultipleAccounts)); + } + } + + /// There are no Audible accounts + public bool ZeroAccounts => _accountsCount == 0; + /// There is at least one Audible account + public bool AnyAccounts => _accountsCount > 0; + /// There is exactly one Audible account + public bool OneAccount => _accountsCount == 1; + /// There are more than 1 Audible accounts + public bool MultipleAccounts => _accountsCount > 1; + + + + /// The Process Queue panel is open + public bool QueueOpen + { + get => _queueOpen; + set + { + this.RaiseAndSetIfChanged(ref _queueOpen, value); + QueueHideButtonText = _queueOpen? "❱❱❱" : "❰❰❰"; + this.RaisePropertyChanged(nameof(QueueHideButtonText)); + } + } + + /// The Process Queue's Expand/Collapse button display text + public string QueueHideButtonText { get; private set; } + + + + /// The number of books visible in the Product Display + public int VisibleCount + { + get => _visibleCount; + set + { + this.RaiseAndSetIfChanged(ref _visibleCount, value); + this.RaisePropertyChanged(nameof(VisibleCountText)); + this.RaisePropertyChanged(nameof(VisibleCountMenuItemText)); + } + } + + /// The Bottom-right visible book count status text + public string VisibleCountText => $"Visible: {VisibleCount}"; + /// The Visible Books menu item header text + public string VisibleCountMenuItemText => $"_Visible Books {VisibleCount}"; + + + + /// The user's library statistics + public LibraryCommands.LibraryStats LibraryStats + { + get => _libraryStats; + set + { + this.RaiseAndSetIfChanged(ref _libraryStats, value); + + var backupsCountText + = !LibraryStats.HasBookResults ? "No books. Begin by importing your library" + : !LibraryStats.HasPendingBooks ? $"All {"book".PluralizeWithCount(LibraryStats.booksFullyBackedUp)} backed up" + : $"BACKUPS: No progress: {LibraryStats.booksNoProgress} In process: {LibraryStats.booksDownloadedOnly} Fully backed up: {LibraryStats.booksFullyBackedUp} {(LibraryStats.booksError > 0 ? $" Errors : {LibraryStats.booksError}" : "")}"; + + var pdfCountText + = !LibraryStats.HasPdfResults ? "" + : LibraryStats.pdfsNotDownloaded == 0 ? $" | All {LibraryStats.pdfsDownloaded} PDFs downloaded" + : $" | PDFs: NOT d/l'ed: {LibraryStats.pdfsNotDownloaded} Downloaded: {LibraryStats.pdfsDownloaded}"; + + StatusCountText = backupsCountText + pdfCountText; + + BookBackupsToolStripText + = LibraryStats.HasPendingBooks + ? $"Begin _Book and PDF Backups: {LibraryStats.PendingBooks} remaining" + : "All books have been liberated"; + + PdfBackupsToolStripText + = LibraryStats.pdfsNotDownloaded > 0 + ? $"Begin _PDF Only Backups: {LibraryStats.pdfsNotDownloaded} remaining" + : "All PDFs have been downloaded"; + + + this.RaisePropertyChanged(nameof(HasBookResults)); + this.RaisePropertyChanged(nameof(StatusCountText)); + this.RaisePropertyChanged(nameof(BookBackupsToolStripText)); + this.RaisePropertyChanged(nameof(PdfBackupsToolStripText)); + } + } + + /// Indicates whether the library contains any books + public bool HasBookResults => LibraryStats?.HasBookResults ?? false; + /// Bottom-left library statistics display text + public string StatusCountText { get; private set; } = "[Calculating backed up book quantities] | [Calculating backed up PDFs]"; + /// The "Begin Book and PDF Backup" menu item header text + public string BookBackupsToolStripText { get; private set; } = "Begin _Book and PDF Backups: 0"; + /// The "Begin PDF Only Backup" menu item header text + public string PdfBackupsToolStripText { get; private set; } = "Begin _PDF Only Backups: 0"; + + + + /// The number of books visible in the Products Display that have not yet been liberated + public int VisibleNotLiberated + { + get => _visibleNotLiberated; + set + { + this.RaiseAndSetIfChanged(ref _visibleNotLiberated, value); + + LiberateVisibleToolStripText + = AnyVisibleNotLiberated + ? $"Liberate _Visible Books: {VisibleNotLiberated}" + : "All visible books are liberated"; + + LiberateVisibleToolStripText_2 + = AnyVisibleNotLiberated + ? $"_Liberate: {VisibleNotLiberated}" + : "All visible books are liberated"; + + this.RaisePropertyChanged(nameof(AnyVisibleNotLiberated)); + this.RaisePropertyChanged(nameof(LiberateVisibleToolStripText)); + this.RaisePropertyChanged(nameof(LiberateVisibleToolStripText_2)); + } + } + + /// Indicates if any of the books visible in the Products Display haven't been liberated + public bool AnyVisibleNotLiberated => VisibleNotLiberated > 0; + /// The "Liberate Visible Books" menu item header text (submenu item of the "Liberate Menu" menu item) + public string LiberateVisibleToolStripText { get; private set; } = "Liberate _Visible Books: 0"; + /// The "Liberate" menu item header text (submenu item of the "Visible Books" menu item) + public string LiberateVisibleToolStripText_2 { get; private set; } = "_Liberate: 0"; } } diff --git a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs index 271b76ad..9345a6cb 100644 --- a/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs +++ b/Source/LibationWinForms/AvaloniaUI/ViewModels/ProcessQueueViewModel.cs @@ -1,5 +1,6 @@ using ApplicationServices; using Avalonia.Threading; +using DataLayer; using ReactiveUI; using System; using System.Collections.Generic; @@ -19,10 +20,13 @@ namespace LibationWinForms.AvaloniaUI.ViewModels public Task QueueRunner { get; private set; } public bool Running => !QueueRunner?.IsCompleted ?? false; + private readonly ProcessQueue.LogMe Logger; + public ProcessQueueViewModel() { Queue.QueuededCountChanged += Queue_QueuededCountChanged; Queue.CompletedCountChanged += Queue_CompletedCountChanged; + Logger = ProcessQueue.LogMe.RegisterForm(this); } private int _completedCount; @@ -66,6 +70,73 @@ namespace LibationWinForms.AvaloniaUI.ViewModels })); } + + #region Add Books to Queue + + private bool isBookInQueue(LibraryBook libraryBook) + => Queue.Any(b => b?.LibraryBook?.Book?.AudibleProductId == libraryBook.Book.AudibleProductId); + + public void AddDownloadPdf(LibraryBook libraryBook) + => AddDownloadPdf(new List() { libraryBook }); + + public void AddDownloadDecrypt(LibraryBook libraryBook) + => AddDownloadDecrypt(new List() { libraryBook }); + + public void AddConvertMp3(LibraryBook libraryBook) + => AddConvertMp3(new List() { libraryBook }); + + public void AddDownloadPdf(IEnumerable entries) + { + List procs = new(); + foreach (var entry in entries) + { + if (isBookInQueue(entry)) + continue; + + ProcessBook2 pbook = new(entry, Logger); + pbook.AddDownloadPdf(); + procs.Add(pbook); + } + + Serilog.Log.Logger.Information("Queueing {count} books", procs.Count); + AddToQueue(procs); + } + + public void AddDownloadDecrypt(IEnumerable entries) + { + List procs = new(); + foreach (var entry in entries) + { + if (isBookInQueue(entry)) + continue; + + ProcessBook2 pbook = new(entry, Logger); + pbook.AddDownloadDecryptBook(); + pbook.AddDownloadPdf(); + procs.Add(pbook); + } + + Serilog.Log.Logger.Information("Queueing {count} books", procs.Count); + AddToQueue(procs); + } + + public void AddConvertMp3(IEnumerable entries) + { + List procs = new(); + foreach (var entry in entries) + { + if (isBookInQueue(entry)) + continue; + + ProcessBook2 pbook = new(entry, Logger); + pbook.AddConvertToMp3(); + procs.Add(pbook); + } + + Serilog.Log.Logger.Information("Queueing {count} books", procs.Count); + AddToQueue(procs); + } + public void AddToQueue(IEnumerable pbook) { Dispatcher.UIThread.Post(() => @@ -76,6 +147,8 @@ namespace LibationWinForms.AvaloniaUI.ViewModels }); } + #endregion + DateTime StartingTime; private async Task QueueLoop() { diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.BackupCounts.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.BackupCounts.axaml.cs index 4d2cbb42..e7e57006 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.BackupCounts.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.BackupCounts.axaml.cs @@ -12,21 +12,12 @@ namespace LibationWinForms.AvaloniaUI.Views private System.ComponentModel.BackgroundWorker updateCountsBw = new(); private void Configure_BackupCounts() { - // init formattable - beginBookBackupsToolStripMenuItem.Format(0); - beginPdfBackupsToolStripMenuItem.Format(0); - pdfsCountsLbl.Text = "| [Calculating backed up PDFs]"; - Load += setBackupCounts; LibraryCommands.LibrarySizeChanged += setBackupCounts; LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts; updateCountsBw.DoWork += UpdateCountsBw_DoWork; - updateCountsBw.RunWorkerCompleted += exportMenuEnable; - updateCountsBw.RunWorkerCompleted += updateBottomBookNumbers; - updateCountsBw.RunWorkerCompleted += update_BeginBookBackups_menuItem; - updateCountsBw.RunWorkerCompleted += updateBottomPdfNumbersAsync; - updateCountsBw.RunWorkerCompleted += udpate_BeginPdfOnlyBackups_menuItem; + updateCountsBw.RunWorkerCompleted += updateBottomNumbersAsync; } private bool runBackupCountsAgain; private void setBackupCounts(object _, object __) @@ -45,74 +36,9 @@ namespace LibationWinForms.AvaloniaUI.Views } } - private void exportMenuEnable(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) + private void updateBottomNumbersAsync(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) { - var libraryStats = e.Result as LibraryCommands.LibraryStats; - Dispatcher.UIThread.Post(() => exportLibraryToolStripMenuItem.IsEnabled = libraryStats.HasBookResults); - } - - // this cannot be cleanly be FormattableToolStripMenuItem because of the optional "Errors" text - private const string backupsCountsLbl_Format = "BACKUPS: No progress: {0} In process: {1} Fully backed up: {2}"; - - private void updateBottomBookNumbers(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) - { - var libraryStats = e.Result as LibraryCommands.LibraryStats; - - var formatString - = !libraryStats.HasBookResults ? "No books. Begin by importing your library" - : libraryStats.booksError > 0 ? backupsCountsLbl_Format + " Errors: {3}" - : libraryStats.HasPendingBooks ? backupsCountsLbl_Format - : $"All {"book".PluralizeWithCount(libraryStats.booksFullyBackedUp)} backed up"; - var statusStripText = string.Format(formatString, - libraryStats.booksNoProgress, - libraryStats.booksDownloadedOnly, - libraryStats.booksFullyBackedUp, - libraryStats.booksError); - Dispatcher.UIThread.InvokeAsync(() => backupsCountsLbl.Text = statusStripText); - } - - // update 'begin book backups' menu item - private void update_BeginBookBackups_menuItem(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) - { - var libraryStats = e.Result as LibraryCommands.LibraryStats; - - var menuItemText - = libraryStats.HasPendingBooks - ? $"{libraryStats.PendingBooks} remaining" - : "All books have been liberated"; - Dispatcher.UIThread.InvokeAsync(() => - { - beginBookBackupsToolStripMenuItem.Format(menuItemText); - beginBookBackupsToolStripMenuItem.IsEnabled = libraryStats.HasPendingBooks; - }); - } - - private async void updateBottomPdfNumbersAsync(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) - { - var libraryStats = e.Result as LibraryCommands.LibraryStats; - - // don't need to assign the output of Format(). It just makes this logic cleaner - var statusStripText - = !libraryStats.HasPdfResults ? "" - : libraryStats.pdfsNotDownloaded > 0 ? await Dispatcher.UIThread.InvokeAsync(()=> pdfsCountsLbl.Format(libraryStats.pdfsNotDownloaded, libraryStats.pdfsDownloaded)) - : $" | All {libraryStats.pdfsDownloaded} PDFs downloaded"; - await Dispatcher.UIThread.InvokeAsync(() => pdfsCountsLbl.Text = statusStripText); - } - - // update 'begin pdf only backups' menu item - private void udpate_BeginPdfOnlyBackups_menuItem(object _, System.ComponentModel.RunWorkerCompletedEventArgs e) - { - var libraryStats = e.Result as LibraryCommands.LibraryStats; - - var menuItemText - = libraryStats.pdfsNotDownloaded > 0 - ? $"{libraryStats.pdfsNotDownloaded} remaining" - : "All PDFs have been downloaded"; - Dispatcher.UIThread.InvokeAsync(() => - { - beginPdfBackupsToolStripMenuItem.Format(menuItemText); - beginPdfBackupsToolStripMenuItem.IsEnabled = libraryStats.pdfsNotDownloaded > 0; - }); + _viewModel.LibraryStats = e.Result as LibraryCommands.LibraryStats; } } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Filter.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Filter.axaml.cs index 25cefe6f..594724dc 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Filter.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Filter.axaml.cs @@ -18,7 +18,7 @@ namespace LibationWinForms.AvaloniaUI.Views { if (e.Key == Key.Return) { - await performFilter(this.filterSearchTb.Text); + await performFilter(_viewModel.FilterString); // silence the 'ding' e.Handled = true; @@ -26,12 +26,12 @@ namespace LibationWinForms.AvaloniaUI.Views } public async void filterBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) - => await performFilter(this.filterSearchTb.Text); + => await performFilter(_viewModel.FilterString); private string lastGoodFilter = ""; private async Task performFilter(string filterString) { - this.filterSearchTb.Text = filterString; + _viewModel.FilterString = filterString; try { diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Liberate.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Liberate.axaml.cs index ac3b31ea..c19ac0ce 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Liberate.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.Liberate.axaml.cs @@ -19,7 +19,7 @@ namespace LibationWinForms.AvaloniaUI.Views Serilog.Log.Logger.Information("Begin backing up all library books"); - processBookQueue1.AddDownloadDecrypt( + _viewModel.ProcessQueueViewModel.AddDownloadDecrypt( ApplicationServices.DbContexts .GetLibrary_Flat_NoTracking() .UnLiberated() @@ -34,7 +34,7 @@ namespace LibationWinForms.AvaloniaUI.Views public async void beginPdfBackupsToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) { SetQueueCollapseState(false); - await Task.Run(() => processBookQueue1.AddDownloadPdf(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() + await Task.Run(() => _viewModel.ProcessQueueViewModel.AddDownloadPdf(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() .Where(lb => lb.Book.UserDefinedItem.PdfStatus is DataLayer.LiberatedStatus.NotLiberated))); } @@ -51,7 +51,7 @@ namespace LibationWinForms.AvaloniaUI.Views if (result == DialogResult.Yes) { SetQueueCollapseState(false); - await Task.Run(() => processBookQueue1.AddConvertMp3(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() + await Task.Run(() => _viewModel.ProcessQueueViewModel.AddConvertMp3(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking() .Where(lb => lb.Book.UserDefinedItem.BookStatus is DataLayer.LiberatedStatus.Liberated && lb.Book.ContentType is DataLayer.ContentType.Product))); } //Only Queue Liberated books for conversion. This isn't a perfect filter, but it's better than nothing. diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs index 4246048e..05d80140 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ProcessQueue.axaml.cs @@ -11,7 +11,7 @@ namespace LibationWinForms.AvaloniaUI.Views { private void Configure_ProcessQueue() { - var collapseState = !Configuration.Instance.GetNonString(nameof(splitContainer1.IsPaneOpen)); + var collapseState = !Configuration.Instance.GetNonString(nameof(_viewModel.QueueOpen)); SetQueueCollapseState(collapseState); } @@ -23,13 +23,13 @@ namespace LibationWinForms.AvaloniaUI.Views { Serilog.Log.Logger.Information("Begin single book backup of {libraryBook}", libraryBook); SetQueueCollapseState(false); - processBookQueue1.AddDownloadDecrypt(libraryBook); + _viewModel.ProcessQueueViewModel.AddDownloadDecrypt(libraryBook); } else if (libraryBook.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated) { Serilog.Log.Logger.Information("Begin single pdf backup of {libraryBook}", libraryBook); SetQueueCollapseState(false); - processBookQueue1.AddDownloadPdf(libraryBook); + _viewModel.ProcessQueueViewModel.AddDownloadPdf(libraryBook); } else if (libraryBook.Book.Audio_Exists()) { @@ -49,14 +49,13 @@ namespace LibationWinForms.AvaloniaUI.Views } private void SetQueueCollapseState(bool collapsed) { - splitContainer1.IsPaneOpen = !collapsed; - toggleQueueHideBtn.Content = splitContainer1.IsPaneOpen ? "❱❱❱" : "❰❰❰"; + _viewModel.QueueOpen = !collapsed; } public void ToggleQueueHideBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) { - SetQueueCollapseState(splitContainer1.IsPaneOpen); - Configuration.Instance.SetObject(nameof(splitContainer1.IsPaneOpen), splitContainer1.IsPaneOpen); + SetQueueCollapseState(_viewModel.QueueOpen); + Configuration.Instance.SetObject(nameof(_viewModel.QueueOpen), _viewModel.QueueOpen); } } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.QuickFilters.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.QuickFilters.axaml.cs index ea430683..159320c2 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.QuickFilters.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.QuickFilters.axaml.cs @@ -11,9 +11,8 @@ namespace LibationWinForms.AvaloniaUI.Views { private void Configure_QuickFilters() { - Load += updateFirstFilterIsDefaultToolStripMenuItem; + _viewModel.FirstFilterIsDefault = QuickFilters.UseDefault; Load += updateFiltersMenu; - QuickFilters.UseDefaultChanged += updateFirstFilterIsDefaultToolStripMenuItem; QuickFilters.Updated += updateFiltersMenu; } @@ -49,14 +48,16 @@ namespace LibationWinForms.AvaloniaUI.Views quickFiltersToolStripMenuItem.Items = allItems; } - private void updateFirstFilterIsDefaultToolStripMenuItem(object sender, EventArgs e) - => firstFilterIsDefaultToolStripMenuItem_Checkbox.IsChecked = QuickFilters.UseDefault; - public void firstFilterIsDefaultToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) - => QuickFilters.UseDefault = firstFilterIsDefaultToolStripMenuItem_Checkbox.IsChecked != true; + { + if (sender is MenuItem mi && mi.Icon is CheckBox checkBox) + { + checkBox.IsChecked = !(checkBox.IsChecked ?? false); + } + } public void addQuickFilterBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) - => QuickFilters.Add(this.filterSearchTb.Text); + => QuickFilters.Add(_viewModel.FilterString); public void editQuickFiltersToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) => new EditQuickFilters().ShowDialog(); diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.RemoveBooks.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.RemoveBooks.axaml.cs index 9d1a0abc..ecf5e0c6 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.RemoveBooks.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.RemoveBooks.axaml.cs @@ -14,7 +14,6 @@ namespace LibationWinForms.AvaloniaUI.Views return; _viewModel.RemoveButtonsVisible = false; - removeLibraryBooksToolStripMenuItem.Click += removeLibraryBooksToolStripMenuItem_Click; } public async void removeBooksBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) @@ -29,9 +28,7 @@ namespace LibationWinForms.AvaloniaUI.Views productsDisplay.CloseRemoveBooksColumn(); //Restore the filter - filterSearchTb.IsEnabled = true; - filterSearchTb.IsVisible = true; - await performFilter(filterSearchTb.Text); + await performFilter(_viewModel.FilterString); } public void removeLibraryBooksToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) @@ -77,8 +74,6 @@ namespace LibationWinForms.AvaloniaUI.Views //For removing books within a filter set, use //Visible Books > Remove from library - filterSearchTb.IsEnabled = false; - filterSearchTb.IsVisible = false; productsDisplay.Filter(null); _viewModel.RemoveButtonsVisible = true; diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanAuto.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanAuto.axaml.cs index b2af2d9c..a441a441 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanAuto.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanAuto.axaml.cs @@ -1,5 +1,6 @@ using ApplicationServices; using AudibleUtilities; +using Avalonia.Controls; using Dinah.Core; using LibationFileManager; using System; @@ -42,8 +43,8 @@ namespace LibationWinForms.AvaloniaUI.Views } }; - // load init state to menu checkbox - Load += updateAutoScanLibraryToolStripMenuItem; + _viewModel.AutoScanChecked = Configuration.Instance.AutoScan; + // if enabled: begin on load Load += startAutoScan; @@ -52,7 +53,6 @@ namespace LibationWinForms.AvaloniaUI.Views AccountsSettingsPersister.Saved += accountsPostSave; // when autoscan setting is changed, update menu checkbox and run autoscan - Configuration.Instance.AutoScanChanged += updateAutoScanLibraryToolStripMenuItem; Configuration.Instance.AutoScanChanged += startAutoScan; } @@ -84,7 +84,12 @@ namespace LibationWinForms.AvaloniaUI.Views else autoScanTimer.Stop(); } - private void updateAutoScanLibraryToolStripMenuItem(object sender, EventArgs e) => autoScanLibraryToolStripMenuItemCheckbox.IsChecked = Configuration.Instance.AutoScan; - private void autoScanLibraryToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args) => Configuration.Instance.AutoScan = autoScanLibraryToolStripMenuItemCheckbox.IsChecked != true; + public void autoScanLibraryToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + if (sender is MenuItem mi && mi.Icon is CheckBox checkBox) + { + checkBox.IsChecked = !(checkBox.IsChecked ?? false); + } + } } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanManual.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanManual.axaml.cs index 2564b720..eec098be 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanManual.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanManual.axaml.cs @@ -22,31 +22,7 @@ namespace LibationWinForms.AvaloniaUI.Views private void refreshImportMenu(object _, EventArgs __) { using var persister = AudibleApiStorage.GetAccountsSettingsPersister(); - var count = persister.AccountsSettings.Accounts.Count; - - autoScanLibraryToolStripMenuItem.IsVisible = count > 0; - - noAccountsYetAddAccountToolStripMenuItem.IsVisible = count == 0; - scanLibraryToolStripMenuItem.IsVisible = count == 1; - scanLibraryOfAllAccountsToolStripMenuItem.IsVisible = count > 1; - scanLibraryOfSomeAccountsToolStripMenuItem.IsVisible = count > 1; - - removeLibraryBooksToolStripMenuItem.IsVisible = count > 0; - - //Avalonia will not fire the Click event for a MenuItem with children, - //so if only 1 account, remove the children. Otherwise add children - //for multiple accounts. - removeLibraryBooksToolStripMenuItem.Items = null; - - if (count > 1) - { - removeLibraryBooksToolStripMenuItem.Items = - new List - { - removeSomeAccountsToolStripMenuItem, - removeAllAccountsToolStripMenuItem - }; - } + _viewModel.AccountsCount = persister.AccountsSettings.Accounts.Count; } public async void noAccountsYetAddAccountToolStripMenuItem_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanNotification.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanNotification.axaml.cs index 4ace3e7c..09c7bfd4 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanNotification.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.ScanNotification.axaml.cs @@ -9,36 +9,18 @@ namespace LibationWinForms.AvaloniaUI.Views { private void Configure_ScanNotification() { - scanningToolStripMenuItem.IsVisible = false; + _viewModel.NumAccountsScanning = 0; LibraryCommands.ScanBegin += LibraryCommands_ScanBegin; LibraryCommands.ScanEnd += LibraryCommands_ScanEnd; } private void LibraryCommands_ScanBegin(object sender, int accountsLength) { - removeLibraryBooksToolStripMenuItem.IsEnabled = false; - removeAllAccountsToolStripMenuItem.IsEnabled = false; - removeSomeAccountsToolStripMenuItem.IsEnabled = false; - scanLibraryToolStripMenuItem.IsEnabled = false; - scanLibraryOfAllAccountsToolStripMenuItem.IsEnabled = false; - scanLibraryOfSomeAccountsToolStripMenuItem.IsEnabled = false; - - this.scanningToolStripMenuItem.IsVisible = true; - this.scanningToolStripMenuItem_Text.Text - = (accountsLength == 1) - ? "Scanning..." - : $"Scanning {accountsLength} accounts..."; + _viewModel.NumAccountsScanning = accountsLength; } private void LibraryCommands_ScanEnd(object sender, EventArgs e) { - removeLibraryBooksToolStripMenuItem.IsEnabled = true; - removeAllAccountsToolStripMenuItem.IsEnabled = true; - removeSomeAccountsToolStripMenuItem.IsEnabled = true; - scanLibraryToolStripMenuItem.IsEnabled = true; - scanLibraryOfAllAccountsToolStripMenuItem.IsEnabled = true; - scanLibraryOfSomeAccountsToolStripMenuItem.IsEnabled = true; - - this.scanningToolStripMenuItem.IsVisible = false; + _viewModel.NumAccountsScanning = 0; } } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs index 98896a42..207c86b2 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.VisibleBooks.axaml.cs @@ -13,14 +13,6 @@ namespace LibationWinForms.AvaloniaUI.Views { private void Configure_VisibleBooks() { - // init formattable - visibleCountLbl.Format(0); - liberateVisibleToolStripMenuItem_VisibleBooksMenu.Format(0); - liberateVisibleToolStripMenuItem_LiberateMenu.Format(0); - - // top menu strip - visibleBooksToolStripMenuItem.Format(0); - LibraryCommands.BookUserDefinedItemCommitted += setLiberatedVisibleMenuItemAsync; } @@ -35,7 +27,7 @@ namespace LibationWinForms.AvaloniaUI.Views Serilog.Log.Logger.Information("Begin backing up visible library books"); - processBookQueue1.AddDownloadDecrypt( + _viewModel.ProcessQueueViewModel.AddDownloadDecrypt( productsDisplay .GetVisibleBookEntries() .UnLiberated() @@ -107,44 +99,14 @@ namespace LibationWinForms.AvaloniaUI.Views } public async void productsDisplay_VisibleCountChanged(object sender, int qty) { - Dispatcher.UIThread.Post(() => - { - // bottom-left visible count - visibleCountLbl.Format(qty); - - // top menu strip - visibleBooksToolStripMenuItem.Format(qty); - visibleBooksToolStripMenuItem.IsEnabled = qty > 0; - }); - - //Not used for anything? - var notLiberatedCount = productsDisplay.GetVisibleBookEntries().Count(lb => lb.Book.UserDefinedItem.BookStatus == DataLayer.LiberatedStatus.NotLiberated); + _viewModel.VisibleCount = qty; await Task.Run(setLiberatedVisibleMenuItem); } void setLiberatedVisibleMenuItem() - { - var notLiberated = productsDisplay.GetVisibleBookEntries().Count(lb => lb.Book.UserDefinedItem.BookStatus == DataLayer.LiberatedStatus.NotLiberated); - - Dispatcher.UIThread.Post(() => - { - if (notLiberated > 0) - { - liberateVisibleToolStripMenuItem_VisibleBooksMenu.Format(notLiberated); - liberateVisibleToolStripMenuItem_VisibleBooksMenu.IsEnabled = true; - - liberateVisibleToolStripMenuItem_LiberateMenu.Format(notLiberated); - liberateVisibleToolStripMenuItem_LiberateMenu.IsEnabled = true; - } - else - { - liberateVisibleToolStripMenuItem_VisibleBooksMenu.Header = "All visible books are liberated"; - liberateVisibleToolStripMenuItem_VisibleBooksMenu.IsEnabled = false; - - liberateVisibleToolStripMenuItem_LiberateMenu.Header = "All visible books are liberated"; - liberateVisibleToolStripMenuItem_LiberateMenu.IsEnabled = false; - } - }); - } + => _viewModel.VisibleNotLiberated + = productsDisplay + .GetVisibleBookEntries() + .Count(lb => lb.Book.UserDefinedItem.BookStatus == LiberatedStatus.NotLiberated); } } diff --git a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml index 61053fe3..22be4f5a 100644 --- a/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml +++ b/Source/LibationWinForms/AvaloniaUI/Views/MainWindow/MainWindow.axaml @@ -25,6 +25,9 @@ + + + @@ -32,20 +35,26 @@ - + - + - - - - - - - - + + + + + + + + + + + + + + @@ -53,11 +62,14 @@ - - + + - + + + + @@ -65,8 +77,11 @@ - + + + + @@ -74,26 +89,32 @@ - + - Toggle _Me0 + - + - + + + + - + - - + + - - - + + + + + + @@ -107,9 +128,9 @@ - + - + @@ -123,29 +144,29 @@ -