diff --git a/Source/LibationAvalonia/App.axaml b/Source/LibationAvalonia/App.axaml index da3b6fad..7677075b 100644 --- a/Source/LibationAvalonia/App.axaml +++ b/Source/LibationAvalonia/App.axaml @@ -1,7 +1,8 @@  + x:Class="LibationAvalonia.App" + Name="Libation"> @@ -69,4 +70,9 @@ + + + + + \ No newline at end of file diff --git a/Source/LibationAvalonia/App.axaml.cs b/Source/LibationAvalonia/App.axaml.cs index c5e309ea..9d1c5159 100644 --- a/Source/LibationAvalonia/App.axaml.cs +++ b/Source/LibationAvalonia/App.axaml.cs @@ -14,6 +14,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using ReactiveUI; +using DataLayer; namespace LibationAvalonia { @@ -45,9 +47,6 @@ namespace LibationAvalonia { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var acceleratorKey = Configuration.IsMacOs ? KeyModifiers.Meta : KeyModifiers.Alt; - AvaloniaLocator.CurrentMutable.Bind().ToFunc(() => new AccessKeyHandlerEx(acceleratorKey)); - var config = Configuration.Instance; if (!config.LibationSettingsAreValid) @@ -219,9 +218,8 @@ namespace LibationAvalonia LoadStyles(); var mainWindow = new MainWindow(); desktop.MainWindow = MainWindow = mainWindow; - mainWindow.RestoreSizeAndLocation(Configuration.Instance); - mainWindow.OnLoad(); mainWindow.OnLibraryLoaded(LibraryTask.GetAwaiter().GetResult()); + mainWindow.RestoreSizeAndLocation(Configuration.Instance); mainWindow.Show(); } diff --git a/Source/LibationAvalonia/Controls/DirectorySelectControl.axaml b/Source/LibationAvalonia/Controls/DirectorySelectControl.axaml index 45f6fe02..c66c7a1b 100644 --- a/Source/LibationAvalonia/Controls/DirectorySelectControl.axaml +++ b/Source/LibationAvalonia/Controls/DirectorySelectControl.axaml @@ -27,7 +27,7 @@ + Text="{Binding Converter={StaticResource KnownDirectoryConverter}}" /> diff --git a/Source/LibationAvalonia/Controls/GroupBox.axaml b/Source/LibationAvalonia/Controls/GroupBox.axaml index 91246b19..e94dfe41 100644 --- a/Source/LibationAvalonia/Controls/GroupBox.axaml +++ b/Source/LibationAvalonia/Controls/GroupBox.axaml @@ -6,9 +6,6 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="LibationAvalonia.Controls.GroupBox"> - - - - + - + - + - - - - + + + + + - - - + + + - + @@ -67,10 +130,10 @@ - - - - + + + + @@ -82,12 +145,12 @@ - + - + - - - - - - + + + + + + @@ -122,19 +185,19 @@ - - + + - - + + - - + + - + - + @@ -155,23 +218,23 @@ - @@ -179,17 +242,17 @@ - + - + @@ -203,10 +266,10 @@ - - - - + + + + diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs index 20dfe906..21e2b87a 100644 --- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs @@ -1,58 +1,32 @@ -using ApplicationServices; +using Avalonia.Controls; +using Avalonia.Input; using Avalonia.ReactiveUI; using DataLayer; using LibationAvalonia.ViewModels; using LibationFileManager; +using LibationUiBase.GridView; using System; using System.Collections.Generic; using System.Linq; namespace LibationAvalonia.Views { - public partial class MainWindow : ReactiveWindow + public partial class MainWindow : ReactiveWindow { - public event EventHandler Load; public event EventHandler> LibraryLoaded; - private readonly MainWindowViewModel _viewModel; - public MainWindow() { - this.DataContext = _viewModel = new MainWindowViewModel(); + DataContext = new MainVM(this); InitializeComponent(); - - // eg: if one of these init'd productsGrid, then another can't reliably subscribe to it - Configure_BackupCounts(); - Configure_ScanAuto(); - Configure_ScanNotification(); - Configure_VisibleBooks(); - Configure_QuickFilters(); - Configure_ScanManual(); - Configure_RemoveBooks(); - Configure_Liberate(); - Configure_Export(); - Configure_Settings(); - Configure_ProcessQueue(); Configure_Upgrade(); - Configure_Filter(); - // misc which belongs in winforms app but doesn't have a UI element - Configure_NonUI(); - _viewModel.ProductsDisplay.RemovableCountChanged += ProductsDisplay_RemovableCountChanged; - _viewModel.ProductsDisplay.VisibleCountChanged += ProductsDisplay_VisibleCountChanged; - - { - this.LibraryLoaded += MainWindow_LibraryLoaded; - - LibraryCommands.LibrarySizeChanged += async (_, _) => await _viewModel.ProductsDisplay.UpdateGridAsync(DbContexts.GetLibrary_Flat_NoTracking(includeParents: true)); - Closing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); - } + Loaded += MainWindow_Loaded; Closing += MainWindow_Closing; - - Opened += MainWindow_Opened; + LibraryLoaded += MainWindow_LibraryLoaded; } - private async void MainWindow_Opened(object sender, EventArgs e) + private async void MainWindow_Loaded(object sender, EventArgs e) { if (Configuration.Instance.FirstLaunch) { @@ -66,21 +40,71 @@ namespace LibationAvalonia.Views Configuration.Instance.FirstLaunch = false; } } - + private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { productsDisplay?.CloseImageDisplay(); + this.SaveSizeAndLocation(Configuration.Instance); } private async void MainWindow_LibraryLoaded(object sender, List dbBooks) { if (QuickFilters.UseDefault) - await performFilter(QuickFilters.Filters.FirstOrDefault()); + await ViewModel.PerformFilter(QuickFilters.Filters.FirstOrDefault()); - _viewModel.ProductsDisplay.BindToGrid(dbBooks); + ViewModel.ProductsDisplay.BindToGrid(dbBooks); } - public void OnLoad() => Load?.Invoke(this, EventArgs.Empty); public void OnLibraryLoaded(List initialLibrary) => LibraryLoaded?.Invoke(this, initialLibrary); + public void ProductsDisplay_LiberateClicked(object _, LibraryBook libraryBook) => ViewModel.LiberateClicked(libraryBook); + public void ProductsDisplay_LiberateSeriesClicked(object _, ISeriesEntry series) => ViewModel.LiberateSeriesClicked(series); + public void ProductsDisplay_ConvertToMp3Clicked(object _, LibraryBook libraryBook) => ViewModel.ConvertToMp3Clicked(libraryBook); + + public async void filterSearchTb_KeyPress(object _, KeyEventArgs e) + { + if (e.Key == Key.Return) + { + await ViewModel.PerformFilter(ViewModel.FilterString); + + // silence the 'ding' + e.Handled = true; + } + } + + private void QuickFiltersMenuItem_KeyDown(object _, KeyEventArgs e) + { + int keyNum = (int)e.Key - 34; + + if (keyNum <= 9 && keyNum >= 1) + { + ViewModel.QuickFilterMenuItems + .OfType() + .FirstOrDefault(i => i.Header is string h && h.StartsWith($"_{keyNum}")) + ?.Command + ?.Execute(null); + } + } + private void Configure_Upgrade() + { + setProgressVisible(false); +#if DEBUG + async System.Threading.Tasks.Task upgradeAvailable(LibationUiBase.UpgradeEventArgs e) + { + var notificationResult = await new LibationAvalonia.Dialogs.UpgradeNotificationDialog(e.UpgradeProperties, e.CapUpgrade).ShowDialogAsync(this); + + e.Ignore = notificationResult == DialogResult.Ignore; + e.InstallUpgrade = notificationResult == DialogResult.OK; + } + + var upgrader = new LibationUiBase.Upgrader(); + upgrader.DownloadProgress += async (_, e) => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => ViewModel.DownloadProgress = e.ProgressPercentage); + upgrader.DownloadBegin += async (_, _) => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(true)); + upgrader.DownloadCompleted += async (_, _) => await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => setProgressVisible(false)); + + Opened += async (_, _) => await upgrader.CheckForUpgradeAsync(upgradeAvailable); +#endif + } + + private void setProgressVisible(bool visible) => ViewModel.DownloadProgress = visible ? 0 : null; } } diff --git a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml index 87b50442..555576dc 100644 --- a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml +++ b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml @@ -11,9 +11,6 @@ - - - diff --git a/Source/LibationAvalonia/Walkthrough.cs b/Source/LibationAvalonia/Walkthrough.cs index b7bd49d1..8cee6272 100644 --- a/Source/LibationAvalonia/Walkthrough.cs +++ b/Source/LibationAvalonia/Walkthrough.cs @@ -149,7 +149,7 @@ namespace LibationAvalonia await displayControlAsync(MainForm.importToolStripMenuItem); await displayControlAsync(scanItem); - scanItem.RaiseEvent(new RoutedEventArgs(MenuItem.ClickEvent)); + scanItem.Command.Execute(null); MainForm.importToolStripMenuItem.Close(); var tcs = new TaskCompletionSource(); @@ -193,7 +193,7 @@ namespace LibationAvalonia await displayControlAsync(MainForm.filterBtn); - MainForm.filterBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)); + MainForm.filterBtn.Command.Execute(null); await Task.Delay(1000); @@ -222,7 +222,7 @@ namespace LibationAvalonia await Task.Delay(750); await displayControlAsync(MainForm.addQuickFilterBtn); - MainForm.addQuickFilterBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)); + MainForm.addQuickFilterBtn.Command.Execute(null); await displayControlAsync(MainForm.quickFiltersToolStripMenuItem); await displayControlAsync(editQuickFiltersToolStripMenuItem);