diff --git a/.github/workflows/build-deb.yml b/.github/workflows/build-deb.yml
new file mode 100644
index 00000000..e1e3db3d
--- /dev/null
+++ b/.github/workflows/build-deb.yml
@@ -0,0 +1,39 @@
+# build-deb.yml
+# Reusable workflow that builds the Linux Debian package.
+---
+name: build_deb
+
+on:
+ workflow_call:
+ inputs:
+ version:
+ type: string
+ description: 'Version number'
+ required: true
+
+env:
+ FILE_NAME: "Libation.${{ inputs.version }}-linux-chardonnay"
+
+jobs:
+ build_deb:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Download Artifact
+ uses: actions/download-artifact@master
+ with:
+ name: "${{ env.FILE_NAME }}.tar.gz"
+
+ - name: Build .deb
+ id: deb
+ run: |
+ chmod +x ./.github/workflows/scripts/targz2deb.sh
+ ./.github/workflows/scripts/targz2deb.sh "${{ env.FILE_NAME }}.tar.gz" ${{ inputs.version }}
+
+ - name: Publish .deb
+ uses: actions/upload-artifact@v3
+ with:
+ name: ${{ env.FILE_NAME }}.deb
+ path: ${{ env.FILE_NAME }}.deb
+ if-no-files-found: error
diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml
index 3c0d1401..b9b7cf37 100644
--- a/.github/workflows/build-linux.yml
+++ b/.github/workflows/build-linux.yml
@@ -15,6 +15,10 @@ on:
description: 'Skip running unit tests'
required: false
default: true
+ outputs:
+ version:
+ description: "The Libation version number"
+ value: ${{ jobs.build.outputs.version }}
env:
DOTNET_CONFIGURATION: 'Release'
@@ -23,6 +27,8 @@ env:
jobs:
build:
runs-on: ubuntu-latest
+ outputs:
+ version: ${{ steps.get_version.outputs.version }}
strategy:
matrix:
os: [Linux, MacOS]
@@ -66,6 +72,8 @@ jobs:
id: zip
working-directory: ./Source/bin/Publish/${{ matrix.os }}-${{ matrix.release_name }}
run: |
+ delfiles=("libmp3lame.x86.dll" "libmp3lame.x64.dll" "ffmpegaac.x86.dll" "ffmpegaac.x64.dll" "ZipExtractor.exe")
+ for n in "${delfiles[@]}"; do rm "$n"; done
osbuild="$(echo '${{ matrix.os }}' | tr '[:upper:]' '[:lower:]')"
artifact="Libation.${{ steps.get_version.outputs.version }}-${osbuild}-${{ matrix.release_name }}"
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
index 8739bb6f..cfac74ec 100644
--- a/.github/workflows/build-windows.yml
+++ b/.github/workflows/build-windows.yml
@@ -15,6 +15,10 @@ on:
description: 'Skip running unit tests'
required: false
default: true
+ outputs:
+ version:
+ description: "The Libation version number"
+ value: ${{ jobs.build.outputs.version }}
env:
DOTNET_CONFIGURATION: 'Release'
@@ -23,6 +27,8 @@ env:
jobs:
build:
runs-on: windows-latest
+ outputs:
+ version: ${{ steps.get_version.outputs.version }}
strategy:
matrix:
os: [Windows]
@@ -48,8 +54,7 @@ jobs:
if ("${{ inputs.version_override }}".length -gt 0) {
$version = "${{ inputs.version_override }}"
} else {
- [xml]$appScaffolding = Get-Content -Path ./Source/AppScaffolding/AppScaffolding.csproj
- $version = $appScaffolding.Project.PropertyGroup.Version
+ $version = (Select-Xml -Path "./Source/AppScaffolding/AppScaffolding.csproj" -XPath "/Project/PropertyGroup/Version").Node.InnerXML.Trim()
}
"version=$version" >> $env:GITHUB_OUTPUT
@@ -69,10 +74,13 @@ jobs:
- name: Zip artifact
id: zip
working-directory: ./Source/bin/Publish
- run: |
+ run: |
+ $dir = "${{ matrix.os }}-${{ matrix.release_name }}\"
+ $delfiles = @("libmp3lame.so", "ffmpegaac.so", "glass-with-glow_256.svg", "Libation.desktop")
+ foreach ($file in $delfiles){ if (test-path $dir$file){ Remove-Item $dir$file } }
$artifact="${{ matrix.prefix }}Libation.${{ steps.get_version.outputs.version }}-" + "${{ matrix.os }}".ToLower() + "-${{ matrix.release_name }}"
"artifact=$artifact" >> $env:GITHUB_OUTPUT
- Compress-Archive -Path "${{ matrix.os }}-${{ matrix.release_name }}\*" -DestinationPath "$artifact.zip"
+ Compress-Archive -Path "${dir}*" -DestinationPath "$artifact.zip"
- name: Publish artifact
uses: actions/upload-artifact@v3
@@ -80,3 +88,4 @@ jobs:
name: ${{ steps.zip.outputs.artifact }}.zip
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
if-no-files-found: error
+
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7b62f1b1..47e89f80 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -28,3 +28,10 @@ jobs:
with:
version_override: ${{ inputs.version_override }}
run_unit_tests: ${{ inputs.run_unit_tests }}
+
+ linux_deb:
+ needs: [linux]
+ uses: ./.github/workflows/build-deb.yml
+ with:
+ version: ${{ needs.linux.outputs.version }}
+
diff --git a/Source/targz2deb.sh b/.github/workflows/scripts/targz2deb.sh
similarity index 99%
rename from Source/targz2deb.sh
rename to .github/workflows/scripts/targz2deb.sh
index 67c675ee..4143aef8 100644
--- a/Source/targz2deb.sh
+++ b/.github/workflows/scripts/targz2deb.sh
@@ -116,7 +116,6 @@ Version: $VERSION
Architecture: all
Essential: no
Priority: optional
-Depends: ffmpeg
Maintainer: github.com/rmcrackan
Description: liberate your audiobooks
" >> "$FOLDER_DEBIAN/control"
diff --git a/Source/AaxDecrypter/AaxDecrypter.csproj b/Source/AaxDecrypter/AaxDecrypter.csproj
index 5724667b..4236ee60 100644
--- a/Source/AaxDecrypter/AaxDecrypter.csproj
+++ b/Source/AaxDecrypter/AaxDecrypter.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/Source/AaxDecrypter/AaxcDownloadConvertBase.cs b/Source/AaxDecrypter/AaxcDownloadConvertBase.cs
index dc4eeb66..c42fc4d4 100644
--- a/Source/AaxDecrypter/AaxcDownloadConvertBase.cs
+++ b/Source/AaxDecrypter/AaxcDownloadConvertBase.cs
@@ -32,7 +32,7 @@ namespace AaxDecrypter
AaxFile.AppleTags.Album = AaxFile.AppleTags.Album?.Replace(" (Unabridged)", "");
}
- if (DownloadOptions.FixupFile)
+ if (DownloadOptions.FixupFile && !string.IsNullOrWhiteSpace(AaxFile.AppleTags.Narrator))
AaxFile.AppleTags.AppleListBox.EditOrAddTag("TCOM", AaxFile.AppleTags.Narrator);
//Finishing configuring lame encoder.
diff --git a/Source/DataLayer/EntityExtensions.cs b/Source/DataLayer/EntityExtensions.cs
index ef18a232..acf0b866 100644
--- a/Source/DataLayer/EntityExtensions.cs
+++ b/Source/DataLayer/EntityExtensions.cs
@@ -93,10 +93,12 @@ namespace DataLayer
var starString = new string(STAR, fullStars);
- if (score - fullStars >= 0.25f)
- starString += HALF;
+ if (score - fullStars >= 0.75f)
+ starString += STAR;
+ else if (score - fullStars >= 0.25f)
+ starString += HALF;
- return starString;
+ return starString;
}
}
}
diff --git a/Source/DtoImporterService/BookImporter.cs b/Source/DtoImporterService/BookImporter.cs
index 6b884673..d9de490c 100644
--- a/Source/DtoImporterService/BookImporter.cs
+++ b/Source/DtoImporterService/BookImporter.cs
@@ -174,7 +174,10 @@ namespace DtoImporterService
if (item.PictureLarge is not null)
book.PictureLarge = item.PictureLarge;
- book.UpdateProductRating(item.Product_OverallStars, item.Product_PerformanceStars, item.Product_StoryStars);
+ book.UpdateProductRating(
+ (float)(item.Rating?.OverallDistribution?.AverageRating ?? 0),
+ (float)(item.Rating?.PerformanceDistribution?.AverageRating ?? 0),
+ (float)(item.Rating?.StoryDistribution?.AverageRating ?? 0));
// important to update user-specific info. this will have changed if user has rated/reviewed the book since last library import
book.UserDefinedItem.UpdateRating(item.MyUserRating_Overall, item.MyUserRating_Performance, item.MyUserRating_Story);
diff --git a/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs b/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs
index 3fefa38c..b563883e 100644
--- a/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs
+++ b/Source/LibationAvalonia/Controls/DataGridMyRatingColumn.cs
@@ -2,14 +2,24 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using DataLayer;
-using LibationAvalonia.ViewModels;
using ReactiveUI;
using System;
namespace LibationAvalonia.Controls
{
+ public class StarStringConverter : Avalonia.Data.Converters.IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ => value is Rating rating ? rating.ToStarString() : string.Empty;
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ => throw new NotImplementedException();
+ }
+
public class DataGridMyRatingColumn : DataGridBoundColumn
{
+ [Avalonia.Data.AssignBinding]
+ public Avalonia.Data.IBinding BackgroundBinding { get; set; }
private static Rating DefaultRating => new Rating(0, 0, 0);
public DataGridMyRatingColumn()
{
@@ -24,29 +34,20 @@ namespace LibationAvalonia.Controls
IsEditingMode = false
};
- ToolTip.SetTip(myRatingElement, "Click to change ratings");
cell?.AttachContextMenu();
+ if (!IsReadOnly)
+ ToolTip.SetTip(myRatingElement, "Click to change ratings");
+
if (Binding != null)
{
myRatingElement.Bind(BindingTarget, Binding);
}
-
- void setControlBackground(object dataContext)
+ if (BackgroundBinding != null)
{
- if (dataContext is GridEntry ge)
- myRatingElement.Background = ge.BackgroundBrush;
+ myRatingElement.Bind(MyRatingCellEditor.BackgroundProperty, BackgroundBinding);
}
- setControlBackground(cell?.DataContext);
-
- var subscriber =
- cell
- ?.ObservableForProperty(g => g.DataContext)
- ?.Subscribe(ctx => setControlBackground(ctx?.Value));
-
- myRatingElement.DetachedFromVisualTree += (_, _) => subscriber?.Dispose();
-
return myRatingElement;
}
@@ -57,6 +58,10 @@ namespace LibationAvalonia.Controls
Name = "CellMyRatingEditor",
IsEditingMode = true
};
+ if (BackgroundBinding != null)
+ {
+ myRatingElement.Bind(MyRatingCellEditor.BackgroundProperty, BackgroundBinding);
+ }
return myRatingElement;
}
diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml
index aa2e50f6..c477ba16 100644
--- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml
+++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml
@@ -17,7 +17,7 @@
-
+
diff --git a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs
index 3c7e889f..c5100f14 100644
--- a/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs
+++ b/Source/LibationAvalonia/Controls/MyRatingCellEditor.axaml.cs
@@ -1,6 +1,8 @@
using Avalonia;
using Avalonia.Controls;
using DataLayer;
+using ReactiveUI;
+using System;
using System.Linq;
namespace LibationAvalonia.Controls
@@ -9,6 +11,7 @@ namespace LibationAvalonia.Controls
{
private const string SOLID_STAR = "★";
private const string HOLLOW_STAR = "☆";
+ private const string HALF_STAR = "½";
public static readonly StyledProperty RatingProperty =
AvaloniaProperty.Register(nameof(Rating));
@@ -19,39 +22,41 @@ namespace LibationAvalonia.Controls
public MyRatingCellEditor()
{
InitializeComponent();
+
+ var subscriber = this.ObservableForProperty(p => p.Rating).Subscribe(o => DisplayStarRating(o.Value ?? new Rating(0, 0, 0)));
+ Unloaded += (_, _) => subscriber.Dispose();
+
if (Design.IsDesignMode)
Rating = new Rating(5, 4, 3);
}
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ private void DisplayStarRating(Rating rating)
{
- if (change.Property.Name == nameof(Rating) && Rating is not null)
- {
- var blankValue = IsEditingMode ? HOLLOW_STAR : string.Empty;
+ var blankValue = IsEditingMode ? HOLLOW_STAR : string.Empty;
- int rating = 0;
- foreach (TextBlock star in panelOverall.Children)
- star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : blankValue;
+ string getStar(float score, int starIndex)
+ => Math.Floor(score) > starIndex ? SOLID_STAR
+ : score < starIndex ? blankValue
+ : score - starIndex < 0.25 ? blankValue
+ : score - starIndex > 0.75 ? SOLID_STAR
+ : HALF_STAR;
- rating = 0;
- foreach (TextBlock star in panelPerform.Children)
- star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : blankValue;
+ int starIndex = 0;
+ foreach (TextBlock star in panelOverall.Children)
+ star.Tag = star.Text = getStar(rating.OverallRating, starIndex++);
- rating = 0;
- foreach (TextBlock star in panelStory.Children)
- star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue;
+ starIndex = 0;
+ foreach (TextBlock star in panelPerform.Children)
+ star.Tag = star.Text = getStar(rating.PerformanceRating, starIndex++);
- SetVisible();
- }
- base.OnPropertyChanged(change);
- }
+ starIndex = 0;
+ foreach (TextBlock star in panelStory.Children)
+ star.Tag = star.Text = getStar(rating.StoryRating, starIndex++);
- private void SetVisible()
- {
ratingsGrid.IsEnabled = IsEditingMode;
- tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0;
- tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0;
- tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0;
+ tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || rating.OverallRating > 0;
+ tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || rating.PerformanceRating > 0;
+ tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || rating.StoryRating > 0;
}
public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e)
diff --git a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs
index 9dfc6e3f..41967e0d 100644
--- a/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/AccountsDialog.axaml.cs
@@ -120,7 +120,7 @@ namespace LibationAvalonia.Dialogs
SuggestedStartLocation = new BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)),
FileTypeFilter = new FilePickerFileType[]
{
- new("JSON files (*.json)") { Patterns = new[] { "json" } },
+ new("JSON files (*.json)") { Patterns = new[] { "*.json" } },
}
};
@@ -280,7 +280,7 @@ namespace LibationAvalonia.Dialogs
ShowOverwritePrompt = true,
FileTypeChoices = new FilePickerFileType[]
{
- new("JSON files (*.json)") { Patterns = new[] { "json" } },
+ new("JSON files (*.json)") { Patterns = new[] { "*.json" } },
}
};
diff --git a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs
index 33a039f9..6a3b7213 100644
--- a/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/EditTemplateDialog.axaml.cs
@@ -27,7 +27,7 @@ namespace LibationAvalonia.Dialogs
userEditTbox = this.FindControl(nameof(userEditTbox));
if (Design.IsDesignMode)
{
- AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
+ _ = Configuration.Instance.LibationFiles;
_viewModel = new(Configuration.Instance, Templates.File);
_viewModel.resetTextBox(_viewModel.Template.DefaultTemplate);
Title = $"Edit {_viewModel.Template.Name}";
diff --git a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs
index 0af59ebd..468be111 100644
--- a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml.cs
@@ -22,7 +22,7 @@ namespace LibationAvalonia.Dialogs
public SettingsDialog()
{
if (Design.IsDesignMode)
- AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
+ _ = Configuration.Instance.LibationFiles;
InitializeComponent();
DataContext = settingsDisp = new(config);
diff --git a/Source/LibationAvalonia/ViewModels/GridEntry.cs b/Source/LibationAvalonia/ViewModels/GridEntry.cs
index 4219699e..b20f12cd 100644
--- a/Source/LibationAvalonia/ViewModels/GridEntry.cs
+++ b/Source/LibationAvalonia/ViewModels/GridEntry.cs
@@ -44,8 +44,7 @@ namespace LibationAvalonia.ViewModels
public string Category { get; protected set; }
public string Misc { get; protected set; }
public string Description { get; protected set; }
- public string ProductRating { get; protected set; }
- public string MyRatingString => MyRating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
+ public Rating ProductRating { get; protected set; }
protected Rating _myRating;
public Rating MyRating
{
@@ -68,7 +67,6 @@ namespace LibationAvalonia.ViewModels
public abstract bool IsSeries { get; }
public abstract bool IsEpisode { get; }
public abstract bool IsBook { get; }
- public abstract double Opacity { get; }
public IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : Brushes.Transparent;
#endregion
diff --git a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs
index c79f4cfd..e00c9461 100644
--- a/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs
+++ b/Source/LibationAvalonia/ViewModels/LibraryBookEntry.cs
@@ -53,7 +53,6 @@ namespace LibationAvalonia.ViewModels
public override bool IsSeries => false;
public override bool IsEpisode => Parent is not null;
public override bool IsBook => Parent is null;
- public override double Opacity => Book.UserDefinedItem.Tags.ToLower().Contains("hidden") ? 0.4 : 1;
#endregion
@@ -69,7 +68,7 @@ namespace LibationAvalonia.ViewModels
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
PurchaseDate = libraryBook.DateAdded.ToString("d");
- ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
+ ProductRating = Book.Rating ?? new Rating(0, 0, 0);
Authors = Book.AuthorNames();
Narrators = Book.NarratorNames();
Category = string.Join(" > ", Book.CategoriesNames());
@@ -102,7 +101,6 @@ namespace LibationAvalonia.ViewModels
case nameof(udi.Tags):
Book.UserDefinedItem.Tags = udi.Tags;
this.RaisePropertyChanged(nameof(BookTags));
- this.RaisePropertyChanged(nameof(Opacity));
break;
case nameof(udi.BookStatus):
Book.UserDefinedItem.BookStatus = udi.BookStatus;
diff --git a/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs b/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs
index 2c483c3e..05b92134 100644
--- a/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs
+++ b/Source/LibationAvalonia/ViewModels/ProcessQueueViewModel.cs
@@ -31,7 +31,7 @@ namespace LibationAvalonia.ViewModels
Queue.CompletedCountChanged += Queue_CompletedCountChanged;
if (Design.IsDesignMode)
- AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
+ _ = Configuration.Instance.LibationFiles;
SpeedLimit = Configuration.Instance.DownloadSpeedLimit / 1024m / 1024;
}
diff --git a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs
index c0ca2965..9f2d9749 100644
--- a/Source/LibationAvalonia/ViewModels/SeriesEntry.cs
+++ b/Source/LibationAvalonia/ViewModels/SeriesEntry.cs
@@ -49,7 +49,6 @@ namespace LibationAvalonia.ViewModels
public override bool IsSeries => true;
public override bool IsEpisode => false;
public override bool IsBook => false;
- public override double Opacity => 1;
#endregion
@@ -71,7 +70,7 @@ namespace LibationAvalonia.ViewModels
//Ratings are changed using Update(), which is a problem for Avalonia data bindings because
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
- ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
+ ProductRating = Book.Rating ?? new Rating(0, 0, 0);
Authors = Book.AuthorNames();
Narrators = Book.NarratorNames();
Category = string.Join(" > ", Book.CategoriesNames());
diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml b/Source/LibationAvalonia/Views/ProductsDisplay.axaml
index 28967546..87dfb645 100644
--- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml
+++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml
@@ -19,10 +19,12 @@
CanUserReorderColumns="True">
-
+
+
+
+
+
-
+
@@ -83,7 +89,7 @@
-
+
@@ -93,7 +99,7 @@
-
+
@@ -103,7 +109,7 @@
-
+
@@ -113,7 +119,7 @@
-
+
@@ -123,7 +129,7 @@
-
+
@@ -133,39 +139,45 @@
-
+
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
@@ -187,6 +199,5 @@
-
diff --git a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
index 4d1854b8..7d3a3bc3 100644
--- a/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
+++ b/Source/LibationAvalonia/Views/ProductsDisplay.axaml.cs
@@ -273,13 +273,13 @@ namespace LibationAvalonia.Views
#region Button Click Handlers
- public void LiberateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
+ public async void LiberateButton_Click(object sender, Avalonia.Interactivity.RoutedEventArgs args)
{
var button = args.Source as Button;
if (button.DataContext is SeriesEntry sEntry)
{
- _viewModel.ToggleSeriesExpanded(sEntry);
+ await _viewModel.ToggleSeriesExpanded(sEntry);
//Expanding and collapsing reset the list, which will cause focus to shift
//to the topright cell. Reset focus onto the clicked button's cell.
diff --git a/Source/LibationFileManager/PropertyChangeFilter.cs b/Source/LibationFileManager/PropertyChangeFilter.cs
index c30bfa0f..5fe0d6e4 100644
--- a/Source/LibationFileManager/PropertyChangeFilter.cs
+++ b/Source/LibationFileManager/PropertyChangeFilter.cs
@@ -79,23 +79,36 @@ namespace LibationFileManager
{
private readonly Dictionary> propertyChangedActions = new();
private readonly Dictionary> propertyChangingActions = new();
-
+
private readonly List<(PropertyChangedEventHandlerEx subscriber, PropertyChangedEventHandlerEx wrapper)> changedFilters = new();
private readonly List<(PropertyChangingEventHandlerEx subscriber, PropertyChangingEventHandlerEx wrapper)> changingFilters = new();
- public PropertyChangeFilter()
+ protected void OnPropertyChanged(string propertyName, object newValue)
{
- PropertyChanging += Configuration_PropertyChanging;
- PropertyChanged += Configuration_PropertyChanged;
+ if (propertyChangedActions.ContainsKey(propertyName))
+ {
+ //Invoke observables registered for propertyName
+ foreach (var action in propertyChangedActions[propertyName])
+ action.DynamicInvoke(newValue);
+ }
+
+ _propertyChanged?.Invoke(this, new(propertyName, newValue));
+ }
+
+ protected void OnPropertyChanging(string propertyName, object oldValue, object newValue)
+ {
+ if (propertyChangingActions.ContainsKey(propertyName))
+ {
+ //Invoke observables registered for propertyName
+ foreach (var action in propertyChangingActions[propertyName])
+ action.DynamicInvoke(oldValue, newValue);
+ }
+
+ _propertyChanging?.Invoke(this, new(propertyName, oldValue, newValue));
}
#region Events
- protected void OnPropertyChanged(string propertyName, object newValue)
- => _propertyChanged?.Invoke(this, new(propertyName, newValue));
- protected void OnPropertyChanging(string propertyName, object oldValue, object newValue)
- => _propertyChanging?.Invoke(this, new(propertyName, oldValue, newValue));
-
private PropertyChangedEventHandlerEx _propertyChanged;
private PropertyChangingEventHandlerEx _propertyChanging;
@@ -255,28 +268,6 @@ namespace LibationFileManager
throw new InvalidCastException($"{nameof(Configuration)}.{propertyName} is {propertyInfo.PropertyType}, but parameter is {typeof(T)}.");
}
- private void Configuration_PropertyChanged(object sender, PropertyChangedEventArgsEx e)
- {
- if (propertyChangedActions.ContainsKey(e.PropertyName))
- {
- foreach (var action in propertyChangedActions[e.PropertyName])
- {
- action.DynamicInvoke(e.NewValue);
- }
- }
- }
-
- private void Configuration_PropertyChanging(object sender, PropertyChangingEventArgsEx e)
- {
- if (propertyChangingActions.ContainsKey(e.PropertyName))
- {
- foreach (var action in propertyChangingActions[e.PropertyName])
- {
- action.DynamicInvoke(e.OldValue, e.NewValue);
- }
- }
- }
-
private class Unsubscriber : IDisposable
{
private List _observers;
diff --git a/Source/LibationWinForms/Dialogs/UpgradeNotificationDialog.Designer.cs b/Source/LibationWinForms/Dialogs/UpgradeNotificationDialog.Designer.cs
index 581e0b9e..f1d8ca56 100644
--- a/Source/LibationWinForms/Dialogs/UpgradeNotificationDialog.Designer.cs
+++ b/Source/LibationWinForms/Dialogs/UpgradeNotificationDialog.Designer.cs
@@ -208,11 +208,7 @@
#endregion
- private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox releaseNotesTbox;
- private System.Windows.Forms.GroupBox groupBox1;
- private System.Windows.Forms.LinkLabel linkLabel3;
- private System.Windows.Forms.LinkLabel linkLabel2;
private System.Windows.Forms.LinkLabel packageDlLink;
private System.Windows.Forms.Button dontRemindBtn;
private System.Windows.Forms.Button yesBtn;