Merge pull request #444 from Mbucari/master
Build and attach deb package
This commit is contained in:
commit
89c3ea8311
39
.github/workflows/build-deb.yml
vendored
Normal file
39
.github/workflows/build-deb.yml
vendored
Normal file
@ -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
|
||||||
8
.github/workflows/build-linux.yml
vendored
8
.github/workflows/build-linux.yml
vendored
@ -15,6 +15,10 @@ on:
|
|||||||
description: 'Skip running unit tests'
|
description: 'Skip running unit tests'
|
||||||
required: false
|
required: false
|
||||||
default: true
|
default: true
|
||||||
|
outputs:
|
||||||
|
version:
|
||||||
|
description: "The Libation version number"
|
||||||
|
value: ${{ jobs.build.outputs.version }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOTNET_CONFIGURATION: 'Release'
|
DOTNET_CONFIGURATION: 'Release'
|
||||||
@ -23,6 +27,8 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.get_version.outputs.version }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [Linux, MacOS]
|
os: [Linux, MacOS]
|
||||||
@ -66,6 +72,8 @@ jobs:
|
|||||||
id: zip
|
id: zip
|
||||||
working-directory: ./Source/bin/Publish/${{ matrix.os }}-${{ matrix.release_name }}
|
working-directory: ./Source/bin/Publish/${{ matrix.os }}-${{ matrix.release_name }}
|
||||||
run: |
|
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:]')"
|
osbuild="$(echo '${{ matrix.os }}' | tr '[:upper:]' '[:lower:]')"
|
||||||
artifact="Libation.${{ steps.get_version.outputs.version }}-${osbuild}-${{ matrix.release_name }}"
|
artifact="Libation.${{ steps.get_version.outputs.version }}-${osbuild}-${{ matrix.release_name }}"
|
||||||
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
|
echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}"
|
||||||
|
|||||||
15
.github/workflows/build-windows.yml
vendored
15
.github/workflows/build-windows.yml
vendored
@ -15,6 +15,10 @@ on:
|
|||||||
description: 'Skip running unit tests'
|
description: 'Skip running unit tests'
|
||||||
required: false
|
required: false
|
||||||
default: true
|
default: true
|
||||||
|
outputs:
|
||||||
|
version:
|
||||||
|
description: "The Libation version number"
|
||||||
|
value: ${{ jobs.build.outputs.version }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOTNET_CONFIGURATION: 'Release'
|
DOTNET_CONFIGURATION: 'Release'
|
||||||
@ -23,6 +27,8 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.get_version.outputs.version }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [Windows]
|
os: [Windows]
|
||||||
@ -48,8 +54,7 @@ jobs:
|
|||||||
if ("${{ inputs.version_override }}".length -gt 0) {
|
if ("${{ inputs.version_override }}".length -gt 0) {
|
||||||
$version = "${{ inputs.version_override }}"
|
$version = "${{ inputs.version_override }}"
|
||||||
} else {
|
} else {
|
||||||
[xml]$appScaffolding = Get-Content -Path ./Source/AppScaffolding/AppScaffolding.csproj
|
$version = (Select-Xml -Path "./Source/AppScaffolding/AppScaffolding.csproj" -XPath "/Project/PropertyGroup/Version").Node.InnerXML.Trim()
|
||||||
$version = $appScaffolding.Project.PropertyGroup.Version
|
|
||||||
}
|
}
|
||||||
"version=$version" >> $env:GITHUB_OUTPUT
|
"version=$version" >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
@ -70,9 +75,12 @@ jobs:
|
|||||||
id: zip
|
id: zip
|
||||||
working-directory: ./Source/bin/Publish
|
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="${{ matrix.prefix }}Libation.${{ steps.get_version.outputs.version }}-" + "${{ matrix.os }}".ToLower() + "-${{ matrix.release_name }}"
|
||||||
"artifact=$artifact" >> $env:GITHUB_OUTPUT
|
"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
|
- name: Publish artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
@ -80,3 +88,4 @@ jobs:
|
|||||||
name: ${{ steps.zip.outputs.artifact }}.zip
|
name: ${{ steps.zip.outputs.artifact }}.zip
|
||||||
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
|
path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
|||||||
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@ -28,3 +28,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version_override: ${{ inputs.version_override }}
|
version_override: ${{ inputs.version_override }}
|
||||||
run_unit_tests: ${{ inputs.run_unit_tests }}
|
run_unit_tests: ${{ inputs.run_unit_tests }}
|
||||||
|
|
||||||
|
linux_deb:
|
||||||
|
needs: [linux]
|
||||||
|
uses: ./.github/workflows/build-deb.yml
|
||||||
|
with:
|
||||||
|
version: ${{ needs.linux.outputs.version }}
|
||||||
|
|
||||||
|
|||||||
@ -116,7 +116,6 @@ Version: $VERSION
|
|||||||
Architecture: all
|
Architecture: all
|
||||||
Essential: no
|
Essential: no
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Depends: ffmpeg
|
|
||||||
Maintainer: github.com/rmcrackan
|
Maintainer: github.com/rmcrackan
|
||||||
Description: liberate your audiobooks
|
Description: liberate your audiobooks
|
||||||
" >> "$FOLDER_DEBIAN/control"
|
" >> "$FOLDER_DEBIAN/control"
|
||||||
@ -13,7 +13,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AAXClean.Codecs" Version="0.2.15" />
|
<PackageReference Include="AAXClean.Codecs" Version="0.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -32,7 +32,7 @@ namespace AaxDecrypter
|
|||||||
AaxFile.AppleTags.Album = AaxFile.AppleTags.Album?.Replace(" (Unabridged)", "");
|
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);
|
AaxFile.AppleTags.AppleListBox.EditOrAddTag("TCOM", AaxFile.AppleTags.Narrator);
|
||||||
|
|
||||||
//Finishing configuring lame encoder.
|
//Finishing configuring lame encoder.
|
||||||
|
|||||||
@ -93,7 +93,9 @@ namespace DataLayer
|
|||||||
|
|
||||||
var starString = new string(STAR, fullStars);
|
var starString = new string(STAR, fullStars);
|
||||||
|
|
||||||
if (score - fullStars >= 0.25f)
|
if (score - fullStars >= 0.75f)
|
||||||
|
starString += STAR;
|
||||||
|
else if (score - fullStars >= 0.25f)
|
||||||
starString += HALF;
|
starString += HALF;
|
||||||
|
|
||||||
return starString;
|
return starString;
|
||||||
|
|||||||
@ -174,7 +174,10 @@ namespace DtoImporterService
|
|||||||
if (item.PictureLarge is not null)
|
if (item.PictureLarge is not null)
|
||||||
book.PictureLarge = item.PictureLarge;
|
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
|
// 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);
|
book.UserDefinedItem.UpdateRating(item.MyUserRating_Overall, item.MyUserRating_Performance, item.MyUserRating_Story);
|
||||||
|
|||||||
@ -2,14 +2,24 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
using LibationAvalonia.ViewModels;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace LibationAvalonia.Controls
|
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
|
public class DataGridMyRatingColumn : DataGridBoundColumn
|
||||||
{
|
{
|
||||||
|
[Avalonia.Data.AssignBinding]
|
||||||
|
public Avalonia.Data.IBinding BackgroundBinding { get; set; }
|
||||||
private static Rating DefaultRating => new Rating(0, 0, 0);
|
private static Rating DefaultRating => new Rating(0, 0, 0);
|
||||||
public DataGridMyRatingColumn()
|
public DataGridMyRatingColumn()
|
||||||
{
|
{
|
||||||
@ -24,29 +34,20 @@ namespace LibationAvalonia.Controls
|
|||||||
IsEditingMode = false
|
IsEditingMode = false
|
||||||
};
|
};
|
||||||
|
|
||||||
ToolTip.SetTip(myRatingElement, "Click to change ratings");
|
|
||||||
cell?.AttachContextMenu();
|
cell?.AttachContextMenu();
|
||||||
|
|
||||||
|
if (!IsReadOnly)
|
||||||
|
ToolTip.SetTip(myRatingElement, "Click to change ratings");
|
||||||
|
|
||||||
if (Binding != null)
|
if (Binding != null)
|
||||||
{
|
{
|
||||||
myRatingElement.Bind(BindingTarget, Binding);
|
myRatingElement.Bind(BindingTarget, Binding);
|
||||||
}
|
}
|
||||||
|
if (BackgroundBinding != null)
|
||||||
void setControlBackground(object dataContext)
|
|
||||||
{
|
{
|
||||||
if (dataContext is GridEntry ge)
|
myRatingElement.Bind(MyRatingCellEditor.BackgroundProperty, BackgroundBinding);
|
||||||
myRatingElement.Background = ge.BackgroundBrush;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setControlBackground(cell?.DataContext);
|
|
||||||
|
|
||||||
var subscriber =
|
|
||||||
cell
|
|
||||||
?.ObservableForProperty(g => g.DataContext)
|
|
||||||
?.Subscribe(ctx => setControlBackground(ctx?.Value));
|
|
||||||
|
|
||||||
myRatingElement.DetachedFromVisualTree += (_, _) => subscriber?.Dispose();
|
|
||||||
|
|
||||||
return myRatingElement;
|
return myRatingElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +58,10 @@ namespace LibationAvalonia.Controls
|
|||||||
Name = "CellMyRatingEditor",
|
Name = "CellMyRatingEditor",
|
||||||
IsEditingMode = true
|
IsEditingMode = true
|
||||||
};
|
};
|
||||||
|
if (BackgroundBinding != null)
|
||||||
|
{
|
||||||
|
myRatingElement.Bind(MyRatingCellEditor.BackgroundProperty, BackgroundBinding);
|
||||||
|
}
|
||||||
|
|
||||||
return myRatingElement;
|
return myRatingElement;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
|
using ReactiveUI;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace LibationAvalonia.Controls
|
namespace LibationAvalonia.Controls
|
||||||
@ -9,6 +11,7 @@ namespace LibationAvalonia.Controls
|
|||||||
{
|
{
|
||||||
private const string SOLID_STAR = "★";
|
private const string SOLID_STAR = "★";
|
||||||
private const string HOLLOW_STAR = "☆";
|
private const string HOLLOW_STAR = "☆";
|
||||||
|
private const string HALF_STAR = "½";
|
||||||
|
|
||||||
public static readonly StyledProperty<Rating> RatingProperty =
|
public static readonly StyledProperty<Rating> RatingProperty =
|
||||||
AvaloniaProperty.Register<MyRatingCellEditor, Rating>(nameof(Rating));
|
AvaloniaProperty.Register<MyRatingCellEditor, Rating>(nameof(Rating));
|
||||||
@ -19,39 +22,41 @@ namespace LibationAvalonia.Controls
|
|||||||
public MyRatingCellEditor()
|
public MyRatingCellEditor()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
var subscriber = this.ObservableForProperty(p => p.Rating).Subscribe(o => DisplayStarRating(o.Value ?? new Rating(0, 0, 0)));
|
||||||
|
Unloaded += (_, _) => subscriber.Dispose();
|
||||||
|
|
||||||
if (Design.IsDesignMode)
|
if (Design.IsDesignMode)
|
||||||
Rating = new Rating(5, 4, 3);
|
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;
|
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;
|
||||||
|
|
||||||
|
int starIndex = 0;
|
||||||
foreach (TextBlock star in panelOverall.Children)
|
foreach (TextBlock star in panelOverall.Children)
|
||||||
star.Tag = star.Text = Rating.OverallRating > rating++ ? SOLID_STAR : blankValue;
|
star.Tag = star.Text = getStar(rating.OverallRating, starIndex++);
|
||||||
|
|
||||||
rating = 0;
|
starIndex = 0;
|
||||||
foreach (TextBlock star in panelPerform.Children)
|
foreach (TextBlock star in panelPerform.Children)
|
||||||
star.Tag = star.Text = Rating.PerformanceRating > rating++ ? SOLID_STAR : blankValue;
|
star.Tag = star.Text = getStar(rating.PerformanceRating, starIndex++);
|
||||||
|
|
||||||
rating = 0;
|
starIndex = 0;
|
||||||
foreach (TextBlock star in panelStory.Children)
|
foreach (TextBlock star in panelStory.Children)
|
||||||
star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue;
|
star.Tag = star.Text = getStar(rating.StoryRating, starIndex++);
|
||||||
|
|
||||||
SetVisible();
|
|
||||||
}
|
|
||||||
base.OnPropertyChanged(change);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetVisible()
|
|
||||||
{
|
|
||||||
ratingsGrid.IsEnabled = IsEditingMode;
|
ratingsGrid.IsEnabled = IsEditingMode;
|
||||||
tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0;
|
tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || rating.OverallRating > 0;
|
||||||
tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0;
|
tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || rating.PerformanceRating > 0;
|
||||||
tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0;
|
tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || rating.StoryRating > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e)
|
public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e)
|
||||||
|
|||||||
@ -120,7 +120,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
SuggestedStartLocation = new BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)),
|
SuggestedStartLocation = new BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)),
|
||||||
FileTypeFilter = new FilePickerFileType[]
|
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,
|
ShowOverwritePrompt = true,
|
||||||
FileTypeChoices = new FilePickerFileType[]
|
FileTypeChoices = new FilePickerFileType[]
|
||||||
{
|
{
|
||||||
new("JSON files (*.json)") { Patterns = new[] { "json" } },
|
new("JSON files (*.json)") { Patterns = new[] { "*.json" } },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
userEditTbox = this.FindControl<TextBox>(nameof(userEditTbox));
|
userEditTbox = this.FindControl<TextBox>(nameof(userEditTbox));
|
||||||
if (Design.IsDesignMode)
|
if (Design.IsDesignMode)
|
||||||
{
|
{
|
||||||
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
_ = Configuration.Instance.LibationFiles;
|
||||||
_viewModel = new(Configuration.Instance, Templates.File);
|
_viewModel = new(Configuration.Instance, Templates.File);
|
||||||
_viewModel.resetTextBox(_viewModel.Template.DefaultTemplate);
|
_viewModel.resetTextBox(_viewModel.Template.DefaultTemplate);
|
||||||
Title = $"Edit {_viewModel.Template.Name}";
|
Title = $"Edit {_viewModel.Template.Name}";
|
||||||
|
|||||||
@ -22,7 +22,7 @@ namespace LibationAvalonia.Dialogs
|
|||||||
public SettingsDialog()
|
public SettingsDialog()
|
||||||
{
|
{
|
||||||
if (Design.IsDesignMode)
|
if (Design.IsDesignMode)
|
||||||
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
_ = Configuration.Instance.LibationFiles;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
DataContext = settingsDisp = new(config);
|
DataContext = settingsDisp = new(config);
|
||||||
|
|||||||
@ -44,8 +44,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
public string Category { get; protected set; }
|
public string Category { get; protected set; }
|
||||||
public string Misc { get; protected set; }
|
public string Misc { get; protected set; }
|
||||||
public string Description { get; protected set; }
|
public string Description { get; protected set; }
|
||||||
public string ProductRating { get; protected set; }
|
public Rating ProductRating { get; protected set; }
|
||||||
public string MyRatingString => MyRating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
|
||||||
protected Rating _myRating;
|
protected Rating _myRating;
|
||||||
public Rating MyRating
|
public Rating MyRating
|
||||||
{
|
{
|
||||||
@ -68,7 +67,6 @@ namespace LibationAvalonia.ViewModels
|
|||||||
public abstract bool IsSeries { get; }
|
public abstract bool IsSeries { get; }
|
||||||
public abstract bool IsEpisode { get; }
|
public abstract bool IsEpisode { get; }
|
||||||
public abstract bool IsBook { get; }
|
public abstract bool IsBook { get; }
|
||||||
public abstract double Opacity { get; }
|
|
||||||
public IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : Brushes.Transparent;
|
public IBrush BackgroundBrush => IsEpisode ? App.SeriesEntryGridBackgroundBrush : Brushes.Transparent;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -53,7 +53,6 @@ namespace LibationAvalonia.ViewModels
|
|||||||
public override bool IsSeries => false;
|
public override bool IsSeries => false;
|
||||||
public override bool IsEpisode => Parent is not null;
|
public override bool IsEpisode => Parent is not null;
|
||||||
public override bool IsBook => Parent is null;
|
public override bool IsBook => Parent is null;
|
||||||
public override double Opacity => Book.UserDefinedItem.Tags.ToLower().Contains("hidden") ? 0.4 : 1;
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
//the reference doesn't change. Clone the rating so that it updates within Avalonia properly.
|
//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);
|
_myRating = new Rating(Book.UserDefinedItem.Rating.OverallRating, Book.UserDefinedItem.Rating.PerformanceRating, Book.UserDefinedItem.Rating.StoryRating);
|
||||||
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
PurchaseDate = libraryBook.DateAdded.ToString("d");
|
||||||
ProductRating = Book.Rating?.ToStarString()?.DefaultIfNullOrWhiteSpace("");
|
ProductRating = Book.Rating ?? new Rating(0, 0, 0);
|
||||||
Authors = Book.AuthorNames();
|
Authors = Book.AuthorNames();
|
||||||
Narrators = Book.NarratorNames();
|
Narrators = Book.NarratorNames();
|
||||||
Category = string.Join(" > ", Book.CategoriesNames());
|
Category = string.Join(" > ", Book.CategoriesNames());
|
||||||
@ -102,7 +101,6 @@ namespace LibationAvalonia.ViewModels
|
|||||||
case nameof(udi.Tags):
|
case nameof(udi.Tags):
|
||||||
Book.UserDefinedItem.Tags = udi.Tags;
|
Book.UserDefinedItem.Tags = udi.Tags;
|
||||||
this.RaisePropertyChanged(nameof(BookTags));
|
this.RaisePropertyChanged(nameof(BookTags));
|
||||||
this.RaisePropertyChanged(nameof(Opacity));
|
|
||||||
break;
|
break;
|
||||||
case nameof(udi.BookStatus):
|
case nameof(udi.BookStatus):
|
||||||
Book.UserDefinedItem.BookStatus = udi.BookStatus;
|
Book.UserDefinedItem.BookStatus = udi.BookStatus;
|
||||||
|
|||||||
@ -31,7 +31,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
Queue.CompletedCountChanged += Queue_CompletedCountChanged;
|
Queue.CompletedCountChanged += Queue_CompletedCountChanged;
|
||||||
|
|
||||||
if (Design.IsDesignMode)
|
if (Design.IsDesignMode)
|
||||||
AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
|
_ = Configuration.Instance.LibationFiles;
|
||||||
|
|
||||||
SpeedLimit = Configuration.Instance.DownloadSpeedLimit / 1024m / 1024;
|
SpeedLimit = Configuration.Instance.DownloadSpeedLimit / 1024m / 1024;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,6 @@ namespace LibationAvalonia.ViewModels
|
|||||||
public override bool IsSeries => true;
|
public override bool IsSeries => true;
|
||||||
public override bool IsEpisode => false;
|
public override bool IsEpisode => false;
|
||||||
public override bool IsBook => false;
|
public override bool IsBook => false;
|
||||||
public override double Opacity => 1;
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -71,7 +70,7 @@ namespace LibationAvalonia.ViewModels
|
|||||||
//Ratings are changed using Update(), which is a problem for Avalonia data bindings because
|
//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.
|
//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);
|
_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();
|
Authors = Book.AuthorNames();
|
||||||
Narrators = Book.NarratorNames();
|
Narrators = Book.NarratorNames();
|
||||||
Category = string.Join(" > ", Book.CategoriesNames());
|
Category = string.Join(" > ", Book.CategoriesNames());
|
||||||
|
|||||||
@ -19,10 +19,12 @@
|
|||||||
CanUserReorderColumns="True">
|
CanUserReorderColumns="True">
|
||||||
|
|
||||||
<DataGrid.Styles>
|
<DataGrid.Styles>
|
||||||
<Style Selector="DataGridCell > Panel">
|
<Style Selector="DataGridCell">
|
||||||
<Setter Property="Margin" Value="0,1,0,1"/>
|
|
||||||
<Setter Property="Height" Value="80"/>
|
<Setter Property="Height" Value="80"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="DataGridCell > Panel">
|
||||||
|
<Setter Property="VerticalAlignment" Value="Stretch"/>
|
||||||
|
</Style>
|
||||||
<Style Selector="DataGridCell > Panel > TextBlock">
|
<Style Selector="DataGridCell > Panel > TextBlock">
|
||||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
@ -31,6 +33,10 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</DataGrid.Styles>
|
</DataGrid.Styles>
|
||||||
|
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<controls:StarStringConverter x:Key="starStringConverter" />
|
||||||
|
</DataGrid.Resources>
|
||||||
|
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
|
|
||||||
<DataGridTemplateColumn
|
<DataGridTemplateColumn
|
||||||
@ -73,7 +79,7 @@
|
|||||||
<controls:DataGridTemplateColumnExt MinWidth="150" Width="2*" Header="Title" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
<controls:DataGridTemplateColumnExt MinWidth="150" Width="2*" Header="Title" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Title}" />
|
<TextBlock Text="{Binding Title}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -83,7 +89,7 @@
|
|||||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Authors" CanUserSort="True" SortMemberPath="Authors" ClipboardContentBinding="{Binding Authors}">
|
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Authors" CanUserSort="True" SortMemberPath="Authors" ClipboardContentBinding="{Binding Authors}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Authors}" />
|
<TextBlock Text="{Binding Authors}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -93,7 +99,7 @@
|
|||||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Narrators" CanUserSort="True" SortMemberPath="Narrators" ClipboardContentBinding="{Binding Narrators}">
|
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Narrators" CanUserSort="True" SortMemberPath="Narrators" ClipboardContentBinding="{Binding Narrators}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Narrators}" />
|
<TextBlock Text="{Binding Narrators}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -103,7 +109,7 @@
|
|||||||
<controls:DataGridTemplateColumnExt Width="90" Header="Length" CanUserSort="True" SortMemberPath="Length" ClipboardContentBinding="{Binding Length}">
|
<controls:DataGridTemplateColumnExt Width="90" Header="Length" CanUserSort="True" SortMemberPath="Length" ClipboardContentBinding="{Binding Length}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Length}" />
|
<TextBlock Text="{Binding Length}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -113,7 +119,7 @@
|
|||||||
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Series" CanUserSort="True" SortMemberPath="Series" ClipboardContentBinding="{Binding Series}">
|
<controls:DataGridTemplateColumnExt MinWidth="80" Width="1*" Header="Series" CanUserSort="True" SortMemberPath="Series" ClipboardContentBinding="{Binding Series}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Series}" />
|
<TextBlock Text="{Binding Series}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -123,7 +129,7 @@
|
|||||||
<controls:DataGridTemplateColumnExt MinWidth="100" Width="1*" Header="Description" CanUserSort="True" SortMemberPath="Description" ClipboardContentBinding="{Binding LongDescription}">
|
<controls:DataGridTemplateColumnExt MinWidth="100" Width="1*" Header="Description" CanUserSort="True" SortMemberPath="Description" ClipboardContentBinding="{Binding LongDescription}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
<Panel Background="{Binding BackgroundBrush}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
|
||||||
<TextBlock Text="{Binding Description}" FontSize="11" VerticalAlignment="Top" />
|
<TextBlock Text="{Binding Description}" FontSize="11" VerticalAlignment="Top" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -133,39 +139,45 @@
|
|||||||
<controls:DataGridTemplateColumnExt Width="100" Header="Category" CanUserSort="True" SortMemberPath="Category" ClipboardContentBinding="{Binding Category}">
|
<controls:DataGridTemplateColumnExt Width="100" Header="Category" CanUserSort="True" SortMemberPath="Category" ClipboardContentBinding="{Binding Category}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Category}" />
|
<TextBlock Text="{Binding Category}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="115" Header="Product
Rating" CanUserSort="True" SortMemberPath="ProductRating" ClipboardContentBinding="{Binding ProductRating}">
|
<controls:DataGridMyRatingColumn
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
Header="Product
Rating"
|
||||||
<DataTemplate>
|
IsReadOnly="true"
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
Width="115"
|
||||||
<TextBlock Text="{Binding ProductRating}" TextWrapping="NoWrap" FontSize="11" />
|
SortMemberPath="ProductRating" CanUserSort="True"
|
||||||
</Panel>
|
BackgroundBinding="{Binding BackgroundBrush}"
|
||||||
</DataTemplate>
|
ClipboardContentBinding="{Binding ProductRating, Converter={StaticResource starStringConverter}}"
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
Binding="{Binding ProductRating}" />
|
||||||
</controls:DataGridTemplateColumnExt>
|
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="90" Header="Purchase
Date" CanUserSort="True" SortMemberPath="PurchaseDate" ClipboardContentBinding="{Binding PurchaseDate}">
|
<controls:DataGridTemplateColumnExt Width="90" Header="Purchase
Date" CanUserSort="True" SortMemberPath="PurchaseDate" ClipboardContentBinding="{Binding PurchaseDate}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding PurchaseDate}" />
|
<TextBlock Text="{Binding PurchaseDate}" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</controls:DataGridTemplateColumnExt>
|
</controls:DataGridTemplateColumnExt>
|
||||||
|
|
||||||
<controls:DataGridMyRatingColumn IsReadOnly="false" Width="115" Header="My Rating" CanUserSort="True" SortMemberPath="MyRating" ClipboardContentBinding="{Binding MyRatingString}" Binding="{Binding MyRating, Mode=TwoWay}" />
|
<controls:DataGridMyRatingColumn
|
||||||
|
Header="My Rating"
|
||||||
|
IsReadOnly="false"
|
||||||
|
Width="115"
|
||||||
|
SortMemberPath="MyRating" CanUserSort="True"
|
||||||
|
BackgroundBinding="{Binding BackgroundBrush}"
|
||||||
|
ClipboardContentBinding="{Binding MyRating, Converter={StaticResource starStringConverter}}"
|
||||||
|
Binding="{Binding MyRating, Mode=TwoWay}" />
|
||||||
|
|
||||||
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Background="{Binding BackgroundBrush}" Opacity="{Binding Opacity}">
|
<Panel Background="{Binding BackgroundBrush}">
|
||||||
<TextBlock Text="{Binding Misc}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
<TextBlock Text="{Binding Misc}" TextWrapping="WrapWithOverflow" FontSize="10" />
|
||||||
</Panel>
|
</Panel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -187,6 +199,5 @@
|
|||||||
|
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@ -273,13 +273,13 @@ namespace LibationAvalonia.Views
|
|||||||
|
|
||||||
#region Button Click Handlers
|
#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;
|
var button = args.Source as Button;
|
||||||
|
|
||||||
if (button.DataContext is SeriesEntry sEntry)
|
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
|
//Expanding and collapsing reset the list, which will cause focus to shift
|
||||||
//to the topright cell. Reset focus onto the clicked button's cell.
|
//to the topright cell. Reset focus onto the clicked button's cell.
|
||||||
|
|||||||
@ -83,19 +83,32 @@ namespace LibationFileManager
|
|||||||
private readonly List<(PropertyChangedEventHandlerEx subscriber, PropertyChangedEventHandlerEx wrapper)> changedFilters = new();
|
private readonly List<(PropertyChangedEventHandlerEx subscriber, PropertyChangedEventHandlerEx wrapper)> changedFilters = new();
|
||||||
private readonly List<(PropertyChangingEventHandlerEx subscriber, PropertyChangingEventHandlerEx wrapper)> changingFilters = new();
|
private readonly List<(PropertyChangingEventHandlerEx subscriber, PropertyChangingEventHandlerEx wrapper)> changingFilters = new();
|
||||||
|
|
||||||
public PropertyChangeFilter()
|
protected void OnPropertyChanged(string propertyName, object newValue)
|
||||||
{
|
{
|
||||||
PropertyChanging += Configuration_PropertyChanging;
|
if (propertyChangedActions.ContainsKey(propertyName))
|
||||||
PropertyChanged += Configuration_PropertyChanged;
|
{
|
||||||
|
//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
|
#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 PropertyChangedEventHandlerEx _propertyChanged;
|
||||||
private PropertyChangingEventHandlerEx _propertyChanging;
|
private PropertyChangingEventHandlerEx _propertyChanging;
|
||||||
|
|
||||||
@ -255,28 +268,6 @@ namespace LibationFileManager
|
|||||||
throw new InvalidCastException($"{nameof(Configuration)}.{propertyName} is {propertyInfo.PropertyType}, but parameter is {typeof(T)}.");
|
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 class Unsubscriber : IDisposable
|
||||||
{
|
{
|
||||||
private List<Delegate> _observers;
|
private List<Delegate> _observers;
|
||||||
|
|||||||
@ -208,11 +208,7 @@
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private System.Windows.Forms.Label label1;
|
|
||||||
private System.Windows.Forms.TextBox releaseNotesTbox;
|
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.LinkLabel packageDlLink;
|
||||||
private System.Windows.Forms.Button dontRemindBtn;
|
private System.Windows.Forms.Button dontRemindBtn;
|
||||||
private System.Windows.Forms.Button yesBtn;
|
private System.Windows.Forms.Button yesBtn;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user