diff --git a/Images/libation_glass.svg b/Images/libation_glass.svg index 7ecd7089..bc632ab1 100644 --- a/Images/libation_glass.svg +++ b/Images/libation_glass.svg @@ -1,34 +1,36 @@ - + - - + diff --git a/Images/libation_hangover.svg b/Images/libation_hangover.svg index e1759e86..5d89848c 100644 --- a/Images/libation_hangover.svg +++ b/Images/libation_hangover.svg @@ -1,30 +1,31 @@ - - - - - - + + + + diff --git a/Source/HangoverAvalonia/Assets/hangover.ico b/Source/HangoverAvalonia/Assets/hangover.ico index c29a9b6a..a210d139 100644 Binary files a/Source/HangoverAvalonia/Assets/hangover.ico and b/Source/HangoverAvalonia/Assets/hangover.ico differ diff --git a/Source/HangoverAvalonia/hangover.ico b/Source/HangoverAvalonia/hangover.ico index c29a9b6a..a210d139 100644 Binary files a/Source/HangoverAvalonia/hangover.ico and b/Source/HangoverAvalonia/hangover.ico differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow-PSD.zip b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow-PSD.zip new file mode 100644 index 00000000..80885c7c Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow-PSD.zip differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow.ico b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow.ico index c29a9b6a..a210d139 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow.ico and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow.ico differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_1024.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_1024.png new file mode 100644 index 00000000..2727b889 Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_1024.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_128.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_128.png index da3db627..ede45a85 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_128.png and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_128.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_16.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_16.png index 6cdd85a4..c08d50bc 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_16.png and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_16.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_20.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_20.png new file mode 100644 index 00000000..ef6fcdcc Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_20.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_24.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_24.png new file mode 100644 index 00000000..6456e90a Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_24.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_256.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_256.png index cb0f01bf..18f415af 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_256.png and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_256.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_32.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_32.png index d57c68bc..d6cd74ef 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_32.png and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_32.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_40.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_40.png new file mode 100644 index 00000000..f2c5cc1c Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_40.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_48.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_48.png new file mode 100644 index 00000000..7bfd0f89 Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_48.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_512.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_512.png index 023dedc5..23e8a620 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_512.png and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_512.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_64.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_64.png index 11873bf1..e8d0fa43 100644 Binary files a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_64.png and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_64.png differ diff --git a/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_96.png b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_96.png new file mode 100644 index 00000000..f49c0789 Binary files /dev/null and b/Source/HangoverWinForms/Resources/Hangover icon/spilled-glass-with-glow_96.png differ diff --git a/Source/HangoverWinForms/hangover.ico b/Source/HangoverWinForms/hangover.ico index c29a9b6a..a210d139 100644 Binary files a/Source/HangoverWinForms/hangover.ico and b/Source/HangoverWinForms/hangover.ico differ diff --git a/Source/LibationAvalonia/App.axaml b/Source/LibationAvalonia/App.axaml index 13a64b07..a2499ea8 100644 --- a/Source/LibationAvalonia/App.axaml +++ b/Source/LibationAvalonia/App.axaml @@ -20,6 +20,11 @@ + + + + 0 + @@ -28,17 +33,11 @@ - - - - - - @@ -47,35 +46,32 @@ - - - - - - - - + - - + - + + + + + + - + + + + + + + + diff --git a/Source/LibationAvalonia/App.axaml.cs b/Source/LibationAvalonia/App.axaml.cs index 55e2a137..3201b953 100644 --- a/Source/LibationAvalonia/App.axaml.cs +++ b/Source/LibationAvalonia/App.axaml.cs @@ -2,7 +2,6 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; -using Avalonia.Media; using Avalonia.Platform; using Avalonia.Styling; using LibationAvalonia.Dialogs; @@ -13,19 +12,22 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Avalonia.Threading; +using Dinah.Core; +using LibationAvalonia.Themes; +using Avalonia.Data.Core.Plugins; +using System.Linq; +#nullable enable namespace LibationAvalonia { public class App : Application { - public static MainWindow MainWindow { get; private set; } - public static IBrush ProcessQueueBookFailedBrush { get; private set; } - public static IBrush ProcessQueueBookCompletedBrush { get; private set; } - public static IBrush ProcessQueueBookCancelledBrush { get; private set; } - public static IBrush ProcessQueueBookDefaultBrush { get; private set; } - public static IBrush SeriesEntryGridBackgroundBrush { get; private set; } + public static Task>? LibraryTask { get; set; } + public static ChardonnayTheme? DefaultThemeColors { get; private set; } + public static MainWindow? MainWindow { get; private set; } + public static Uri AssetUriBase { get; } = new("avares://Libation/Assets/"); + public static new Application Current => Application.Current ?? throw new InvalidOperationException("The Avalonia app hasn't started yet."); - public static readonly Uri AssetUriBase = new("avares://Libation/Assets/"); public static Stream OpenAsset(string assetRelativePath) => AssetLoader.Open(new Uri(AssetUriBase, assetRelativePath)); @@ -34,12 +36,16 @@ namespace LibationAvalonia AvaloniaXamlLoader.Load(this); } - public static Task> LibraryTask; - public override void OnFrameworkInitializationCompleted() { + DefaultThemeColors = ChardonnayTheme.GetLiveTheme(); + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + // Avoid duplicate validations from both Avalonia and the CommunityToolkit. + // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins + DisableAvaloniaDataAnnotationValidation(); + var config = Configuration.Instance; if (!config.LibationSettingsAreValid) @@ -69,11 +75,23 @@ namespace LibationAvalonia base.OnFrameworkInitializationCompleted(); } - - private async void Setup_Closing(object sender, System.ComponentModel.CancelEventArgs e) + private void DisableAvaloniaDataAnnotationValidation() { - var setupDialog = sender as SetupDialog; - var desktop = ApplicationLifetime as IClassicDesktopStyleApplicationLifetime; + // Get an array of plugins to remove + var dataValidationPluginsToRemove = + BindingPlugins.DataValidators.OfType().ToArray(); + + // remove each entry found + foreach (var plugin in dataValidationPluginsToRemove) + { + BindingPlugins.DataValidators.Remove(plugin); + } + } + + private async void Setup_Closing(object? sender, System.ComponentModel.CancelEventArgs e) + { + if (sender is not SetupDialog setupDialog || ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) + return; try { @@ -87,7 +105,7 @@ namespace LibationAvalonia if (setupDialog.Config.LibationSettingsAreValid) { - string theme = setupDialog.SelectedTheme.Content as string; + string? theme = setupDialog.SelectedTheme.Content as string; setupDialog.Config.SetString(theme, nameof(ThemeVariant)); @@ -143,7 +161,7 @@ namespace LibationAvalonia desktop.MainWindow = libationFilesDialog; libationFilesDialog.Show(); - void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e) + void WindowClosing(object? sender, System.ComponentModel.CancelEventArgs e) { libationFilesDialog.Closing -= WindowClosing; e.Cancel = true; @@ -201,16 +219,9 @@ namespace LibationAvalonia private static void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop) { - Current.RequestedThemeVariant = Configuration.Instance.GetString(propertyName: nameof(ThemeVariant)) switch - { - nameof(ThemeVariant.Dark) => ThemeVariant.Dark, - nameof(ThemeVariant.Light) => ThemeVariant.Light, - // "System" - _ => ThemeVariant.Default - }; + Configuration.Instance.PropertyChanged += ThemeVariant_PropertyChanged; + OpenAndApplyTheme(Configuration.Instance.GetString(propertyName: nameof(ThemeVariant))); - //Reload colors for current theme - LoadStyles(); var mainWindow = new MainWindow(); desktop.MainWindow = MainWindow = mainWindow; mainWindow.Loaded += MainWindow_Loaded; @@ -218,19 +229,23 @@ namespace LibationAvalonia mainWindow.Show(); } - private static async void MainWindow_Loaded(object sender, Avalonia.Interactivity.RoutedEventArgs e) + [PropertyChangeFilter(nameof(ThemeVariant))] + private static void ThemeVariant_PropertyChanged(object sender, PropertyChangedEventArgsEx e) + => OpenAndApplyTheme(e.NewValue as string); + + private static void OpenAndApplyTheme(string? themeVariant) { - var library = await LibraryTask; - await Dispatcher.UIThread.InvokeAsync(() => MainWindow.OnLibraryLoadedAsync(library)); + using var themePersister = ChardonnayThemePersister.Create(); + themePersister?.Target.ApplyTheme(themeVariant); } - private static void LoadStyles() + private static async void MainWindow_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e) { - ProcessQueueBookFailedBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookFailedBrush)); - ProcessQueueBookCompletedBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookCompletedBrush)); - ProcessQueueBookCancelledBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookCancelledBrush)); - SeriesEntryGridBackgroundBrush = AvaloniaUtils.GetBrushFromResources(nameof(SeriesEntryGridBackgroundBrush)); - ProcessQueueBookDefaultBrush = AvaloniaUtils.GetBrushFromResources(nameof(ProcessQueueBookDefaultBrush)); + if (LibraryTask is not null && MainWindow is not null) + { + var library = await LibraryTask; + await Dispatcher.UIThread.InvokeAsync(() => MainWindow.OnLibraryLoadedAsync(library)); + } } } } diff --git a/Source/LibationAvalonia/Assets/DataGridColumnHeader.xaml b/Source/LibationAvalonia/Assets/DataGridColumnHeader.xaml deleted file mode 100644 index 8c82dc2d..00000000 --- a/Source/LibationAvalonia/Assets/DataGridColumnHeader.xaml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Source/LibationAvalonia/Assets/libation.ico b/Source/LibationAvalonia/Assets/libation.ico index d3e00443..88dff50b 100644 Binary files a/Source/LibationAvalonia/Assets/libation.ico and b/Source/LibationAvalonia/Assets/libation.ico differ diff --git a/Source/LibationAvalonia/AvaloniaUtils.cs b/Source/LibationAvalonia/AvaloniaUtils.cs index 714491bf..11508b70 100644 --- a/Source/LibationAvalonia/AvaloniaUtils.cs +++ b/Source/LibationAvalonia/AvaloniaUtils.cs @@ -1,8 +1,8 @@ -using Avalonia.Controls; -using Avalonia.Media; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Media.Imaging; using Avalonia.VisualTree; -using LibationAvalonia.Dialogs; using LibationFileManager; using System.Threading.Tasks; @@ -11,17 +11,21 @@ namespace LibationAvalonia { internal static class AvaloniaUtils { - public static IBrush GetBrushFromResources(string name) - => GetBrushFromResources(name, Brushes.Transparent); - public static IBrush GetBrushFromResources(string name, IBrush defaultBrush) + public static T DynamicResource(this T control, AvaloniaProperty prop, object resourceKey) where T : Control { - if ((App.Current?.TryGetResource(name, App.Current.ActualThemeVariant, out var value) ?? false) && value is IBrush brush) - return brush; - return defaultBrush; + control[!prop] = new DynamicResourceExtension(resourceKey); + return control; } - public static Task ShowDialogAsync(this DialogWindow dialogWindow, Window? owner = null) - => dialogWindow.ShowDialog(owner ?? App.MainWindow); + public static Task ShowDialogAsync(this Dialogs.DialogWindow dialogWindow, Window? owner = null) + => ((owner ?? App.MainWindow) is Window window) + ? dialogWindow.ShowDialog(window) + : Task.FromResult(DialogResult.None); + + public static Task ShowDialogAsync(this Dialogs.Login.WebLoginDialog dialogWindow, Window? owner = null) + => ((owner ?? App.MainWindow) is Window window) + ? dialogWindow.ShowDialog(window) + : Task.FromResult(DialogResult.None); public static Window? GetParentWindow(this Control control) => control.GetVisualRoot() as Window; diff --git a/Source/LibationAvalonia/Controls/GroupBox.axaml b/Source/LibationAvalonia/Controls/GroupBox.axaml index da3b0e32..cce62b01 100644 --- a/Source/LibationAvalonia/Controls/GroupBox.axaml +++ b/Source/LibationAvalonia/Controls/GroupBox.axaml @@ -8,7 +8,7 @@ @@ -72,12 +72,6 @@ IsVisible="{CompiledBinding IsError}" Fill="{DynamicResource CancelRed}" Data="{StaticResource BookErrorIcon}" /> - - diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml b/Source/LibationAvalonia/Views/MainWindow.axaml index 49f01599..9542b089 100644 --- a/Source/LibationAvalonia/Views/MainWindow.axaml +++ b/Source/LibationAvalonia/Views/MainWindow.axaml @@ -160,7 +160,7 @@ - + @@ -221,6 +221,7 @@ Name="productsDisplay" DataContext="{CompiledBinding ProductsDisplay}" LiberateClicked="ProductsDisplay_LiberateClicked" + TagsButtonClicked="ProductsDisplay_TagsButtonClicked" LiberateSeriesClicked="ProductsDisplay_LiberateSeriesClicked" ConvertToMp3Clicked="ProductsDisplay_ConvertToMp3Clicked" /> diff --git a/Source/LibationAvalonia/Views/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow.axaml.cs index 61eb14f2..1f47c5ef 100644 --- a/Source/LibationAvalonia/Views/MainWindow.axaml.cs +++ b/Source/LibationAvalonia/Views/MainWindow.axaml.cs @@ -4,6 +4,7 @@ using Avalonia.ReactiveUI; using Avalonia.Threading; using DataLayer; using FileManager; +using LibationAvalonia.Dialogs; using LibationAvalonia.ViewModels; using LibationFileManager; using LibationUiBase.GridView; @@ -137,6 +138,18 @@ namespace LibationAvalonia.Views public void ProductsDisplay_LiberateSeriesClicked(object _, ISeriesEntry series) => ViewModel.LiberateSeriesClicked(series); public void ProductsDisplay_ConvertToMp3Clicked(object _, LibraryBook libraryBook) => ViewModel.ConvertToMp3Clicked(libraryBook); + BookDetailsDialog bookDetailsForm; + public void ProductsDisplay_TagsButtonClicked(object _, LibraryBook libraryBook) + { + if (bookDetailsForm is null || !bookDetailsForm.IsVisible) + { + bookDetailsForm = new BookDetailsDialog(libraryBook); + bookDetailsForm.Show(this); + } + else + bookDetailsForm.LibraryBook = libraryBook; + } + public async void filterSearchTb_KeyPress(object _, KeyEventArgs e) { if (e.Key == Key.Return) diff --git a/Source/LibationAvalonia/Views/ProcessBookControl.axaml b/Source/LibationAvalonia/Views/ProcessBookControl.axaml index fc227280..864ce3ee 100644 --- a/Source/LibationAvalonia/Views/ProcessBookControl.axaml +++ b/Source/LibationAvalonia/Views/ProcessBookControl.axaml @@ -3,9 +3,10 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:LibationAvalonia.ViewModels" + xmlns:views="clr-namespace:LibationAvalonia.Views" x:DataType="vm:ProcessBookViewModel" mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="87" MaxHeight="87" MinHeight="87" MinWidth="300" - x:Class="LibationAvalonia.Views.ProcessBookControl" Background="{CompiledBinding BackgroundColor}"> + x:Class="LibationAvalonia.Views.ProcessBookControl"> @@ -68,7 +81,7 @@ diff --git a/Source/LibationAvalonia/Views/ProcessBookControl.axaml.cs b/Source/LibationAvalonia/Views/ProcessBookControl.axaml.cs index f7ccc4d0..b79ea913 100644 --- a/Source/LibationAvalonia/Views/ProcessBookControl.axaml.cs +++ b/Source/LibationAvalonia/Views/ProcessBookControl.axaml.cs @@ -1,4 +1,5 @@ using ApplicationServices; +using Avalonia; using Avalonia.Controls; using DataLayer; using LibationAvalonia.ViewModels; @@ -12,6 +13,16 @@ namespace LibationAvalonia.Views { public static event QueueItemPositionButtonClicked PositionButtonClicked; public static event QueueItemCancelButtonClicked CancelButtonClicked; + + public static readonly StyledProperty ProcessBookStatusProperty = + AvaloniaProperty.Register(nameof(ProcessBookStatus), enableDataValidation: true); + + public ProcessBookStatus ProcessBookStatus + { + get => GetValue(ProcessBookStatusProperty); + set => SetValue(ProcessBookStatusProperty, value); + } + public ProcessBookControl() { InitializeComponent(); diff --git a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml index 8c3f3815..9418f2c2 100644 --- a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml +++ b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml @@ -7,6 +7,7 @@ xmlns:viewModels="clr-namespace:LibationAvalonia.ViewModels" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="650" + Background="{DynamicResource SystemRegionColor}" x:Class="LibationAvalonia.Views.ProcessQueueControl"> @@ -35,7 +36,7 @@ Process Queue - + Queue Log - + diff --git a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs index 0b7761d8..de001556 100644 --- a/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs +++ b/Source/LibationAvalonia/Views/ProcessQueueControl.axaml.cs @@ -9,13 +9,15 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading.Tasks; +#nullable enable namespace LibationAvalonia.Views { public partial class ProcessQueueControl : UserControl { - private TrackedQueue Queue => _viewModel.Queue; - private ProcessQueueViewModel _viewModel => DataContext as ProcessQueueViewModel; + private TrackedQueue? Queue => _viewModel?.Queue; + private ProcessQueueViewModel? _viewModel => DataContext as ProcessQueueViewModel; public ProcessQueueControl() { @@ -25,6 +27,7 @@ namespace LibationAvalonia.Views ProcessBookControl.CancelButtonClicked += ProcessBookControl2_CancelButtonClicked; #region Design Mode Testing +#if DEBUG if (Design.IsDesignMode) { var vm = new ProcessQueueViewModel(); @@ -85,6 +88,7 @@ namespace LibationAvalonia.Views vm.Queue.MoveNext(); return; } +#endif #endregion } @@ -98,53 +102,59 @@ namespace LibationAvalonia.Views private async void ProcessBookControl2_CancelButtonClicked(ProcessBookViewModel item) { if (item is not null) + { await item.CancelAsync(); - Queue.RemoveQueued(item); + Queue?.RemoveQueued(item); + } } private void ProcessBookControl2_ButtonClicked(ProcessBookViewModel item, QueuePosition queueButton) { - Queue.MoveQueuePosition(item, queueButton); + Queue?.MoveQueuePosition(item, queueButton); } public async void CancelAllBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) { - Queue.ClearQueue(); - if (Queue.Current is not null) + Queue?.ClearQueue(); + if (Queue?.Current is not null) await Queue.Current.CancelAsync(); } public void ClearFinishedBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) { - Queue.ClearCompleted(); + Queue?.ClearCompleted(); - if (!_viewModel.Running) + if (_viewModel?.Running is false) _viewModel.RunningTime = string.Empty; } public void ClearLogBtn_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) { - _viewModel.LogEntries.Clear(); + _viewModel?.LogEntries.Clear(); } private async 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}")); - await App.MainWindow.Clipboard.SetTextAsync(logText); + if (_viewModel is ProcessQueueViewModel vm) + { + string logText = string.Join("\r\n", vm.LogEntries.Select(r => $"{r.LogDate.ToShortDateString()} {r.LogDate.ToShortTimeString()}\t{r.LogMessage}")); + if (App.MainWindow?.Clipboard?.SetTextAsync(logText) is Task setter) + await setter; + } } private async void cancelAllBtn_Click(object sender, EventArgs e) { - Queue.ClearQueue(); - if (Queue.Current is not null) + Queue?.ClearQueue(); + if (Queue?.Current is not null) await Queue.Current.CancelAsync(); } private void btnClearFinished_Click(object sender, EventArgs e) { - Queue.ClearCompleted(); + Queue?.ClearCompleted(); - if (!_viewModel.Running) + if (_viewModel?.Running is false) _viewModel.RunningTime = string.Empty; } @@ -155,7 +165,7 @@ namespace LibationAvalonia.Views { public static readonly DecimalConverter Instance = new(); - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is string sourceText && targetType.IsAssignableTo(typeof(decimal?))) { @@ -172,7 +182,7 @@ namespace LibationAvalonia.Views return 0; } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is decimal val) { @@ -184,7 +194,7 @@ namespace LibationAvalonia.Views : val.ToString("F2") ) + " MB/s"; } - return value.ToString(); + return value?.ToString(); } } } diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml index fd90a1c1..90517420 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml @@ -18,6 +18,7 @@ ItemsSource="{Binding GridEntries}" CanUserSortColumns="True" BorderThickness="3" CanUserResizeColumns="True" + LoadingRow="ProductsDisplay_LoadingRow" CanUserReorderColumns="True"> @@ -93,7 +94,7 @@ - + @@ -103,7 +104,7 @@ - + @@ -113,7 +114,7 @@ - + @@ -123,7 +124,7 @@ - + @@ -133,7 +134,7 @@ - + @@ -143,7 +144,7 @@ - + @@ -153,7 +154,7 @@ - + @@ -163,7 +164,7 @@ - + @@ -177,14 +178,13 @@ MinWidth="10" Width="{Binding ProductRatingWidth, Mode=TwoWay}" SortMemberPath="ProductRating" CanUserSort="True" OpacityBinding="{CompiledBinding Liberate.Opacity}" - BackgroundBinding="{CompiledBinding Liberate.BackgroundBrush}" ClipboardContentBinding="{CompiledBinding ProductRating}" Binding="{CompiledBinding ProductRating}" /> - + @@ -198,14 +198,13 @@ MinWidth="10" Width="{Binding MyRatingWidth, Mode=TwoWay}" SortMemberPath="MyRating" CanUserSort="True" OpacityBinding="{CompiledBinding Liberate.Opacity}" - BackgroundBinding="{CompiledBinding Liberate.BackgroundBrush}" ClipboardContentBinding="{CompiledBinding MyRating}" Binding="{CompiledBinding MyRating, Mode=TwoWay}" /> - + @@ -215,7 +214,7 @@ - + diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs index 6f6948ab..fd18d16b 100644 --- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs +++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs @@ -1,6 +1,8 @@ using ApplicationServices; using Avalonia; using Avalonia.Controls; +using Avalonia.Input.Platform; +using Avalonia.Media; using Avalonia.Platform.Storage; using Avalonia.Styling; using DataLayer; @@ -17,16 +19,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +#nullable enable namespace LibationAvalonia.Views { public partial class ProductsDisplay : UserControl { - public event EventHandler LiberateClicked; - public event EventHandler LiberateSeriesClicked; - public event EventHandler ConvertToMp3Clicked; + public event EventHandler? LiberateClicked; + public event EventHandler? LiberateSeriesClicked; + public event EventHandler? ConvertToMp3Clicked; + public event EventHandler? TagsButtonClicked; - private ProductsDisplayViewModel _viewModel => DataContext as ProductsDisplayViewModel; - ImageDisplayDialog imageDisplayDialog; + private ProductsDisplayViewModel? _viewModel => DataContext as ProductsDisplayViewModel; + ImageDisplayDialog? imageDisplayDialog; public ProductsDisplay() { @@ -52,6 +56,8 @@ namespace LibationAvalonia.Views Configuration.Instance.PropertyChanged += Configuration_GridScaleChanged; Configuration.Instance.PropertyChanged += Configuration_FontChanged; + #region Design Mode Testing +#if DEBUG if (Design.IsDesignMode) { using var context = DbContexts.GetContext(); @@ -80,6 +86,8 @@ namespace LibationAvalonia.Views setFontScale(1); return; } +#endif + #endregion setGridScale(Configuration.Instance.GridScaleFactor); setFontScale(Configuration.Instance.GridFontScaleFactor); @@ -91,6 +99,14 @@ namespace LibationAvalonia.Views } } + private void ProductsDisplay_LoadingRow(object sender, DataGridRowEventArgs e) + { + if (e.Row.DataContext is LibraryBookEntry entry && entry.Liberate.IsEpisode) + e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SeriesEntryGridBackgroundBrush"); + else + e.Row.DynamicResource(DataGridRow.BackgroundProperty, "SystemRegionColor"); + } + private void RemoveColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) { if (sender is DataGridColumn col && e.Property == DataGridColumn.IsVisibleProperty) @@ -105,13 +121,15 @@ namespace LibationAvalonia.Views [PropertyChangeFilter(nameof(Configuration.GridScaleFactor))] private void Configuration_GridScaleChanged(object sender, Dinah.Core.PropertyChangedEventArgsEx e) { - setGridScale((float)e.NewValue); + if (e.NewValue is float value) + setGridScale(value); } [PropertyChangeFilter(nameof(Configuration.GridFontScaleFactor))] private void Configuration_FontChanged(object sender, Dinah.Core.PropertyChangedEventArgsEx e) { - setFontScale((float)e.NewValue); + if (e.NewValue is float value) + setFontScale(value); } private readonly Style rowHeightStyle; @@ -171,17 +189,18 @@ namespace LibationAvalonia.Views #region Cell Context Menu - public void ProductsGrid_CellContextMenuStripNeeded(object sender, DataGridCellContextMenuStripNeededEventArgs args) + public void ProductsGrid_CellContextMenuStripNeeded(object? sender, DataGridCellContextMenuStripNeededEventArgs args) { var entry = args.GridEntry; var ctx = new GridContextMenu(entry, '_'); - if (args.Column.SortMemberPath is not "Liberate" and not "Cover") + if (args.Column.SortMemberPath is not "Liberate" and not "Cover" + && App.MainWindow?.Clipboard is IClipboard clipboard) { args.ContextMenuItems.Add(new MenuItem { Header = ctx.CopyCellText, - Command = ReactiveCommand.CreateFromTask(() => App.MainWindow.Clipboard.SetTextAsync(args.CellClipboardContents)) + Command = ReactiveCommand.CreateFromTask(() => clipboard?.SetTextAsync(args.CellClipboardContents) ?? Task.CompletedTask) }); args.ContextMenuItems.Add(new Separator()); } @@ -240,13 +259,14 @@ namespace LibationAvalonia.Views { try { - var window = this.GetParentWindow(); + if (this.GetParentWindow() is not Window window) + return; var openFileDialogOptions = new FilePickerOpenOptions { Title = ctx.LocateFileDialogTitle, AllowMultiple = false, - SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books.PathWithoutPrefix), + SuggestedStartLocation = await window.StorageProvider.TryGetFolderFromPathAsync(Configuration.Instance.Books?.PathWithoutPrefix!), FileTypeFilter = new FilePickerFileType[] { new("All files (*.*)") { Patterns = new[] { "*" } }, @@ -303,7 +323,7 @@ namespace LibationAvalonia.Views { var template = ctx.CreateTemplateEditor(libraryBook, existingTemplate); var form = new EditTemplateDialog(template); - if (await form.ShowDialog(this.GetParentWindow()) == DialogResult.OK) + if (this.GetParentWindow() is Window window && await form.ShowDialog(window) == DialogResult.OK) { setNewTemplate(template.EditingTemplate.TemplateText); } @@ -340,12 +360,12 @@ namespace LibationAvalonia.Views #region View Bookmarks/Clips - if (!entry.Liberate.IsSeries) + if (!entry.Liberate.IsSeries && VisualRoot is Window window) { args.ContextMenuItems.Add(new MenuItem { Header = ctx.ViewBookmarksText, - Command = ReactiveCommand.CreateFromTask(() => new BookRecordsDialog(entry.LibraryBook).ShowDialog(VisualRoot as Window)) + Command = ReactiveCommand.CreateFromTask(() => new BookRecordsDialog(entry.LibraryBook).ShowDialog(window)) }); } @@ -389,6 +409,9 @@ namespace LibationAvalonia.Views var HeaderCell_PI = typeof(DataGridColumn).GetProperty("HeaderCell", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (HeaderCell_PI is null) + return; + foreach (var column in productsGrid.Columns) { var itemName = column.SortMemberPath; @@ -406,8 +429,9 @@ namespace LibationAvalonia.Views } ); - var headercell = HeaderCell_PI.GetValue(column) as DataGridColumnHeader; - headercell.ContextMenu = contextMenu; + var headerCell = HeaderCell_PI.GetValue(column) as DataGridColumnHeader; + if (headerCell is not null) + headerCell.ContextMenu = contextMenu; column.IsVisible = gridColumnsVisibilities.GetValueOrDefault(itemName, true); } @@ -425,30 +449,30 @@ namespace LibationAvalonia.Views } } - private void ContextMenu_ContextMenuOpening(object sender, System.ComponentModel.CancelEventArgs e) + private void ContextMenu_ContextMenuOpening(object? sender, System.ComponentModel.CancelEventArgs e) { - var contextMenu = sender as ContextMenu; + if (sender is not ContextMenu contextMenu) + return; foreach (var mi in contextMenu.Items.OfType()) { - if (mi.Tag is DataGridColumn column) + if (mi.Tag is DataGridColumn column && mi.Icon is CheckBox cbox) { - var cbox = mi.Icon as CheckBox; cbox.IsChecked = column.IsVisible; } } } - private void ContextMenu_MenuClosed(object sender, Avalonia.Interactivity.RoutedEventArgs e) + private void ContextMenu_MenuClosed(object? sender, Avalonia.Interactivity.RoutedEventArgs e) { - var contextMenu = sender as ContextMenu; + if (sender is not ContextMenu contextMenu) + return; var config = Configuration.Instance; var dictionary = config.GridColumnsVisibilities; foreach (var mi in contextMenu.Items.OfType()) { - if (mi.Tag is DataGridColumn column) + if (mi.Tag is DataGridColumn column && mi.Icon is CheckBox cbox) { - var cbox = mi.Icon as CheckBox; column.IsVisible = cbox.IsChecked == true; dictionary[column.SortMemberPath] = cbox.IsChecked == true; } @@ -463,7 +487,7 @@ namespace LibationAvalonia.Views config.GridColumnsVisibilities = dictionary; } - private void ProductsGrid_ColumnDisplayIndexChanged(object sender, DataGridColumnEventArgs e) + private void ProductsGrid_ColumnDisplayIndexChanged(object? sender, DataGridColumnEventArgs e) { var config = Configuration.Instance; @@ -478,9 +502,10 @@ namespace LibationAvalonia.Views public async void LiberateButton_Click(object sender, EventArgs e) { - var button = sender as LiberateStatusButton; + if (sender is not LiberateStatusButton button) + return; - if (button.DataContext is ISeriesEntry sEntry) + if (button.DataContext is ISeriesEntry sEntry && _viewModel is not null) { await _viewModel.ToggleSeriesExpanded(sEntry); @@ -518,7 +543,7 @@ namespace LibationAvalonia.Views var picDef = new PictureDefinition(gEntry.LibraryBook.Book.PictureLarge ?? gEntry.LibraryBook.Book.PictureId, PictureSize.Native); - void PictureCached(object sender, PictureCachedEventArgs e) + void PictureCached(object? sender, PictureCachedEventArgs e) { if (e.Definition.PictureId == picDef.PictureId) imageDisplayDialog.SetCoverBytes(e.Picture); @@ -558,7 +583,7 @@ namespace LibationAvalonia.Views DescriptionText = gEntry.Description, }; - void CloseWindow(object o, DataGridRowEventArgs e) + void CloseWindow(object? o, DataGridRowEventArgs e) { displayWindow.Close(); } @@ -572,21 +597,13 @@ namespace LibationAvalonia.Views } } - BookDetailsDialog bookDetailsForm; - public void OnTagsButtonClick(object sender, Avalonia.Interactivity.RoutedEventArgs args) { var button = args.Source as Button; - if (button.DataContext is ILibraryBookEntry lbEntry && VisualRoot is Window window) + if (button?.DataContext is ILibraryBookEntry lbEntry) { - if (bookDetailsForm is null || !bookDetailsForm.IsVisible) - { - bookDetailsForm = new BookDetailsDialog(lbEntry.LibraryBook); - bookDetailsForm.Show(window); - } - else - bookDetailsForm.LibraryBook = lbEntry.LibraryBook; + TagsButtonClicked?.Invoke(this, lbEntry.LibraryBook); } } diff --git a/Source/LibationAvalonia/Views/SeriesViewDialog.axaml b/Source/LibationAvalonia/Views/SeriesViewDialog.axaml index 58ffdd26..e55a6f12 100644 --- a/Source/LibationAvalonia/Views/SeriesViewDialog.axaml +++ b/Source/LibationAvalonia/Views/SeriesViewDialog.axaml @@ -4,7 +4,6 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="LibationAvalonia.Views.SeriesViewDialog" - Icon="/Assets/libation.ico" Title="View All Items in Series"> !IsSeries && Book.UserDefinedItem.Tags.ContainsInsensitive("hidden") ? 0.4 : 1; - public abstract object BackgroundBrush { get; } public object ButtonImage => GetLiberateIcon(); public string ToolTip => GetTooltip(); private Book Book { get; } diff --git a/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs b/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs index 0a24361a..48ab8901 100644 --- a/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs +++ b/Source/LibationWinForms/GridView/WinFormsEntryStatus.cs @@ -7,7 +7,7 @@ namespace LibationWinForms.GridView public class WinFormsEntryStatus : EntryStatus, IEntryStatus { private static readonly Color SERIES_BG_COLOR = Color.FromArgb(230, 255, 230); - public override object BackgroundBrush => IsEpisode ? SERIES_BG_COLOR : SystemColors.ControlLightLight; + public Color BackgroundBrush => IsEpisode ? SERIES_BG_COLOR : SystemColors.ControlLightLight; private WinFormsEntryStatus(LibraryBook libraryBook) : base(libraryBook) { } public static EntryStatus Create(LibraryBook libraryBook) => new WinFormsEntryStatus(libraryBook); diff --git a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs index 3254f5d0..9f840338 100644 --- a/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs +++ b/Source/LibationWinForms/ProcessQueue/ProcessBookControl.cs @@ -65,9 +65,9 @@ namespace LibationWinForms.ProcessQueue ProcessBookResult.Success => ("Finished", ProcessBookStatus.Completed), ProcessBookResult.Cancelled => ("Cancelled", ProcessBookStatus.Cancelled), ProcessBookResult.FailedRetry => ("Error, will retry later", ProcessBookStatus.Failed), - ProcessBookResult.FailedSkip => ("Error, Skippping", ProcessBookStatus.Failed), + ProcessBookResult.FailedSkip => ("Error, Skipping", ProcessBookStatus.Failed), ProcessBookResult.FailedAbort => ("Error, Abort", ProcessBookStatus.Failed), - ProcessBookResult.ValidationFail => ("Validion fail", ProcessBookStatus.Failed), + ProcessBookResult.ValidationFail => ("Validation fail", ProcessBookStatus.Failed), ProcessBookResult.LicenseDenied => ("License Denied", ProcessBookStatus.Failed), ProcessBookResult.LicenseDeniedPossibleOutage => ("Possible Service Interruption", ProcessBookStatus.Failed), _ => ("UNKNOWN", ProcessBookStatus.Failed), diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow-PSD.zip b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow-PSD.zip new file mode 100644 index 00000000..c2efd3c0 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow-PSD.zip differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow.ico b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow.ico index d3e00443..88dff50b 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow.ico and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow.ico differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_1024.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_1024.png new file mode 100644 index 00000000..b3459e93 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_1024.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_128.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_128.png index 190ea6b1..3c8a25be 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_128.png and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_128.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_16.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_16.png index 05e40bec..138f0b66 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_16.png and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_16.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_20.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_20.png new file mode 100644 index 00000000..1b21ed83 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_20.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_24.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_24.png new file mode 100644 index 00000000..55efeba0 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_24.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_256.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_256.png index 2927595f..90c85598 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_256.png and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_256.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_32.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_32.png index 994a99d8..7dda9bf7 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_32.png and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_32.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_40.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_40.png new file mode 100644 index 00000000..0f0e12c8 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_40.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_48.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_48.png new file mode 100644 index 00000000..fc0d3e76 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_48.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_512.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_512.png index ce0d7175..9eab0ec3 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_512.png and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_512.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_64.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_64.png index b62d0b02..5a58e95f 100644 Binary files a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_64.png and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_64.png differ diff --git a/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_96.png b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_96.png new file mode 100644 index 00000000..13723934 Binary files /dev/null and b/Source/LibationWinForms/Resources/Libation icon/glass-with-glow_96.png differ diff --git a/Source/LibationWinForms/Resources/libation.ico b/Source/LibationWinForms/Resources/libation.ico index d3e00443..88dff50b 100644 Binary files a/Source/LibationWinForms/Resources/libation.ico and b/Source/LibationWinForms/Resources/libation.ico differ diff --git a/Source/LibationWinForms/libation.ico b/Source/LibationWinForms/libation.ico index d3e00443..88dff50b 100644 Binary files a/Source/LibationWinForms/libation.ico and b/Source/LibationWinForms/libation.ico differ diff --git a/Source/LoadByOS/LinuxConfigApp/libation_glass.svg b/Source/LoadByOS/LinuxConfigApp/libation_glass.svg index 7ecd7089..bc632ab1 100644 --- a/Source/LoadByOS/LinuxConfigApp/libation_glass.svg +++ b/Source/LoadByOS/LinuxConfigApp/libation_glass.svg @@ -1,34 +1,36 @@ - + - - +