Merge pull request #1790 from Mbucari/master

Update Avalonia to v12
This commit is contained in:
rmcrackan
2026-05-05 09:39:52 -04:00
committed by GitHub
96 changed files with 788 additions and 762 deletions

View File

@@ -118,6 +118,7 @@ mkdir Libation/.background
mv background.png Libation/.background/
ln -s /Applications "./Libation/ "
mkdir ./bundle
sync
hdiutil create -srcFolder ./Libation -o "./bundle/$DMG_FILE"
# Create a .DS_Store by:
# - mounting an existing image in shadow mode (hdiutil attach Libation.dmg -shadow junk.dmg)

View File

@@ -288,64 +288,64 @@ public static class LibationScaffolding
}
private static void logStartupState(Configuration config)
{
{
#if DEBUG
var mode = "Debug";
var mode = "Debug";
#else
var mode = "Release";
#endif
if (Debugger.IsAttached)
mode += " (Debugger attached)";
if (Debugger.IsAttached)
mode += " (Debugger attached)";
// begin logging session with a form feed
Log.Logger.Information("\r\n\f");
// begin logging session with a form feed
Log.Logger.Information("\r\n\f");
static int fileCount(FileManager.LongPath? longPath)
{
if (longPath is null)
return -1;
try { return FileManager.FileUtility.SaferEnumerateFiles(longPath).Count(); }
catch { return -1; }
}
static int fileCount(FileManager.LongPath? longPath)
{
if (longPath is null)
return -1;
try { return FileManager.FileUtility.SaferEnumerateFiles(longPath).Count(); }
catch { return -1; }
}
Log.Logger.Information("Begin. {@DebugInfo}", new
{
AppName = EntryAssembly?.GetName().Name,
Version = BuildVersion?.ToString(),
ReleaseIdentifier,
Configuration.OS,
Environment.OSVersion,
InteropFactory.InteropFunctionsType,
Mode = mode,
LogLevel_Verbose_Enabled = Log.Logger.IsVerboseEnabled(),
LogLevel_Debug_Enabled = Log.Logger.IsDebugEnabled(),
LogLevel_Information_Enabled = Log.Logger.IsInformationEnabled(),
LogLevel_Warning_Enabled = Log.Logger.IsWarningEnabled(),
LogLevel_Error_Enabled = Log.Logger.IsErrorEnabled(),
LogLevel_Fatal_Enabled = Log.Logger.IsFatalEnabled(),
Log.Logger.Information("Begin. {@DebugInfo}", new
{
AppName = EntryAssembly?.GetName().Name,
Version = BuildVersion?.ToString(),
ReleaseIdentifier,
Configuration.OS,
Environment.OSVersion,
InteropFactory.InteropFunctionsType,
Mode = mode,
LogLevel_Verbose_Enabled = Log.Logger.IsVerboseEnabled(),
LogLevel_Debug_Enabled = Log.Logger.IsDebugEnabled(),
LogLevel_Information_Enabled = Log.Logger.IsInformationEnabled(),
LogLevel_Warning_Enabled = Log.Logger.IsWarningEnabled(),
LogLevel_Error_Enabled = Log.Logger.IsErrorEnabled(),
LogLevel_Fatal_Enabled = Log.Logger.IsFatalEnabled(),
config.AutoScan,
config.BetaOptIn,
config.UseCoverAsFolderIcon,
config.LibationFiles,
AudibleFileStorage.BooksDirectory,
config.AutoScan,
config.BetaOptIn,
config.UseCoverAsFolderIcon,
config.LibationFiles,
AudibleFileStorage.BooksDirectory,
config.InProgress,
config.InProgress,
AudibleFileStorage.DownloadsInProgressDirectory,
DownloadsInProgressFiles = fileCount(AudibleFileStorage.DownloadsInProgressDirectory),
AudibleFileStorage.DownloadsInProgressDirectory,
DownloadsInProgressFiles = fileCount(AudibleFileStorage.DownloadsInProgressDirectory),
AudibleFileStorage.DecryptInProgressDirectory,
DecryptInProgressFiles = fileCount(AudibleFileStorage.DecryptInProgressDirectory),
AudibleFileStorage.DecryptInProgressDirectory,
DecryptInProgressFiles = fileCount(AudibleFileStorage.DecryptInProgressDirectory),
disableIPv6 = AppContext.TryGetSwitch("System.Net.DisableIPv6", out bool disableIPv6Value),
});
disableIPv6 = AppContext.TryGetSwitch("System.Net.DisableIPv6", out bool disableIPv6Value),
});
if (InteropFactory.InteropFunctionsType is null)
Serilog.Log.Logger.Warning("WARNING: OSInteropProxy.InteropFunctionsType is null");
}
if (InteropFactory.InteropFunctionsType is null)
Serilog.Log.Logger.Warning("WARNING: OSInteropProxy.InteropFunctionsType is null");
}
private static void wireUpSystemEvents(Configuration configuration)
private static void wireUpSystemEvents(Configuration configuration)
{
LibraryCommands.LibrarySizeChanged += (object? _, List<DataLayer.LibraryBook> libraryBooks)
=> SearchEngineCommands.FullReIndex(libraryBooks);

View File

@@ -29,7 +29,7 @@ public partial record UpgradeProperties
ZipUrl = zipUrl;
LatestRelease = latestRelease;
var text = NoAppBlockRegex().Replace(notes, "");
var text = NoAppBlockRegex().Replace(notes, "");
text = LinkStripRegex().Replace(text, "$1");
Notes = text.Trim();
}
@@ -37,6 +37,6 @@ public partial record UpgradeProperties
[GeneratedRegex(@"\[(.*)\]\(.*\)")]
private static partial Regex LinkStripRegex();
[GeneratedRegex(@"<!-- BEGIN NO-APP -->.*?<!-- END NO-APP -->", RegexOptions.Singleline)]
private static partial Regex NoAppBlockRegex();
[GeneratedRegex(@"<!-- BEGIN NO-APP -->.*?<!-- END NO-APP -->", RegexOptions.Singleline)]
private static partial Regex NoAppBlockRegex();
}

View File

@@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="AudibleApi" Version="10.1.5.1" />
<PackageReference Include="Google.Protobuf" Version="3.33.5" />
<PackageReference Include="Google.Protobuf" Version="3.34.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -33,7 +33,7 @@ public static class Mkb79AuthImporter
using var persister = AudibleApiStorage.GetAccountsSettingsPersister();
if (persister.AccountsSettings.Accounts.Any(a =>
a.AccountId == account.AccountId && a.IdentityTokens?.Locale.Name == account.Locale?.Name))
a.AccountId == account.AccountId && a.IdentityTokens?.Locale.Name == account.Locale?.Name))
{
return new Mkb79ImportResult(Mkb79ImportOutcome.DuplicateAccount, account);
}

View File

@@ -9,11 +9,11 @@
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,29 +1,26 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DataLayer.Postgres.Migrations;
namespace DataLayer.Postgres.Migrations
/// <inheritdoc />
public partial class ReAddCategoryName2 : Migration
{
/// <inheritdoc />
public partial class ReAddCategoryName2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Name",
table: "Categories",
type: "text",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Name",
table: "Categories",
type: "text",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Name",
table: "Categories");
}
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Name",
table: "Categories");
}
}

View File

@@ -9,11 +9,11 @@
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -1,29 +1,26 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DataLayer.Migrations;
namespace DataLayer.Migrations
/// <inheritdoc />
public partial class ReAddCategoryName2 : Migration
{
/// <inheritdoc />
public partial class ReAddCategoryName2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Name",
table: "Categories",
type: "TEXT",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Name",
table: "Categories",
type: "TEXT",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Name",
table: "Categories");
}
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Name",
table: "Categories");
}
}

View File

@@ -13,13 +13,13 @@
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="10.0.0.1" />
<PackageReference Include="Dinah.EntityFrameworkCore" Version="10.0.0.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.2">
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.2">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="10.0.0.1" />
<PackageReference Include="Polly" Version="8.6.5" />
<PackageReference Include="Polly" Version="8.6.6" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -216,7 +216,7 @@ public static partial class CommonFormatters
public static string Unescape(ReadOnlySpan<char> valueSpan, ReadOnlySpan<char> quoteChars, bool unquoteBackslash = true, bool unescapeDoubleQuotesInsideQuotes = true)
{
if (valueSpan.IsEmpty) return "";
Span<char> search = stackalloc char[quoteChars.Length + 1];
search[0] = '\\';
quoteChars.CopyTo(search[1..]);
@@ -245,8 +245,8 @@ public static partial class CommonFormatters
{
i++; // skip
if (!unescapeDoubleQuotesInsideQuotes ||
i >= valueSpan.Length ||
valueSpan[i] != c)
i >= valueSpan.Length ||
valueSpan[i] != c)
// end block if no 2nd quote follows or doubled quotes don't have special meaning
break;
}

View File

@@ -307,7 +307,8 @@ public partial class ConditionalTagCollection<TClass>(bool caseSensitive = true)
{
var cmp = GetStringComparer(culture);
return e1.OrderBy(e => e, cmp).SequenceEqual(e2.OrderBy(e => e, cmp), cmp);
},
}
,
_ => throw new ArgumentOutOfRangeException() // this should never happen because the regex only allows these values
};
return (v1, v2, culture) => v1 is not null && v2 is not null && checklist(ToEnumerable(v1), ToEnumerable(v2), culture);
@@ -386,7 +387,7 @@ public partial class ConditionalTagCollection<TClass>(bool caseSensitive = true)
{
return StringComparer.Create(culture ?? CultureInfo.CurrentCulture, ignoreCase: true);
}
/// <summary>
/// Build a regular expression check. Uses culture-invariant matching for thread-safety and consistency.
/// Applies a timeout to prevent regex patterns from causing excessive backtracking and blocking.

View File

@@ -63,7 +63,7 @@ public class NamingTemplate
return (_templateToString.DynamicInvoke(delegateArgs) as TemplatePart)!.FirstPart;
}
/// <summary>Parse a template string to a <see cref="NamingTemplate"/></summary>
/// <param name="template">The template string to parse</param>
/// <param name="tagCollections">A collection of <see cref="TagCollection"/> with

View File

@@ -20,10 +20,10 @@ public class PropertyTagCollection<TClass> : TagCollection
var parameters = formatter.Method.GetParameters();
if (formatter.Method.ReturnType != typeof(string)
|| parameters.Length != 4
|| parameters[0].ParameterType != typeof(ITemplateTag)
|| parameters[2].ParameterType != typeof(string)
|| !typeof(CultureInfo).IsAssignableFrom(parameters[3].ParameterType))
|| parameters.Length != 4
|| parameters[0].ParameterType != typeof(ITemplateTag)
|| parameters[2].ParameterType != typeof(string)
|| !typeof(CultureInfo).IsAssignableFrom(parameters[3].ParameterType))
throw new ArgumentException(
$"{nameof(defaultFormatters)} must have a signature of [{nameof(String)} PropertyFormatter<T>({nameof(ITemplateTag)}, T, {nameof(String)}, {nameof(CultureInfo)})]");

View File

@@ -60,7 +60,7 @@ public static class RegExpExtensions
{
// part before match
if (m.Index > pos)
sb.Append(gapEvaluator(input[pos .. m.Index]));
sb.Append(gapEvaluator(input[pos..m.Index]));
// the match itself
sb.Append(matchEvaluator(m));

View File

@@ -3,14 +3,16 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:controls="clr-namespace:HangoverAvalonia.Controls"
xmlns:vms="clr-namespace:HangoverAvalonia.ViewModels"
x:Class="HangoverAvalonia.Controls.CheckedListBox">
<ScrollViewer
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding $parent[1].Items}">
<ItemsControl ItemsSource="{Binding $parent[controls:CheckedListBox].Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate x:DataType="vms:CheckBoxViewModel">
<CheckBox HorizontalAlignment="Stretch" Margin="10,0,0,0" Content="{Binding Item}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>

View File

@@ -70,12 +70,11 @@
<TrimmableAssembly Include="Avalonia.Themes.Default" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="11.3.11" />
<PackageReference Include="Avalonia.Desktop" Version="12.0.2" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.3.11" />
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.8" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.11" />
<PackageReference Include="Tmds.DBus.Protocol" Version="0.21.3" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.3.14" />
<PackageReference Include="ReactiveUI.Avalonia" Version="12.0.1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HangoverBase\HangoverBase.csproj" />

View File

@@ -18,5 +18,5 @@ internal class Program
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace()
.UseReactiveUI();
.UseReactiveUI(_ => { });
}

View File

@@ -4,6 +4,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:HangoverAvalonia.Controls"
xmlns:vms="clr-namespace:HangoverAvalonia.ViewModels"
x:DataType="vms:MainVM"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="500"
Width="800" Height="500"
x:Class="HangoverAvalonia.Views.MainWindow"

View File

@@ -89,7 +89,7 @@
</Style>
<Style Selector="dialogs|DialogWindow">
<Setter Property="SystemDecorations" Value="Full"/>
<Setter Property="WindowDecorations" Value="Full"/>
<Setter Property="Icon" Value="/Assets/libation.ico"/>
<Setter Property="Template">
<ControlTemplate>

View File

@@ -47,9 +47,6 @@ public class App : Application
MessageBoxBase.ShowAsyncImpl = (owner, message, caption, buttons, icon, defaultButton, saveAndRestorePosition) =>
MessageBox.Show(owner as Window, message, caption, buttons, icon, defaultButton, saveAndRestorePosition);
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
if (LibraryTask is null)
{
RunSetupIfNeededAsync(desktop, Configuration.Instance);
@@ -114,19 +111,6 @@ public class App : Application
LibationScaffolding.RunPostMigrationScaffolding(Variety.Chardonnay, config);
}
private void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
DataAnnotationsValidationPlugin[] dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (DataAnnotationsValidationPlugin? plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
private static void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop)
{
Configuration.Instance.PropertyChanged += ThemeVariant_PropertyChanged;

View File

@@ -24,7 +24,7 @@ internal static class AvaloniaUtils
: Task.FromResult(DialogResult.None);
public static Window GetParentWindow(this Control control)
=> control.GetVisualRoot() as Window ?? App.MainWindow
=> TopLevel.GetTopLevel(control) as Window ?? App.MainWindow
?? throw new InvalidOperationException("Cannot find parent window.");

View File

@@ -3,14 +3,15 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:Class="LibationAvalonia.Controls.CheckedListBox">
<ScrollViewer
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding $parent[1].Items}">
<ItemsControl ItemsSource="{Binding $parent[controls:CheckedListBox].Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate x:DataType="controls:CheckBoxViewModel">
<CheckBox HorizontalAlignment="Stretch" Margin="10,0,0,0" Content="{Binding Item}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>

View File

@@ -7,8 +7,8 @@ namespace LibationAvalonia.Controls;
public class DataGridMyRatingColumn : DataGridBoundColumn
{
[AssignBinding] public IBinding? BackgroundBinding { get; set; }
[AssignBinding] public IBinding? OpacityBinding { get; set; }
[AssignBinding] public BindingBase? BackgroundBinding { get; set; }
[AssignBinding] public BindingBase? OpacityBinding { get; set; }
private static Rating DefaultRating => new Rating(0, 0, 0);
public DataGridMyRatingColumn()
{

View File

@@ -3,6 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:DataType="controls:DirectoryOrCustomSelectControl"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="LibationAvalonia.Controls.DirectoryOrCustomSelectControl">
@@ -39,7 +40,7 @@
Margin="0,0,0,8"
Name="tboxKnownDirPath"
IsEnabled="{Binding #rbKnown.IsChecked}"
Text="{Binding #cmbKnownDirs.SelectedItem.Directory}" />
Text="{Binding #cmbKnownDirs.((controls:KnownDirectoryItem)SelectedItem).Directory}"/>
<RadioButton
@@ -53,7 +54,7 @@
Name="tboxCustomDirPath"
Margin="0,0,10,0"
VerticalAlignment="Center"
Text="{Binding $parent[1].Directory, Mode=OneWayToSource}"
Text="{Binding $parent[controls:DirectoryOrCustomSelectControl].Directory, Mode=OneWayToSource}"
IsEnabled="{Binding #rbCustom.IsChecked}"/>
<Button

View File

@@ -124,57 +124,54 @@ public partial class DirectoryOrCustomSelectControl : UserControl
public async void Browse_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (VisualRoot is not Window window)
return;
var options = new FolderPickerOpenOptions
{
AllowMultiple = false
};
var selectedFolders = await window.StorageProvider.OpenFolderPickerAsync(options);
var selectedFolders = await this.GetParentWindow().StorageProvider.OpenFolderPickerAsync(options);
Directory = selectedFolders.SingleOrDefault()?.TryGetLocalPath() ?? Directory;
}
private class KnownDirectoryItem : ReactiveObject
{
public Configuration.KnownDirectories KnownDirectory { get; set; }
public string? Directory { get => field; set => this.RaiseAndSetIfChanged(ref field, value); }
public string? Name { get; }
public string? SubDirectory
{
get => field;
set
{
field = value;
if (Configuration.GetKnownDirectoryPath(KnownDirectory) is string dir)
{
Directory = Path.Combine(dir, field ?? "");
}
}
}
public KnownDirectoryItem(Configuration.KnownDirectories known, string? subDir)
{
Name = known.GetDescription();
KnownDirectory = known;
SubDirectory = subDir;
}
public bool IsSamePathAs(string? otherPath)
{
if (string.IsNullOrWhiteSpace(otherPath) || string.IsNullOrWhiteSpace(Directory))
return false;
try
{
var p1 = Path.GetFullPath(Directory);
var p2 = Path.GetFullPath(otherPath);
return p1.Equals(p2, System.StringComparison.OrdinalIgnoreCase);
}
catch { return false; }
}
public override string? ToString() => Name?.ToString();
}
}
public class KnownDirectoryItem : ReactiveObject
{
public Configuration.KnownDirectories KnownDirectory { get; set; }
public string? Directory { get => field; set => this.RaiseAndSetIfChanged(ref field, value); }
public string? Name { get; }
public string? SubDirectory
{
get => field;
set
{
field = value;
if (Configuration.GetKnownDirectoryPath(KnownDirectory) is string dir)
{
Directory = Path.Combine(dir, field ?? "");
}
}
}
public KnownDirectoryItem(Configuration.KnownDirectories known, string? subDir)
{
Name = known.GetDescription();
KnownDirectory = known;
SubDirectory = subDir;
}
public bool IsSamePathAs(string? otherPath)
{
if (string.IsNullOrWhiteSpace(otherPath) || string.IsNullOrWhiteSpace(Directory))
return false;
try
{
var p1 = Path.GetFullPath(Directory);
var p2 = Path.GetFullPath(otherPath);
return p1.Equals(p2, System.StringComparison.OrdinalIgnoreCase);
}
catch { return false; }
}
public override string? ToString() => Name?.ToString();
}

View File

@@ -18,13 +18,13 @@
<Setter Property="Height" Value="NaN"/>
</Style>
</StackPanel.Styles>
<!-- MinHeight="{Binding #displayPathTbox.MinHeight}" -->
<controls:WheelComboBox
HorizontalContentAlignment = "Stretch"
HorizontalAlignment = "Stretch"
Name="combo"
MinHeight="{Binding #displayPathTbox.MinHeight}"
SelectedItem="{Binding $parent[1].SelectedDirectory, Mode=TwoWay}"
ItemsSource="{Binding $parent[1].KnownDirectories}">
SelectedItem="{Binding $parent[controls:DirectorySelectControl].SelectedDirectory, Mode=TwoWay}"
ItemsSource="{Binding $parent[controls:DirectorySelectControl].KnownDirectories}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource KnownDirectoryConverter}}" />
@@ -36,7 +36,7 @@
<MultiBinding Converter="{StaticResource KnownDirectoryPath}">
<MultiBinding.Bindings>
<Binding Path="#combo.SelectedItem"/>
<Binding Path="$parent[1].SubDirectory"/>
<Binding Path="$parent[controls:DirectorySelectControl].SubDirectory"/>
</MultiBinding.Bindings>
</MultiBinding>
</TextBox.Text>

View File

@@ -30,29 +30,26 @@ public partial class Audio : UserControl
if (!accounts.AccountsSettings.Accounts.All(a => a.IdentityTokens?.DeviceType == AudibleApi.Resources.DeviceType))
{
if (VisualRoot is Window parent)
{
var choice = await MessageBox.Show(parent,
"In order to enable widevine content, Libation will need to log into your accounts again.\r\n\r\n" +
"Do you want Libation to clear your current account settings and prompt you to login before the next download?",
"Widevine Content Unavailable",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2);
var choice = await MessageBox.Show(this.GetParentWindow(),
"In order to enable widevine content, Libation will need to log into your accounts again.\r\n\r\n" +
"Do you want Libation to clear your current account settings and prompt you to login before the next download?",
"Widevine Content Unavailable",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2);
if (choice == DialogResult.Yes)
if (choice == DialogResult.Yes)
{
foreach (var account in accounts.AccountsSettings.Accounts.ToArray())
{
foreach (var account in accounts.AccountsSettings.Accounts.ToArray())
if (account.Locale is not null && account.IdentityTokens?.DeviceType != AudibleApi.Resources.DeviceType)
{
if (account.Locale is not null && account.IdentityTokens?.DeviceType != AudibleApi.Resources.DeviceType)
{
accounts.AccountsSettings.Delete(account);
var acc = accounts.AccountsSettings.Upsert(account.AccountId, account.Locale.Name);
acc.AccountName = account.AccountName;
}
accounts.AccountsSettings.Delete(account);
var acc = accounts.AccountsSettings.Upsert(account.AccountId, account.Locale.Name);
acc.AccountName = account.AccountName;
}
return;
}
return;
}
_viewModel?.UseWidevine = false;

View File

@@ -12,7 +12,7 @@
<controls:GroupBox
Grid.Row="0"
Margin="5"
Label="{CompiledBinding BadBookGroupboxText}">
Label="{Binding BadBookGroupboxText}">
<Grid
ColumnDefinitions="*,*"
@@ -29,36 +29,36 @@
<RadioButton
Grid.Column="0"
Grid.Row="0"
IsChecked="{CompiledBinding BadBookAsk, Mode=TwoWay}">
IsChecked="{Binding BadBookAsk, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookAskText}" />
<TextBlock Text="{Binding BadBookAskText}" />
</RadioButton>
<RadioButton
Grid.Column="1"
Grid.Row="0"
IsChecked="{CompiledBinding BadBookAbort, Mode=TwoWay}">
IsChecked="{Binding BadBookAbort, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookAbortText}" />
<TextBlock Text="{Binding BadBookAbortText}" />
</RadioButton>
<RadioButton
Grid.Column="0"
Grid.Row="1"
IsChecked="{CompiledBinding BadBookRetry, Mode=TwoWay}">
IsChecked="{Binding BadBookRetry, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookRetryText}" />
<TextBlock Text="{Binding BadBookRetryText}" />
</RadioButton>
<RadioButton
Grid.Column="1"
Grid.Row="1"
IsChecked="{CompiledBinding BadBookIgnore, Mode=TwoWay}">
IsChecked="{Binding BadBookIgnore, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding BadBookIgnoreText}" />
<TextBlock Text="{Binding BadBookIgnoreText}" />
</RadioButton>
</Grid>
@@ -90,12 +90,12 @@
Grid.Row="0"
Grid.Column="0"
Margin="0,5,0,0"
Text="{CompiledBinding FolderTemplateText}" />
Text="{Binding FolderTemplateText}" />
<TextBox
Grid.Row="1"
Grid.Column="0"
Text="{CompiledBinding FolderTemplate}" />
Text="{Binding FolderTemplate}" />
<Button
Grid.Row="1"
@@ -106,12 +106,12 @@
<TextBlock
Grid.Row="2"
Grid.Column="0"
Text="{CompiledBinding FileTemplateText}" />
Text="{Binding FileTemplateText}" />
<TextBox
Grid.Row="3"
Grid.Column="0"
Text="{CompiledBinding FileTemplate}" />
Text="{Binding FileTemplate}" />
<Button
Grid.Row="3"
@@ -122,12 +122,12 @@
<TextBlock
Grid.Row="4"
Grid.Column="0"
Text="{CompiledBinding ChapterFileTemplateText}" />
Text="{Binding ChapterFileTemplateText}" />
<TextBox
Grid.Row="5"
Grid.Column="0"
Text="{CompiledBinding ChapterFileTemplate}" />
Text="{Binding ChapterFileTemplate}" />
<Button
Grid.Row="5"
@@ -140,7 +140,7 @@
Grid.Column="0"
Height="30"
Margin="0"
Content="{CompiledBinding EditCharReplacementText}"
Content="{Binding EditCharReplacementText}"
Click="EditCharReplacementButton_Click" />
</Grid>
@@ -156,11 +156,11 @@
<TextBlock
Margin="0,0,0,10"
TextWrapping="Wrap"
Text="{CompiledBinding InProgressDescriptionText}" />
Text="{Binding InProgressDescriptionText}" />
<controls:DirectoryOrCustomSelectControl
Directory="{CompiledBinding InProgressDirectory, Mode=TwoWay}"
KnownDirectories="{CompiledBinding KnownDirectories}" />
Directory="{Binding InProgressDirectory, Mode=TwoWay}"
KnownDirectories="{Binding KnownDirectories}" />
</StackPanel>
</controls:GroupBox>
@@ -172,23 +172,23 @@
<CheckBox
Margin="5"
VerticalAlignment="Top"
IsVisible="{CompiledBinding !Config.IsLinux}"
IsChecked="{CompiledBinding UseCoverAsFolderIcon, Mode=TwoWay}">
IsVisible="{Binding !Config.IsLinux}"
IsChecked="{Binding UseCoverAsFolderIcon, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{CompiledBinding UseCoverAsFolderIconText}" />
Text="{Binding UseCoverAsFolderIconText}" />
</CheckBox>
<CheckBox
Margin="5"
VerticalAlignment="Top"
IsChecked="{CompiledBinding SaveMetadataToFile, Mode=TwoWay}">
IsChecked="{Binding SaveMetadataToFile, Mode=TwoWay}">
<TextBlock
TextWrapping="Wrap"
Text="{CompiledBinding SaveMetadataToFileText}" />
Text="{Binding SaveMetadataToFileText}" />
</CheckBox>
</StackPanel>

View File

@@ -18,29 +18,29 @@
</Style>
</StackPanel.Styles>
<CheckBox IsChecked="{CompiledBinding AutoScan, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding AutoScanText}" />
<CheckBox IsChecked="{Binding AutoScan, Mode=TwoWay}">
<TextBlock Text="{Binding AutoScanText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding ShowImportedStats, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding ShowImportedStatsText}" />
<CheckBox IsChecked="{Binding ShowImportedStats, Mode=TwoWay}">
<TextBlock Text="{Binding ShowImportedStatsText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding ImportEpisodes, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding ImportEpisodesText}" />
<CheckBox IsChecked="{Binding ImportEpisodes, Mode=TwoWay}">
<TextBlock Text="{Binding ImportEpisodesText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding ImportPlusTitles, Mode=TwoWay}"
ToolTip.Tip="{CompiledBinding ImportPlusTitlesTip}">
<TextBlock Text="{CompiledBinding ImportPlusTitlesText}" />
<CheckBox IsChecked="{Binding ImportPlusTitles, Mode=TwoWay}"
ToolTip.Tip="{Binding ImportPlusTitlesTip}">
<TextBlock Text="{Binding ImportPlusTitlesText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding DownloadEpisodes, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding DownloadEpisodesText}" />
<CheckBox IsChecked="{Binding DownloadEpisodes, Mode=TwoWay}">
<TextBlock Text="{Binding DownloadEpisodesText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding AutoDownloadEpisodes, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding AutoDownloadEpisodesText}" />
<CheckBox IsChecked="{Binding AutoDownloadEpisodes, Mode=TwoWay}">
<TextBlock Text="{Binding AutoDownloadEpisodesText}" />
</CheckBox>
</StackPanel>
</UserControl>

View File

@@ -17,19 +17,19 @@
<StackPanel>
<TextBlock
Margin="5"
Text="{CompiledBinding BooksText}" />
Text="{Binding BooksText}" />
<controls:DirectoryOrCustomSelectControl Margin="0,10,0,10"
SubDirectory="Books"
Directory="{CompiledBinding BooksDirectory, Mode=TwoWay}"
KnownDirectories="{CompiledBinding KnownDirectories}" />
Directory="{Binding BooksDirectory, Mode=TwoWay}"
KnownDirectories="{Binding KnownDirectories}" />
<CheckBox IsChecked="{CompiledBinding SavePodcastsToParentFolder, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding SavePodcastsToParentFolderText}" />
<CheckBox IsChecked="{Binding SavePodcastsToParentFolder, Mode=TwoWay}">
<TextBlock Text="{Binding SavePodcastsToParentFolderText}" />
</CheckBox>
<CheckBox IsChecked="{CompiledBinding OverwriteExisting, Mode=TwoWay}">
<TextBlock Text="{CompiledBinding OverwriteExistingText}" />
<CheckBox IsChecked="{Binding OverwriteExisting, Mode=TwoWay}">
<TextBlock Text="{Binding OverwriteExistingText}" />
</CheckBox>
<Grid
@@ -39,21 +39,21 @@
<TextBlock
VerticalAlignment="Center"
Margin="0,0,10,0"
Text="{CompiledBinding CreationTimeText}" />
Text="{Binding CreationTimeText}" />
<controls:WheelComboBox
Height="25"
Grid.Column="1"
Margin="0,5"
HorizontalContentAlignment="Stretch"
SelectedItem="{CompiledBinding CreationTime, Mode=TwoWay}"
ItemsSource="{CompiledBinding DateTimeSources}" />
SelectedItem="{Binding CreationTime, Mode=TwoWay}"
ItemsSource="{Binding DateTimeSources}" />
<TextBlock
VerticalAlignment="Center"
Grid.Row="1"
Margin="0,0,10,0"
Text="{CompiledBinding LastWriteTimeText}" />
Text="{Binding LastWriteTimeText}" />
<controls:WheelComboBox
Height="25"
@@ -61,8 +61,8 @@
Grid.Column="1"
Margin="0,5"
HorizontalContentAlignment="Stretch"
SelectedItem="{CompiledBinding LastWriteTime, Mode=TwoWay}"
ItemsSource="{CompiledBinding DateTimeSources}" />
SelectedItem="{Binding LastWriteTime, Mode=TwoWay}"
ItemsSource="{Binding DateTimeSources}" />
</Grid>
@@ -72,16 +72,16 @@
<CheckBox
Grid.Row="1"
Margin="10,5"
IsEnabled="{CompiledBinding !UseWebViewSettingDisabled}"
IsChecked="{CompiledBinding UseWebView, Mode=TwoWay}">
IsEnabled="{Binding !UseWebViewSettingDisabled}"
IsChecked="{Binding UseWebView, Mode=TwoWay}">
<StackPanel>
<TextBlock Text="{CompiledBinding UseWebViewText}" />
<TextBlock Text="{Binding UseWebViewText}" />
<TextBlock
IsVisible="{CompiledBinding UseWebViewSettingDisabled}"
IsVisible="{Binding UseWebViewSettingDisabled}"
FontStyle="Italic"
Opacity="0.8"
Margin="0,2,0,0"
Text="{CompiledBinding UseWebViewSnapMessage}" />
Text="{Binding UseWebViewSnapMessage}" />
</StackPanel>
</CheckBox>
@@ -98,15 +98,15 @@
Width="120"
Height="25"
HorizontalContentAlignment="Stretch"
SelectedItem="{CompiledBinding LoggingLevel, Mode=TwoWay}"
ItemsSource="{CompiledBinding LoggingLevels}" />
SelectedItem="{Binding LoggingLevel, Mode=TwoWay}"
ItemsSource="{Binding LoggingLevels}" />
<Button
Margin="50,0,0,0"
Padding="20,0"
VerticalAlignment="Stretch"
Content="Open Log Folder"
Command="{CompiledBinding OpenLogFolderButton}" />
Command="{Binding OpenLogFolderButton}" />
</StackPanel>
@@ -121,12 +121,12 @@
<TextBlock
Margin="0,0,10,0"
VerticalAlignment="Center"
Text="{CompiledBinding GridScaleFactorText}"/>
Text="{Binding GridScaleFactorText}"/>
<Slider
Grid.Column="1"
Width="200"
Value="{CompiledBinding GridScaleFactor, Mode=TwoWay}"
Value="{Binding GridScaleFactor, Mode=TwoWay}"
VerticalAlignment="Center"
Minimum="-100"
Maximum="100"
@@ -139,13 +139,13 @@
Margin="0,0,10,0"
Grid.Row="1"
VerticalAlignment="Center"
Text="{CompiledBinding GridFontScaleFactorText}"/>
Text="{Binding GridFontScaleFactorText}"/>
<Slider
Grid.Column="1"
Grid.Row="1"
Width="200"
Value="{CompiledBinding GridFontScaleFactor, Mode=TwoWay}"
Value="{Binding GridFontScaleFactor, Mode=TwoWay}"
VerticalAlignment="Center"
Minimum="-100"
Maximum="100"
@@ -161,7 +161,7 @@
Padding="20,0"
VerticalAlignment="Stretch"
Content="Apply Display Settings"
Command="{CompiledBinding ApplyDisplaySettings}"/>
Command="{Binding ApplyDisplaySettings}"/>
</Grid>
</controls:GroupBox>
@@ -181,8 +181,8 @@
Name="ThemeComboBox"
Grid.Column="1"
MinWidth="80"
SelectedItem="{CompiledBinding ThemeVariant, Mode=TwoWay}"
ItemsSource="{CompiledBinding Themes}"/>
SelectedItem="{Binding ThemeVariant, Mode=TwoWay}"
ItemsSource="{Binding Themes}"/>
<Button
Grid.Column="2"

View File

@@ -5,6 +5,7 @@
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="650"
xmlns:views="clr-namespace:LibationAvalonia.Views"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
x:DataType="controls:ThemePreviewControl"
x:Class="LibationAvalonia.Controls.ThemePreviewControl">
<Grid RowDefinitions="Auto,Auto,*">
<controls:GroupBox>

View File

@@ -7,6 +7,8 @@
Width="450" Height="540"
x:Class="LibationAvalonia.Dialogs.AboutDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:AboutVM"
Title="About Libation">
<Grid Margin="10" RowDefinitions="Auto,Auto,Auto,Auto,*">

View File

@@ -4,6 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Width="800" Height="450"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:AccountsDialog"
x:Class="LibationAvalonia.Dialogs.AccountsDialog"
Title="Audible Accounts">
<Grid RowDefinitions="*,Auto">

View File

@@ -5,6 +5,8 @@
mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="450"
Width="700" Height="450"
x:Class="LibationAvalonia.Dialogs.BookRecordsDialog"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:BookRecordsDialog"
Title="BookRecordsDialog">
<Grid RowDefinitions="*,Auto">
@@ -28,45 +30,52 @@
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridCheckBoxColumn
Width="Auto"
IsReadOnly="False"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding IsChecked, Mode=TwoWay}"
Header="Checked"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding Type}"
Header="Type"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding Created}"
Header="Created"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding Start}"
Header="Start"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding Modified}"
Header="Modified"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding End}"
Header="End"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding Note}"
Header="Note"/>
<DataGridTextColumn
Width="Auto"
IsReadOnly="True"
x:DataType="dialogs:BookRecordsDialog+BookRecordEntry"
Binding="{Binding Title}"
Header="Title"/>

View File

@@ -202,7 +202,7 @@ public partial class BookRecordsDialog : DialogWindow
#region DataGrid Bindings
private class BookRecordEntry : ViewModels.ViewModelBase
public class BookRecordEntry : ViewModels.ViewModelBase
{
private const string DateFormat = "yyyy-MM-dd HH\\:mm";
public IRecord Record { get; }

View File

@@ -4,7 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="540" d:DesignHeight="140"
x:Class="LibationAvalonia.Dialogs.DescriptionDisplayDialog"
SystemDecorations="None"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:DescriptionDisplayDialog"
WindowDecorations="None"
Title="DescriptionDisplay">
<Window.Styles>

View File

@@ -46,7 +46,7 @@ public partial class DescriptionDisplayDialog : Window
this.Position = new PixelPoint((int)SpawnLocation.X, (int)Math.Min(SpawnLocation.Y, workingHeight - DescriptionTextBox.DesiredSize.Height));
}
private void DescriptionTextBox_LostFocus(object sender, Avalonia.Interactivity.RoutedEventArgs e)
private void DescriptionTextBox_LostFocus(object sender, Avalonia.Input.FocusChangedEventArgs e)
{
Close();
}

View File

@@ -21,9 +21,8 @@ public abstract class DialogWindow : Window
{
SaveAndRestorePosition = saveAndRestorePosition;
KeyDown += DialogWindow_KeyDown;
Initialized += DialogWindow_Initialized;
Opened += DialogWindow_Opened;
Loaded += DialogWindow_Loaded;
Opened += DialogWindow_Opened;
Closing += DialogWindow_Closing;
if (Design.IsDesignMode)
@@ -38,12 +37,6 @@ public abstract class DialogWindow : Window
}
}
private void DialogWindow_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
if (!CanResize)
this.HideMinMaxBtns();
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@@ -51,12 +44,14 @@ public abstract class DialogWindow : Window
if (MinHeight == MaxHeight && MinWidth == MaxWidth)
{
CanResize = false;
CanMinimize = false;
CanMaximize = false;
Height = MinHeight;
Width = MinWidth;
}
}
private void DialogWindow_Initialized(object? sender, EventArgs e)
private void DialogWindow_Loaded(object? sender, EventArgs e)
{
this.WindowStartupLocation = WindowStartupLocation.CenterOwner;
if (SaveAndRestorePosition)

View File

@@ -16,7 +16,7 @@
CanUserSortColumns="False"
AutoGenerateColumns="False"
IsReadOnly="False"
ItemsSource="{CompiledBinding Filters}"
ItemsSource="{Binding Filters}"
GridLinesVisibility="All">
<DataGrid.Columns>
@@ -29,7 +29,7 @@
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
IsEnabled="{CompiledBinding !IsDefault}"
IsEnabled="{Binding !IsDefault}"
Click="DeleteButton_Clicked" />
</DataTemplate>
@@ -39,13 +39,13 @@
<DataGridTextColumn
Width="*"
IsReadOnly="False"
Binding="{CompiledBinding Name, Mode=TwoWay}"
Binding="{Binding Name, Mode=TwoWay}"
Header="Name"/>
<DataGridTextColumn
Width="*"
IsReadOnly="False"
Binding="{CompiledBinding FilterString, Mode=TwoWay}"
Binding="{Binding FilterString, Mode=TwoWay}"
Header="Filter"/>
<DataGridTemplateColumn Header="Move&#xa;Up">
@@ -60,8 +60,8 @@
Click="MoveUpButton_Clicked">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<CompiledBinding Path="!IsTop" />
<CompiledBinding Path="!IsDefault" />
<Binding Path="!IsTop" />
<Binding Path="!IsDefault" />
</MultiBinding>
</Button.IsEnabled>
</Button>
@@ -82,8 +82,8 @@
Click="MoveDownButton_Clicked">
<Button.IsEnabled>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<CompiledBinding Path="!IsBottom" />
<CompiledBinding Path="!IsDefault" />
<Binding Path="!IsBottom" />
<Binding Path="!IsDefault" />
</MultiBinding>
</Button.IsEnabled>
</Button>

View File

@@ -86,7 +86,7 @@ public partial class EditQuickFilters : DialogWindow
ReIndexFilters();
}
protected override void SaveAndClose()
public new void SaveAndClose()
{
QuickFilters.ReplaceAll(Filters.Select(x => x.AsNamedFilter()).OfType<QuickFilters.NamedFilter>());
base.SaveAndClose();

View File

@@ -21,13 +21,13 @@
Grid.Column="0"
Grid.Row="0"
Margin="0,0,0,10"
Text="{CompiledBinding Description}" />
Text="{Binding Description}" />
<TextBox
Grid.Column="0"
Grid.Row="1"
Name="userEditTbox"
Text="{CompiledBinding UserTemplateText, Mode=TwoWay}" />
Text="{Binding UserTemplateText, Mode=TwoWay}" />
<Button
Grid.Column="1"
@@ -36,7 +36,7 @@
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
Content="Reset to Default"
Command="{CompiledBinding ResetToDefault}"/>
Command="{Binding ResetToDefault}"/>
</Grid>
<Grid Grid.Row="1" ColumnDefinitions="Auto,*"
Margin="0,0,0,10">
@@ -49,13 +49,13 @@
GridLinesVisibility="All"
AutoGenerateColumns="False"
DoubleTapped="EditTemplateViewModel_DoubleTapped"
ItemsSource="{CompiledBinding ListItems}" >
ItemsSource="{Binding ListItems}" >
<DataGrid.Columns>
<DataGridTemplateColumn Width="Auto" Header="Tag">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="18" Margin="10,0,10,0" VerticalAlignment="Center" Text="{CompiledBinding Item1}" />
<TextBlock Height="18" Margin="10,0,10,0" VerticalAlignment="Center" Text="{Binding Item1}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -66,7 +66,7 @@
<TextBlock
Height="18"
Margin="10,0,10,0"
VerticalAlignment="Center" Text="{CompiledBinding Item2}" />
VerticalAlignment="Center" Text="{Binding Item2}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
@@ -91,7 +91,7 @@
<TextBlock
TextWrapping="WrapWithOverflow"
Inlines="{CompiledBinding Inlines}" />
Inlines="{Binding Inlines}" />
</Border>
@@ -99,8 +99,8 @@
Grid.Row="2"
Margin="5"
Foreground="Firebrick"
Text="{CompiledBinding WarningText}"
IsVisible="{CompiledBinding WarningText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
Text="{Binding WarningText}"
IsVisible="{Binding WarningText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</Grid>
</Grid>
<controls:LinkLabel

View File

@@ -19,10 +19,10 @@
CanUserSortColumns="True"
AutoGenerateColumns="False"
IsReadOnly="True"
ItemsSource="{CompiledBinding Books}">
ItemsSource="{Binding Books}">
<DataGrid.Styles>
<Style x:DataType="vm:BookDataViewModel" Selector="DataGridRow">
<Setter Property="Background" Value="{CompiledBinding ScanStatus, Converter={x:Static dialogs:FindBetterQualityBooksDialog.RowConverter }}" />
<Setter Property="Background" Value="{Binding ScanStatus, Converter={x:Static dialogs:FindBetterQualityBooksDialog.RowConverter }}" />
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
@@ -30,51 +30,51 @@
<DataGridTextColumn
Width="120"
IsReadOnly="False"
Binding="{CompiledBinding Asin}"
Binding="{Binding Asin}"
Header="ASIN"/>
<DataGridTextColumn
Width="120"
IsReadOnly="True"
Binding="{CompiledBinding Title}"
Binding="{Binding Title}"
Header="Title"/>
<DataGridTextColumn
Width="120"
IsReadOnly="True"
Binding="{CompiledBinding FoundFile}"
Binding="{Binding FoundFile}"
Header="Best Found File"/>
<DataGridTextColumn
Width="90"
IsReadOnly="True"
Binding="{CompiledBinding Codec}"
Binding="{Binding Codec}"
Header="Existing&#xa;Codec"/>
<DataGridTextColumn
Width="90"
IsReadOnly="True"
SortMemberPath="Bitrate"
Binding="{CompiledBinding BitrateString}"
Binding="{Binding BitrateString}"
Header="Existing&#xa;Bitrate"/>
<DataGridTextColumn
Width="90"
IsReadOnly="True"
Binding="{CompiledBinding AvailableCodec}"
Binding="{Binding AvailableCodec}"
Header="Available&#xa;Codec"/>
<DataGridTextColumn
Width="90"
IsReadOnly="True"
SortMemberPath="AvailableBitrate"
Binding="{CompiledBinding AvailableBitrateString}"
Binding="{Binding AvailableBitrateString}"
Header="Available&#xa;Bitrate"/>
<DataGridCheckBoxColumn
Width="90"
IsReadOnly="True"
Binding="{CompiledBinding IsSignificant}"
Binding="{Binding IsSignificant}"
Header="Significantly&#xa;Greater?"/>
</DataGrid.Columns>

View File

@@ -7,6 +7,8 @@
MinWidth="500" MinHeight="500"
Width="500" Height="520"
Title="Cover"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:ImageDisplayDialog+BitmapHolder"
WindowStartupLocation="CenterOwner">
<Image Stretch="Uniform" Source="{Binding CoverImage}">

View File

@@ -8,6 +8,8 @@
Width="800" Height="165"
x:Class="LibationAvalonia.Dialogs.LibationFilesDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:LibationFilesDialog+DirSelectOptions"
WindowStartupLocation="CenterScreen"
Title="Book Details">

View File

@@ -8,7 +8,7 @@ namespace LibationAvalonia.Dialogs;
public partial class LibationFilesDialog : DialogWindow, ILibationInstallLocation
{
private class DirSelectOptions
public class DirSelectOptions
{
public List<Configuration.KnownDirectories> KnownDirectories { get; } = new()
{

View File

@@ -9,6 +9,8 @@
MinHeight="135" MaxHeight="135"
MinWidth="550" MaxWidth="550"
Width="550" Height="135"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:LiberatedStatusBatchAutoDialog"
WindowStartupLocation="CenterOwner">
<Grid Margin="10" RowDefinitions="Auto,Auto">

View File

@@ -11,4 +11,8 @@ public partial class LiberatedStatusBatchAutoDialog : DialogWindow
DataContext = this;
ControlToFocusOnShow = SaveButton;
}
// For compiled bindings
public new void SaveAndClose() => base.SaveAndClose();
}

View File

@@ -9,6 +9,8 @@
MinWidth="400" MinHeight="100"
MaxWidth="400" MaxHeight="100"
Width="400" Height="100"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:LiberatedStatusBatchManualDialog"
WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="Auto,Auto" ColumnDefinitions="*,Auto">

View File

@@ -6,7 +6,7 @@ namespace LibationAvalonia.Dialogs;
public partial class LiberatedStatusBatchManualDialog : DialogWindow
{
private class liberatedComboBoxItem
public class liberatedComboBoxItem
{
public LiberatedStatus Status { get; set; }
public string? Text { get; set; }
@@ -27,11 +27,11 @@ public partial class LiberatedStatusBatchManualDialog : DialogWindow
}
}
public IList BookStatuses { get; } = new List<liberatedComboBoxItem>
{
public List<liberatedComboBoxItem> BookStatuses { get; } =
[
new liberatedComboBoxItem { Status = LiberatedStatus.Liberated, Text = "Downloaded" },
new liberatedComboBoxItem { Status = LiberatedStatus.NotLiberated, Text = "Not Downloaded" },
};
];
public LiberatedStatusBatchManualDialog(bool isPdf) : this()
{
@@ -42,7 +42,7 @@ public partial class LiberatedStatusBatchManualDialog : DialogWindow
public LiberatedStatusBatchManualDialog()
{
InitializeComponent();
SelectedItem = BookStatuses[0] as liberatedComboBoxItem;
SelectedItem = BookStatuses[0];
DataContext = this;
ControlToFocusOnShow = SaveButton;
}

View File

@@ -8,6 +8,8 @@
CanResize="True"
WindowStartupLocation="CenterOwner"
x:Class="LibationAvalonia.Dialogs.Login.LoginExternalDialog"
xmlns:login="clr-namespace:LibationAvalonia.Dialogs.Login"
x:DataType="login:LoginExternalDialog"
Title="Audible Login External">
<Grid RowDefinitions="Auto,Auto,2*,Auto,*" ColumnDefinitions="*" Margin="5">

View File

@@ -1,5 +1,6 @@
using AudibleUtilities;
using Avalonia.Controls;
using Avalonia.Input.Platform;
using Dinah.Core;
using System;
using System.Linq;

View File

@@ -8,6 +8,8 @@
Width="600" Height="450"
x:Class="LibationAvalonia.Dialogs.MessageBoxAlertAdminDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:MessageBoxAlertAdminDialog"
Title="MessageBoxAlertAdminDialog"
WindowStartupLocation="CenterOwner">

View File

@@ -5,9 +5,11 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d" d:DesignWidth="265" d:DesignHeight="110"
MinWidth="265" MinHeight="110"
CanMaximize="False"
CanMinimize="False"
x:DataType="vm:MessageBoxViewModel"
x:Class="LibationAvalonia.Dialogs.MessageBoxWindow"
Title="{CompiledBinding Caption}" ShowInTaskbar="True">
Title="{Binding Caption}" ShowInTaskbar="True">
<Grid ColumnDefinitions="*" RowDefinitions="*,Auto">
@@ -18,19 +20,19 @@
<Panel Height="32" Width="32" Grid.Column="0" Margin="5,0,5,0" VerticalAlignment="Top">
<Panel.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<CompiledBinding Path="IsAsterisk" />
<CompiledBinding Path="IsError" />
<CompiledBinding Path="IsQuestion" />
<CompiledBinding Path="IsExclamation" />
<Binding Path="IsAsterisk" />
<Binding Path="IsError" />
<Binding Path="IsQuestion" />
<Binding Path="IsExclamation" />
</MultiBinding>
</Panel.IsVisible>
<Image IsVisible="{CompiledBinding IsAsterisk}" Stretch="Uniform" Source="/Assets/MBIcons/Asterisk_64.png"/>
<Image IsVisible="{CompiledBinding IsError}" Stretch="Uniform" Source="/Assets/MBIcons/Error_64.png"/>
<Image IsVisible="{CompiledBinding IsQuestion}" Stretch="Uniform" Source="/Assets/MBIcons/Question_64.png"/>
<Image IsVisible="{CompiledBinding IsExclamation}" Stretch="Uniform" Source="/Assets/MBIcons/Exclamation_64.png"/>
<Image IsVisible="{Binding IsAsterisk}" Stretch="Uniform" Source="/Assets/MBIcons/Asterisk_64.png"/>
<Image IsVisible="{Binding IsError}" Stretch="Uniform" Source="/Assets/MBIcons/Error_64.png"/>
<Image IsVisible="{Binding IsQuestion}" Stretch="Uniform" Source="/Assets/MBIcons/Question_64.png"/>
<Image IsVisible="{Binding IsExclamation}" Stretch="Uniform" Source="/Assets/MBIcons/Exclamation_64.png"/>
</Panel>
<TextBlock Margin="5,0,0,0" Name="messageTextBlock" MinHeight="45" MinWidth="193" TextWrapping="WrapWithOverflow" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="12" Text="{CompiledBinding Message}" />
<TextBlock Margin="5,0,0,0" Name="messageTextBlock" MinHeight="45" MinWidth="193" TextWrapping="WrapWithOverflow" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="12" Text="{Binding Message}" />
</StackPanel>
</DockPanel>
@@ -38,13 +40,13 @@
<DockPanel Height="45" Grid.Row="1" Background="{DynamicResource SystemChromeMediumLowColor}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="5" DockPanel.Dock="Bottom">
<Button Grid.Column="0" MinWidth="75" MinHeight="28" Name="Button1" Click="Button1_Click" Margin="5">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{CompiledBinding Button1Text}"/>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Button1Text}"/>
</Button>
<Button Grid.Column="1" IsVisible="{CompiledBinding HasButton2}" MinWidth="75" MinHeight="28" Name="Button2" Click="Button2_Click" Margin="5">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{CompiledBinding Button2Text}"/>
<Button Grid.Column="1" IsVisible="{Binding HasButton2}" MinWidth="75" MinHeight="28" Name="Button2" Click="Button2_Click" Margin="5">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Button2Text}"/>
</Button>
<Button Grid.Column="2" IsVisible="{CompiledBinding HasButton3}" MinWidth="75" MinHeight="28" Name="Button3" Click="Button3_Click" Margin="5">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{CompiledBinding Button3Text}"/>
<Button Grid.Column="2" IsVisible="{Binding HasButton3}" MinWidth="75" MinHeight="28" Name="Button3" Click="Button3_Click" Margin="5">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Button3Text}"/>
</Button>
</StackPanel>
</DockPanel>

View File

@@ -49,26 +49,26 @@
<Grid Grid.Row="1" RowDefinitions="Auto,Auto,*">
<TextBlock Text="STRING FIELDS" />
<TextBlock Grid.Row="1" Text="{CompiledBinding StringUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{CompiledBinding StringFields}"/>
<TextBlock Grid.Row="1" Text="{Binding StringUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{Binding StringFields}"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="1" RowDefinitions="Auto,Auto,*">
<TextBlock Text="NUMBER FIELDS" />
<TextBlock Grid.Row="1" Text="{CompiledBinding NumberUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{CompiledBinding NumberFields}"/>
<TextBlock Grid.Row="1" Text="{Binding NumberUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{Binding NumberFields}"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="2" RowDefinitions="Auto,Auto,*">
<TextBlock Text="BOOLEAN (TRUE/FALSE) FIELDS" />
<TextBlock Grid.Row="1" Text="{CompiledBinding BoolUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{CompiledBinding BoolFields}"/>
<TextBlock Grid.Row="1" Text="{Binding BoolUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{Binding BoolFields}"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="3" RowDefinitions="Auto,Auto,*">
<TextBlock Text="ID FIELDS" />
<TextBlock Grid.Row="1" Text="{CompiledBinding IdUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{CompiledBinding IdFields}"/>
<TextBlock Grid.Row="1" Text="{Binding IdUsage}" />
<ListBox Grid.Row="2" DoubleTapped="ListBox_DoubleTapped" ItemsSource="{Binding IdFields}"/>
</Grid>
</Grid>
</Window>

View File

@@ -49,7 +49,7 @@
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:Important DataContext="{CompiledBinding ImportantSettings}" />
<settings:Important DataContext="{Binding ImportantSettings, Mode=OneTime}" />
</ScrollViewer>
</TabItem>
<TabItem>
@@ -58,7 +58,7 @@
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:Import DataContext="{CompiledBinding ImportSettings}" />
<settings:Import DataContext="{Binding ImportSettings, Mode=OneTime}" />
</ScrollViewer>
</TabItem>
@@ -68,7 +68,7 @@
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:DownloadDecrypt DataContext="{CompiledBinding DownloadDecryptSettings}" />
<settings:DownloadDecrypt DataContext="{Binding DownloadDecryptSettings, Mode=OneTime}" />
</ScrollViewer>
</TabItem>
@@ -77,7 +77,7 @@
<TextBlock Text="Audio File Settings"/>
</TabItem.Header>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<settings:Audio DataContext="{CompiledBinding AudioSettings}" />
<settings:Audio DataContext="{Binding AudioSettings, Mode=OneTime}" />
</ScrollViewer>
</TabItem>
</TabControl>

View File

@@ -4,6 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="630" d:DesignHeight="90"
x:Class="LibationAvalonia.Dialogs.TagsBatchDialog"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:TagsBatchDialog"
MinWidth="630" MinHeight="90"
MaxWidth="630" MaxHeight="90"
Width="630" Height="110"

View File

@@ -12,4 +12,7 @@ public partial class TagsBatchDialog : DialogWindow
DataContext = this;
}
// For compiled bindings
public new void SaveAndClose() => base.SaveAndClose();
}

View File

@@ -6,6 +6,8 @@
Width="965" Height="850"
x:Class="LibationAvalonia.Dialogs.ThemePickerDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:ThemePickerDialog"
Title="Theme Editor">
<Grid ColumnDefinitions="Auto,*">

View File

@@ -14,7 +14,7 @@ namespace LibationAvalonia.Dialogs;
public partial class ThemePickerDialog : DialogWindow
{
protected DataGridCollectionView ThemeColors { get; }
public AvaloniaList<ThemeItemColor> ThemeColors { get; }
private ChardonnayTheme ExistingTheme { get; } = ChardonnayTheme.GetLiveTheme();
private ChardonnayTheme WorkingTheme { get; set; }
@@ -38,7 +38,7 @@ public partial class ThemePickerDialog : DialogWindow
}
}
protected async Task ImportTheme()
public async Task ImportTheme()
{
try
{
@@ -74,7 +74,7 @@ public partial class ThemePickerDialog : DialogWindow
}
}
protected async Task ExportTheme()
public async Task ExportTheme()
{
try
{
@@ -110,22 +110,24 @@ public partial class ThemePickerDialog : DialogWindow
}
}
protected override void CancelAndClose()
public new void CancelAndClose()
{
ExistingTheme.ApplyTheme(ActualThemeVariant);
base.CancelAndClose();
}
protected void ResetColors()
public void ResetColors()
=> ResetTheme(ExistingTheme);
protected void LoadDefaultColors()
public void LoadDefaultColors()
{
if (App.DefaultThemeColors is ChardonnayTheme defaults)
ResetTheme(defaults);
}
protected override async Task SaveAndCloseAsync()
public new async Task SaveAndCloseAsync()
{
using (var themePersister = ChardonnayThemePersister.Create())
{
@@ -174,7 +176,7 @@ public partial class ThemePickerDialog : DialogWindow
WorkingTheme.ApplyTheme(ActualThemeVariant);
}
private class ThemeItemColor : ViewModels.ViewModelBase
public class ThemeItemColor : ViewModels.ViewModelBase
{
public required string ThemeItemName { get; init; }
public required Action<Color, string>? ColorSetter { get; set; }

View File

@@ -34,7 +34,7 @@
DisableContextMenu="True"
DisableColumnCustomization="True"
IsEnabled="{Binding $parent.((dialogs:TrashBinViewModel)DataContext).ControlsEnabled}"
DataContext="{Binding ProductsDisplay}" />
DataContext="{Binding ProductsDisplay, Mode=OneTime}" />
<Grid
Margin="0,5,0,0"

View File

@@ -5,6 +5,8 @@
mc:Ignorable="d" d:DesignWidth="550" d:DesignHeight="450"
x:Class="LibationAvalonia.Dialogs.UpgradeNotificationDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:dialogs="clr-namespace:LibationAvalonia.Dialogs"
x:DataType="dialogs:UpgradeNotificationDialog"
MinWidth="500" MinHeight="400"
Height="450" Width="550"
WindowStartupLocation="CenterOwner"

View File

@@ -111,62 +111,4 @@ public static class FormSaveExtension
public int Width;
public bool IsMaximized;
}
public static void HideMinMaxBtns(this Window form)
{
if (Design.IsDesignMode || !Configuration.IsWindows || form.TryGetPlatformHandle() is not IPlatformHandle handle)
return;
var windowStyle
= GetWindowStyle(handle.Handle)
.Remove(WINDOW_STYLE.WS_MINIMIZEBOX)
.Remove(WINDOW_STYLE.WS_MAXIMIZEBOX);
SetWindowStyle(handle.Handle, windowStyle);
}
const int GWL_STYLE = -16;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetWindowLong")]
static extern long GetWindowLong(IntPtr hWnd, int nIndex);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowLong")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, long dwNewLong);
static WINDOW_STYLE GetWindowStyle(IntPtr hWnd) => (WINDOW_STYLE)GetWindowLong(hWnd, GWL_STYLE);
static void SetWindowStyle(IntPtr hWnd, WINDOW_STYLE style) => SetWindowLong(hWnd, GWL_STYLE, (long)style);
[Flags]
enum WINDOW_STYLE : long
{
WS_OVERLAPPED = 0x0,
WS_TILED = 0x0,
WS_ACTIVECAPTION = 0x1,
WS_MAXIMIZEBOX = 0x10000,
WS_TABSTOP = 0x10000,
WS_MINIMIZEBOX = 0x20000,
WS_GROUP = 0x20000,
WS_THICKFRAME = 0x40000,
WS_SIZEBOX = 0x40000,
WS_SYSMENU = 0x80000,
WS_HSCROLL = 0x100000,
WS_VSCROLL = 0x200000,
WS_DLGFRAME = 0x400000,
WS_BORDER = 0x800000,
WS_CAPTION = 0xc00000,
WS_OVERLAPPEDWINDOW = 0xcf0000,
WS_TILEDWINDOW = 0xcf0000,
WS_MAXIMIZE = 0x1000000,
WS_CLIPCHILDREN = 0x2000000,
WS_CLIPSIBLINGS = 0x4000000,
WS_DISABLED = 0x8000000,
WS_VISIBLE = 0x10000000,
WS_ICONIC = 0x20000000,
WS_MINIMIZE = 0x20000000,
WS_CHILD = 0x40000000,
WS_CHILDWINDOW = 0x40000000,
WS_POPUP = 0x80000000,
WS_POPUPWINDOW = 0x80880000
}
}

View File

@@ -12,7 +12,6 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Nullable>enable</Nullable>
<StartupObject />
</PropertyGroup>
<ItemGroup>
@@ -73,14 +72,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Controls.ColorPicker" Version="11.3.11" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.11" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.3.11" />
<PackageReference Include="Avalonia.Desktop" Version="11.3.11" />
<PackageReference Include="ReactiveUI.Avalonia" Version="11.3.8" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.11" />
<PackageReference Include="WebViewControlAvaloniaFree" Version="11.3.16" />
<PackageReference Include="Tmds.DBus.Protocol" Version="0.21.3" />
<PackageReference Include="Avalonia.Controls.ColorPicker" Version="12.0.2" />
<PackageReference Include="Avalonia.Controls.WebView" Version="12.0.0" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.14" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="12.0.0" />
<PackageReference Include="Avalonia.Desktop" Version="12.0.2" />
<PackageReference Include="ReactiveUI.Avalonia" Version="12.0.1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -189,7 +189,7 @@ public class MessageBox
IsVisible = false,
Height = 1,
Width = 1,
SystemDecorations = SystemDecorations.None,
WindowDecorations = WindowDecorations.None,
ShowInTaskbar = false
};

View File

@@ -89,7 +89,7 @@ static class Program
return AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace()
.UseReactiveUI()
.UseReactiveUI(_ => { })
.AfterSetup(_ => SetupLock.Exit());
}
}

View File

@@ -26,7 +26,7 @@ partial class MainVM
private void Configure_Filters()
{
FirstFilterIsDefault = QuickFilters.UseDefault;
MainWindow.Initialized += updateFiltersMenu;
MainWindow.Loaded += updateFiltersMenu;
QuickFilters.Updated += updateFiltersMenu;
//We need to be able to dynamically add and remove menu items from the Quick Filters menu.

View File

@@ -36,7 +36,7 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Padding="0"
IsEnabled="{CompiledBinding IsButtonEnabled}" Click="Button_Click" >
IsEnabled="{Binding IsButtonEnabled}" Click="Button_Click" >
<Grid RowDefinitions="*,8*,*">
<Viewbox
@@ -45,31 +45,31 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Panel>
<Panel IsVisible="{CompiledBinding !IsError}">
<Panel IsVisible="{Binding !IsError}">
<Panel IsVisible="{CompiledBinding IsSeries}">
<Path IsVisible="{CompiledBinding Expanded}" Data="{StaticResource CollapseIcon}" />
<Path IsVisible="{CompiledBinding !Expanded}" Data="{StaticResource ExpandIcon}" />
<Panel IsVisible="{Binding IsSeries}">
<Path IsVisible="{Binding Expanded}" Data="{StaticResource CollapseIcon}" />
<Path IsVisible="{Binding !Expanded}" Data="{StaticResource ExpandIcon}" />
</Panel>
<Grid
IsVisible="{CompiledBinding !IsSeries}"
IsVisible="{Binding !IsSeries}"
HorizontalAlignment="Center"
ColumnDefinitions="Auto,Auto">
<Canvas Width="29.44" Height="64">
<Rectangle Canvas.Left="5" Canvas.Top="5" IsVisible="{CompiledBinding RedVisible}" Fill="{DynamicResource StoplightRed}" />
<Rectangle Canvas.Left="5" Canvas.Top="23" IsVisible="{CompiledBinding YellowVisible}" Fill="{DynamicResource StoplightYellow}" />
<Rectangle Canvas.Left="5" Canvas.Top="42" IsVisible="{CompiledBinding GreenVisible}" Fill="{DynamicResource StoplightGreen}" />
<Rectangle Canvas.Left="5" Canvas.Top="5" IsVisible="{Binding RedVisible}" Fill="{DynamicResource StoplightRed}" />
<Rectangle Canvas.Left="5" Canvas.Top="23" IsVisible="{Binding YellowVisible}" Fill="{DynamicResource StoplightYellow}" />
<Rectangle Canvas.Left="5" Canvas.Top="42" IsVisible="{Binding GreenVisible}" Fill="{DynamicResource StoplightGreen}" />
<Path Height="64" Stretch="Uniform" Data="{StaticResource StoplightBodyIcon}"/>
</Canvas>
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfDownloadedVisible}" Data="{StaticResource PdfDownloadedIcon}"/>
<Path Grid.Column="1" IsVisible="{CompiledBinding PdfNotDownloadedVisible}" Data="{StaticResource PdfNotDownloadedIcon}"/>
<Path Grid.Column="1" IsVisible="{Binding PdfDownloadedVisible}" Data="{StaticResource PdfDownloadedIcon}"/>
<Path Grid.Column="1" IsVisible="{Binding PdfNotDownloadedVisible}" Data="{StaticResource PdfNotDownloadedIcon}"/>
</Grid>
</Panel>
<Path
Stretch="None" Width="64"
IsVisible="{CompiledBinding IsError}"
IsVisible="{Binding IsError}"
Fill="{DynamicResource CancelRed}"
Data="{StaticResource BookErrorIcon}" />
</Panel>

View File

@@ -19,56 +19,56 @@
<NativeMenu>
<NativeMenuItem
Header="Auto Scan Library"
Command="{CompiledBinding ToggleAutoScan}"
IsChecked="{CompiledBinding AutoScanChecked}"
Command="{Binding ToggleAutoScan}"
IsChecked="{Binding AutoScanChecked}"
ToggleType="CheckBox" />
<NativeMenuItemSeparator />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Liberate">
<NativeMenu>
<NativeMenuItem Command="{CompiledBinding BackupAllBooks}" Header="{CompiledBinding BookBackupsToolStripText}" Gesture="{OnPlatform macOS='alt+⌘+B'}" />
<NativeMenuItem Command="{CompiledBinding BackupAllPdfs}" Header="{CompiledBinding PdfBackupsToolStripText}" Gesture="{OnPlatform macOS='alt+⌘+P'}"/>
<NativeMenuItem Command="{CompiledBinding ConvertAllToMp3Async}" Header="Convert all M4b to Mp3 [Long-running]..." />
<NativeMenuItem Command="{CompiledBinding LiberateVisible}" Header="{CompiledBinding LiberateVisibleToolStripText}" IsEnabled="{CompiledBinding AnyVisibleNotLiberated}" />
<NativeMenuItem Command="{Binding BackupAllBooks}" Header="{Binding BookBackupsToolStripText}" Gesture="{OnPlatform macOS='alt+⌘+B'}" />
<NativeMenuItem Command="{Binding BackupAllPdfs}" Header="{Binding PdfBackupsToolStripText}" Gesture="{OnPlatform macOS='alt+⌘+P'}"/>
<NativeMenuItem Command="{Binding ConvertAllToMp3Async}" Header="Convert all M4b to Mp3 [Long-running]..." />
<NativeMenuItem Command="{Binding LiberateVisible}" Header="{Binding LiberateVisibleToolStripText}" IsEnabled="{Binding AnyVisibleNotLiberated}" />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Export">
<NativeMenu>
<NativeMenuItem Command="{CompiledBinding ExportLibraryAsync}" Header="Export Library" Gesture="{OnPlatform macOS='alt+⌘+X'}"/>
<NativeMenuItem Command="{Binding ExportLibraryAsync}" Header="Export Library" Gesture="{OnPlatform macOS='alt+⌘+X'}"/>
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Quick Filters">
<NativeMenu>
<NativeMenuItem
Header="Start Libation with 1st filter Default"
Command="{CompiledBinding ToggleFirstFilterIsDefault}"
IsChecked="{CompiledBinding FirstFilterIsDefault}"
Command="{Binding ToggleFirstFilterIsDefault}"
IsChecked="{Binding FirstFilterIsDefault}"
ToggleType="CheckBox" />
<NativeMenuItem Command="{CompiledBinding EditQuickFiltersAsync}" Header="Edit quick filters..." Gesture="{OnPlatform macOS='alt+⌘+Q'}" />
<NativeMenuItem Command="{Binding EditQuickFiltersAsync}" Header="Edit quick filters..." Gesture="{OnPlatform macOS='alt+⌘+Q'}" />
<NativeMenuItemSeparator />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Visible Books">
<NativeMenu>
<NativeMenuItem Command="{CompiledBinding LiberateVisible}" Header="{CompiledBinding LiberateVisibleToolStripText_2}" IsEnabled="{CompiledBinding AnyVisibleNotLiberated}" Gesture="{OnPlatform macOS='alt+⌘+V'}" />
<NativeMenuItem Command="{CompiledBinding ReplaceTagsAsync}" Header="Replace Tags..." />
<NativeMenuItem Command="{CompiledBinding SetBookDownloadedAsync}" Header="Set book 'Downloaded' status manually..." />
<NativeMenuItem Command="{CompiledBinding SetPdfDownloadedAsync}" Header="Set PDF 'Downloaded' status manually..." />
<NativeMenuItem Command="{CompiledBinding SetDownloadedAutoAsync}" Header="Set 'Downloaded' status automatically..." />
<NativeMenuItem Command="{CompiledBinding RemoveVisibleAsync}" Header="Remove from library..." />
<NativeMenuItem Command="{Binding LiberateVisible}" Header="{Binding LiberateVisibleToolStripText_2}" IsEnabled="{Binding AnyVisibleNotLiberated}" Gesture="{OnPlatform macOS='alt+⌘+V'}" />
<NativeMenuItem Command="{Binding ReplaceTagsAsync}" Header="Replace Tags..." />
<NativeMenuItem Command="{Binding SetBookDownloadedAsync}" Header="Set book 'Downloaded' status manually..." />
<NativeMenuItem Command="{Binding SetPdfDownloadedAsync}" Header="Set PDF 'Downloaded' status manually..." />
<NativeMenuItem Command="{Binding SetDownloadedAutoAsync}" Header="Set 'Downloaded' status automatically..." />
<NativeMenuItem Command="{Binding RemoveVisibleAsync}" Header="Remove from library..." />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Settings">
<NativeMenu>
<NativeMenuItem Command="{CompiledBinding ShowAccountsAsync}" Header="Accounts..." Gesture="{OnPlatform macOS='⌘+.'}" />
<NativeMenuItem Command="{CompiledBinding ShowSettingsAsync}" Header="Settings..." Gesture="{OnPlatform macOS='⌘+,'}" />
<NativeMenuItem Command="{Binding ShowAccountsAsync}" Header="Accounts..." Gesture="{OnPlatform macOS='⌘+.'}" />
<NativeMenuItem Command="{Binding ShowSettingsAsync}" Header="Settings..." Gesture="{OnPlatform macOS='⌘+,'}" />
<NativeMenuItemSeparator />
<NativeMenuItem Command="{CompiledBinding ShowTrashBinAsync}" Header="Trash Bin" Gesture="{OnPlatform macOS='alt+⌘+T'}" />
<NativeMenuItem Command="{CompiledBinding LaunchHangover}" Header="Launch Hangover" />
<NativeMenuItem Command="{Binding ShowTrashBinAsync}" Header="Trash Bin" Gesture="{OnPlatform macOS='alt+⌘+T'}" />
<NativeMenuItem Command="{Binding LaunchHangover}" Header="Launch Hangover" />
<NativeMenuItemSeparator />
<NativeMenuItem Command="{CompiledBinding StartWalkthroughAsync}" Header="Take a Guided Tour of Libation" />
<NativeMenuItem Command="{CompiledBinding ShowAboutAsync}" Header="About..." />
<NativeMenuItem Command="{Binding StartWalkthroughAsync}" Header="Take a Guided Tour of Libation" />
<NativeMenuItem Command="{Binding ShowAboutAsync}" Header="About..." />
</NativeMenu>
</NativeMenuItem>
</NativeMenu>
@@ -78,7 +78,7 @@
<Border Grid.Row="0" BorderBrush="{DynamicResource SystemBaseLowColor}" BorderThickness="0,1">
<Grid ColumnDefinitions="*,Auto">
<!-- Menu Strip -->
<Menu VerticalAlignment="Top" IsVisible="{CompiledBinding MenuBarVisible}">
<Menu VerticalAlignment="Top" IsVisible="{Binding MenuBarVisible}">
<!-- Decrease height of menu strop -->
<Menu.Styles>
@@ -90,80 +90,80 @@
<!-- Import Menu -->
<MenuItem Name="importToolStripMenuItem" Header="_Import">
<MenuItem IsVisible="{CompiledBinding AnyAccounts}" Command="{CompiledBinding ToggleAutoScan}" Header="A_uto Scan Library">
<MenuItem IsVisible="{Binding AnyAccounts}" Command="{Binding ToggleAutoScan}" Header="A_uto Scan Library">
<MenuItem.Icon>
<CheckBox BorderThickness="0" IsChecked="{CompiledBinding AutoScanChecked, Mode=TwoWay}" IsHitTestVisible="False" />
<CheckBox BorderThickness="0" IsChecked="{Binding AutoScanChecked, Mode=TwoWay}" IsHitTestVisible="False" />
</MenuItem.Icon>
</MenuItem>
<MenuItem IsVisible="{CompiledBinding !AnyAccounts}" Command="{CompiledBinding AddAccountsAsync}" Header="No accounts yet. A_dd Account..." />
<MenuItem IsVisible="{Binding !AnyAccounts}" Command="{Binding AddAccountsAsync}" Header="No accounts yet. A_dd Account..." />
<!-- Scan Library -->
<MenuItem IsVisible="{CompiledBinding OneAccount}" IsEnabled="{CompiledBinding !ActivelyScanning}" Name="scanLibraryToolStripMenuItem" Command="{CompiledBinding ScanAccountAsync}" Header="Scan _Library" />
<MenuItem IsVisible="{CompiledBinding MultipleAccounts}" IsEnabled="{CompiledBinding !ActivelyScanning}" Name="scanLibraryOfAllAccountsToolStripMenuItem" Command="{CompiledBinding ScanAllAccountsAsync}" Header="Scan Library of _All Accounts" />
<MenuItem IsVisible="{CompiledBinding MultipleAccounts}" IsEnabled="{CompiledBinding !ActivelyScanning}" Command="{CompiledBinding ScanSomeAccountsAsync}" Header="Scan Library of _Some Accounts" />
<MenuItem IsVisible="{Binding OneAccount}" IsEnabled="{Binding !ActivelyScanning}" Name="scanLibraryToolStripMenuItem" Command="{Binding ScanAccountAsync}" Header="Scan _Library" />
<MenuItem IsVisible="{Binding MultipleAccounts}" IsEnabled="{Binding !ActivelyScanning}" Name="scanLibraryOfAllAccountsToolStripMenuItem" Command="{Binding ScanAllAccountsAsync}" Header="Scan Library of _All Accounts" />
<MenuItem IsVisible="{Binding MultipleAccounts}" IsEnabled="{Binding !ActivelyScanning}" Command="{Binding ScanSomeAccountsAsync}" Header="Scan Library of _Some Accounts" />
<Separator IsVisible="{CompiledBinding AnyAccounts}" />
<Separator IsVisible="{Binding AnyAccounts}" />
<!-- Remove Books -->
<MenuItem IsVisible="{CompiledBinding OneAccount}" IsEnabled="{CompiledBinding RemoveMenuItemsEnabled}" Command="{CompiledBinding RemoveBooksAsync}" Header="_Remove Library Books" />
<MenuItem IsVisible="{CompiledBinding MultipleAccounts}" IsEnabled="{CompiledBinding RemoveMenuItemsEnabled}" Command="{CompiledBinding RemoveBooksAllAsync}" Header="_Remove Books from All Accounts" />
<MenuItem IsVisible="{CompiledBinding MultipleAccounts}" IsEnabled="{CompiledBinding RemoveMenuItemsEnabled}" Command="{CompiledBinding RemoveBooksSomeAsync}" Header="_Remove Books from Some Accounts" />
<MenuItem IsVisible="{Binding OneAccount}" IsEnabled="{Binding RemoveMenuItemsEnabled}" Command="{Binding RemoveBooksAsync}" Header="_Remove Library Books" />
<MenuItem IsVisible="{Binding MultipleAccounts}" IsEnabled="{Binding RemoveMenuItemsEnabled}" Command="{Binding RemoveBooksAllAsync}" Header="_Remove Books from All Accounts" />
<MenuItem IsVisible="{Binding MultipleAccounts}" IsEnabled="{Binding RemoveMenuItemsEnabled}" Command="{Binding RemoveBooksSomeAsync}" Header="_Remove Books from Some Accounts" />
<Separator />
<MenuItem Command="{CompiledBinding LocateAudiobooksAsync}" Header="L_ocate Audiobooks..." ToolTip.Tip="{CompiledBinding LocateAudiobooksTip}" />
<MenuItem Command="{Binding LocateAudiobooksAsync}" Header="L_ocate Audiobooks..." ToolTip.Tip="{Binding LocateAudiobooksTip}" />
</MenuItem>
<!-- Liberate Menu -->
<MenuItem Header="_Liberate">
<MenuItem Command="{CompiledBinding BackupAllBooks}" Header="{CompiledBinding BookBackupsToolStripText}" />
<MenuItem Command="{CompiledBinding BackupAllPdfs}" Header="{CompiledBinding PdfBackupsToolStripText}" />
<MenuItem Command="{CompiledBinding ConvertAllToMp3Async}" Header="Convert all _M4b to Mp3 [Long-running]..." />
<MenuItem Command="{CompiledBinding LiberateVisible}" Header="{CompiledBinding LiberateVisibleToolStripText}" IsEnabled="{CompiledBinding AnyVisibleNotLiberated}" />
<MenuItem Command="{Binding BackupAllBooks}" Header="{Binding BookBackupsToolStripText}" />
<MenuItem Command="{Binding BackupAllPdfs}" Header="{Binding PdfBackupsToolStripText}" />
<MenuItem Command="{Binding ConvertAllToMp3Async}" Header="Convert all _M4b to Mp3 [Long-running]..." />
<MenuItem Command="{Binding LiberateVisible}" Header="{Binding LiberateVisibleToolStripText}" IsEnabled="{Binding AnyVisibleNotLiberated}" />
</MenuItem>
<!-- Export Menu -->
<MenuItem Header="E_xport">
<!-- Remove height style property for menu item -->
<MenuItem IsEnabled="{CompiledBinding LibraryStats.HasBookResults}" Command="{CompiledBinding ExportLibraryAsync}" Header="E_xport Library" InputGesture="ctrl+S" />
<MenuItem IsEnabled="{Binding LibraryStats?.HasBookResults, TargetNullValue=false}" Command="{Binding ExportLibraryAsync}" Header="E_xport Library" InputGesture="ctrl+S" />
</MenuItem>
<!-- Quick Filters Menu -->
<MenuItem Name="quickFiltersToolStripMenuItem" Header="Quick _Filters" ItemsSource="{CompiledBinding QuickFilterMenuItems}" />
<MenuItem Name="quickFiltersToolStripMenuItem" Header="Quick _Filters" ItemsSource="{Binding QuickFilterMenuItems}" />
<!-- Visible Books Menu -->
<MenuItem Header="{CompiledBinding VisibleCountMenuItemText}" >
<MenuItem Command="{CompiledBinding LiberateVisible}" Header="{CompiledBinding LiberateVisibleToolStripText_2}" IsEnabled="{CompiledBinding AnyVisibleNotLiberated}" />
<MenuItem Command="{CompiledBinding ReplaceTagsAsync}" Header="Replace _Tags..." />
<MenuItem Command="{CompiledBinding SetBookDownloadedAsync}" Header="Set book '_Downloaded' status manually..." />
<MenuItem Command="{CompiledBinding SetPdfDownloadedAsync}" Header="Set _PDF 'Downloaded' status manually..." />
<MenuItem Command="{CompiledBinding SetDownloadedAutoAsync}" Header="Set '_Downloaded' status automatically..." />
<MenuItem Command="{CompiledBinding RemoveVisibleAsync}" Header="_Remove from library..." />
<MenuItem Header="{Binding VisibleCountMenuItemText}" >
<MenuItem Command="{Binding LiberateVisible}" Header="{Binding LiberateVisibleToolStripText_2}" IsEnabled="{Binding AnyVisibleNotLiberated}" />
<MenuItem Command="{Binding ReplaceTagsAsync}" Header="Replace _Tags..." />
<MenuItem Command="{Binding SetBookDownloadedAsync}" Header="Set book '_Downloaded' status manually..." />
<MenuItem Command="{Binding SetPdfDownloadedAsync}" Header="Set _PDF 'Downloaded' status manually..." />
<MenuItem Command="{Binding SetDownloadedAutoAsync}" Header="Set '_Downloaded' status automatically..." />
<MenuItem Command="{Binding RemoveVisibleAsync}" Header="_Remove from library..." />
</MenuItem>
<!-- Settings Menu -->
<MenuItem Header="_Settings" Name="settingsToolStripMenuItem">
<MenuItem Name="accountsToolStripMenuItem" Command="{CompiledBinding ShowAccountsAsync}" Header="_Accounts..." InputGesture="ctrl+shift+A"/>
<MenuItem Name="basicSettingsToolStripMenuItem" Command="{CompiledBinding ShowSettingsAsync}" Header="_Settings..." InputGesture="ctrl+P" />
<MenuItem Name="accountsToolStripMenuItem" Command="{Binding ShowAccountsAsync}" Header="_Accounts..." InputGesture="ctrl+shift+A"/>
<MenuItem Name="basicSettingsToolStripMenuItem" Command="{Binding ShowSettingsAsync}" Header="_Settings..." InputGesture="ctrl+P" />
<Separator />
<MenuItem Command="{CompiledBinding ShowTrashBinAsync}" Header="Trash Bin" />
<MenuItem Command="{CompiledBinding LaunchHangover}" Header="Launch _Hangover" />
<MenuItem Command="{Binding ShowTrashBinAsync}" Header="Trash Bin" />
<MenuItem Command="{Binding LaunchHangover}" Header="Launch _Hangover" />
<Separator />
<MenuItem Command="{CompiledBinding ShowFindBetterQualityBooksAsync}" Header="Scan for Better Quality Audiobooks" ToolTip.Tip="{CompiledBinding FindBetterQualityBooksTip}"/>
<MenuItem Command="{Binding ShowFindBetterQualityBooksAsync}" Header="Scan for Better Quality Audiobooks" ToolTip.Tip="{Binding FindBetterQualityBooksTip}"/>
<Separator />
<MenuItem Command="{CompiledBinding StartWalkthroughAsync}" Header="Take a Guided _Tour of Libation" />
<MenuItem Command="{CompiledBinding ShowAboutAsync}" Header="A_bout..." />
<MenuItem Command="{Binding StartWalkthroughAsync}" Header="Take a Guided _Tour of Libation" />
<MenuItem Command="{Binding ShowAboutAsync}" Header="A_bout..." />
</MenuItem>
</Menu>
<StackPanel IsVisible="{CompiledBinding ActivelyScanning}" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<StackPanel IsVisible="{Binding ActivelyScanning}" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Path VerticalAlignment="Center" Fill="{DynamicResource IconFill}" Data="{StaticResource ImportIcon}" />
<TextBlock Margin="5,0,5,0" VerticalAlignment="Center" Text="{CompiledBinding ScanningText}"/>
<TextBlock Margin="5,0,5,0" VerticalAlignment="Center" Text="{Binding ScanningText}"/>
</StackPanel>
</Grid>
</Border>
@@ -182,21 +182,21 @@
</Style>
</Grid.Styles>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<Button Name="filterHelpBtn" Margin="0" Command="{CompiledBinding FilterHelpBtn}" Content="?"/>
<Button Name="addQuickFilterBtn" Command="{CompiledBinding AddQuickFilterBtn}" Content="Add To Quick Filters"/>
<StackPanel Grid.Column="0" IsVisible="{Binding !RemoveButtonsVisible}" Orientation="Horizontal">
<Button Name="filterHelpBtn" Margin="0" Command="{Binding FilterHelpBtn}" Content="?"/>
<Button Name="addQuickFilterBtn" Command="{Binding AddQuickFilterBtn}" Content="Add To Quick Filters"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button IsVisible="{CompiledBinding RemoveButtonsVisible}" IsEnabled="{CompiledBinding RemoveBooksButtonEnabled}" Command="{CompiledBinding RemoveBooksBtn}" Content="{CompiledBinding RemoveBooksButtonText}"/>
<Button IsVisible="{CompiledBinding RemoveButtonsVisible}" Command="{CompiledBinding DoneRemovingBtn}" Content="Done Removing Books"/>
<Button IsVisible="{Binding RemoveButtonsVisible}" IsEnabled="{Binding RemoveBooksButtonEnabled}" Command="{Binding RemoveBooksBtn}" Content="{Binding RemoveBooksButtonText}"/>
<Button IsVisible="{Binding RemoveButtonsVisible}" Command="{Binding DoneRemovingBtn}" Content="Done Removing Books"/>
</StackPanel>
<Grid
Grid.Column="1"
Margin="10,0,0,0"
ColumnDefinitions="*,Auto"
IsVisible="{CompiledBinding !RemoveButtonsVisible}">
IsVisible="{Binding !RemoveButtonsVisible}">
<TextBox
Grid.Column="0"
Name="filterSearchTb"
@@ -204,7 +204,7 @@
InnerRightContent="{x:Null}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Text="{CompiledBinding SelectedNamedFilter.Filter, Mode=OneWay}"
Text="{Binding SelectedNamedFilter.Filter, Mode=OneWay}"
KeyDown="filterSearchTb_KeyPress" />
<Button
Grid.Column="1"
@@ -218,11 +218,11 @@
</Grid>
<StackPanel Grid.Column="2" Height="30" Orientation="Horizontal">
<Button Name="filterBtn" Command="{CompiledBinding FilterBtn}" CommandParameter="{CompiledBinding #filterSearchTb.Text}" VerticalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Content="Filter"/>
<Button Padding="2,6" VerticalAlignment="Stretch" Command="{CompiledBinding ToggleQueueHideBtn}">
<Button Name="filterBtn" IsVisible="{Binding !RemoveButtonsVisible}" Command="{Binding FilterBtn}" CommandParameter="{Binding #filterSearchTb.Text}" VerticalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Content="Filter"/>
<Button Padding="2,6" VerticalAlignment="Stretch" Command="{Binding ToggleQueueHideBtn}">
<Path Stretch="Uniform" Fill="{DynamicResource IconFill}" Data="{StaticResource LeftArrows}">
<Path.RenderTransform>
<RotateTransform Angle="{CompiledBinding QueueButtonAngle}"/>
<RotateTransform Angle="{Binding QueueButtonAngle}"/>
</Path.RenderTransform>
</Path>
</Button>
@@ -231,19 +231,19 @@
</Grid>
<Border Grid.Row="2" Margin="8,0" BorderThickness="1" BorderBrush="{DynamicResource SystemBaseMediumLowColor}">
<SplitView IsPaneOpen="{CompiledBinding QueueOpen}" DisplayMode="Inline" OpenPaneLength="400" MinWidth="400" PanePlacement="Right">
<SplitView IsPaneOpen="{Binding QueueOpen}" DisplayMode="Inline" OpenPaneLength="400" MinWidth="400" PanePlacement="Right">
<!-- Process Queue -->
<SplitView.Pane>
<Border BorderThickness="1,0,0,0" BorderBrush="{DynamicResource SystemBaseMediumLowColor}">
<views:ProcessQueueControl DataContext="{CompiledBinding ProcessQueue}"/>
<views:ProcessQueueControl DataContext="{Binding ProcessQueue, Mode=OneTime}"/>
</Border>
</SplitView.Pane>
<!-- Product Display Grid -->
<views:ProductsDisplay
Name="productsDisplay"
DataContext="{CompiledBinding ProductsDisplay}"
DataContext="{Binding ProductsDisplay, Mode=OneTime}"
LiberateClicked="ProductsDisplay_LiberateClicked"
TagsButtonClicked="ProductsDisplay_TagsButtonClicked"
LiberateSeriesClicked="ProductsDisplay_LiberateSeriesClicked"
@@ -258,10 +258,10 @@
<Setter Property="MinWidth" Value="100" />
</Style>
</Grid.Styles>
<TextBlock FontSize="14" Grid.Column="0" Text="Upgrading:" VerticalAlignment="Center" IsVisible="{CompiledBinding DownloadProgress, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ProgressBar Grid.Column="1" Margin="5,0,10,0" VerticalAlignment="Stretch" Width="100" Value="{CompiledBinding DownloadProgress}" IsVisible="{CompiledBinding DownloadProgress, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<TextBlock FontSize="14" Grid.Column="2" Text="{CompiledBinding VisibleCountText}" VerticalAlignment="Center" />
<TextBlock FontSize="14" Grid.Column="3" Text="{CompiledBinding LibraryStats.StatusString}" VerticalAlignment="Center" />
<TextBlock FontSize="14" Grid.Column="0" Text="Upgrading:" VerticalAlignment="Center" IsVisible="{Binding DownloadProgress, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ProgressBar Grid.Column="1" Margin="5,0,10,0" VerticalAlignment="Stretch" Width="100" Value="{Binding DownloadProgress, TargetNullValue=0}" IsVisible="{Binding DownloadProgress, Converter={x:Static ObjectConverters.IsNotNull}}"/>
<TextBlock FontSize="14" Grid.Column="2" Text="{Binding VisibleCountText}" VerticalAlignment="Center" />
<TextBlock FontSize="14" Grid.Column="3" Text="{Binding LibraryStats?.StatusString}" VerticalAlignment="Center" />
</Grid>
</Grid>
</Window>

View File

@@ -25,7 +25,6 @@ public partial class MainWindow : ReactiveWindow<MainVM>
if (Design.IsDesignMode)
Configuration.CreateMockInstance();
DataContext = new MainVM(this);
ApiExtended.LoginChoiceFactory = account => Dispatcher.UIThread.Invoke(() => new Dialogs.Login.AvaloniaLoginChoiceEager(account));
AudibleApiStorage.LoadError += AudibleApiStorage_LoadError;
@@ -46,6 +45,7 @@ public partial class MainWindow : ReactiveWindow<MainVM>
Configuration.Instance.PropertyChanged += Settings_PropertyChanged;
Settings_PropertyChanged(this, null);
DataContext = new MainVM(this);
}
[Dinah.Core.PropertyChangeFilter(nameof(Configuration.Books))]

View File

@@ -16,7 +16,7 @@
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="views|ProcessBookControl">
<Setter Property="ProcessBookStatus" Value="{CompiledBinding Status}" />
<Setter Property="ProcessBookStatus" Value="{Binding Status}" />
<Style Selector="^[ProcessBookStatus=Cancelled]">
<Setter Property="Background" Value="{DynamicResource ProcessQueueBookCancelledBrush}" />
</Style>
@@ -34,13 +34,13 @@
<Grid ColumnDefinitions="Auto,*,Auto">
<Panel Grid.Column="0" Margin="3" Width="80" Height="80" HorizontalAlignment="Left">
<Image Width="80" Height="80" Source="{CompiledBinding Cover}" Stretch="Uniform" />
<Image Width="80" Height="80" Source="{Binding Cover}" Stretch="Uniform" />
</Panel>
<Grid Margin="0,3,0,3" Grid.Column="1" ColumnDefinitions="*" RowDefinitions="*,16">
<StackPanel Grid.Column="0" Grid.Row="0" Orientation="Vertical">
<TextBlock ClipToBounds="True" TextWrapping="Wrap" FontSize="11" Text="{CompiledBinding Title}" />
<TextBlock FontSize="10" TextWrapping="NoWrap" Text="{CompiledBinding Author}" />
<TextBlock FontSize="10" TextWrapping="NoWrap" Text="{CompiledBinding Narrator}" />
<TextBlock ClipToBounds="True" TextWrapping="Wrap" FontSize="11" Text="{Binding Title}" />
<TextBlock FontSize="10" TextWrapping="NoWrap" Text="{Binding Author}" />
<TextBlock FontSize="10" TextWrapping="NoWrap" Text="{Binding Narrator}" />
</StackPanel>
<Panel Grid.Column="0" Grid.Row="1">
<Panel.Styles>
@@ -48,8 +48,8 @@
<Setter Property="MinWidth" Value="20" />
</Style>
</Panel.Styles>
<ProgressBar IsVisible="{CompiledBinding IsDownloading}" Value="{CompiledBinding Progress}" ShowProgressText="True" FontSize="12" />
<TextBlock IsVisible="{CompiledBinding !IsDownloading}" Text="{CompiledBinding StatusText}"/>
<ProgressBar IsVisible="{Binding IsDownloading}" Value="{Binding Progress}" ShowProgressText="True" FontSize="12" />
<TextBlock IsVisible="{Binding !IsDownloading}" Text="{Binding StatusText}"/>
</Panel>
</Grid>
<Grid Name="ButtonsGrid" Margin="3" Grid.Column="2" HorizontalAlignment="Right" ColumnDefinitions="Auto,Auto">
@@ -64,7 +64,7 @@
</Style>
</Style>
</Grid.Styles>
<StackPanel IsVisible="{CompiledBinding Queued}" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Vertical">
<StackPanel IsVisible="{Binding Queued}" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Vertical">
<Button ToolTip.Tip="Move book to top of queue" Click="MoveFirst_Click">
<Path VerticalAlignment="Top" Data="{StaticResource FirstButtonIcon}" />
@@ -79,14 +79,14 @@
<Path VerticalAlignment="Bottom" Data="{StaticResource LastButtonIcon}" />
</Button>
</StackPanel>
<Panel Margin="3,0,0,0" Grid.Column="1" VerticalAlignment="Top" IsVisible="{CompiledBinding !IsFinished}">
<Panel Margin="3,0,0,0" Grid.Column="1" VerticalAlignment="Top" IsVisible="{Binding !IsFinished}">
<Button Height="32" Background="{DynamicResource CancelRed}" Width="22" CornerRadius="11" Click="Cancel_Click">
<Path Fill="{DynamicResource SystemAltHighColor}" VerticalAlignment="Center" Data="{StaticResource CancelButtonIcon}" RenderTransform="{StaticResource Rotate45Transform}" />
</Button>
</Panel>
</Grid>
<Panel Margin="3" Width="50" Grid.Column="2">
<TextPresenter FontSize="9" VerticalAlignment="Bottom" HorizontalAlignment="Right" IsVisible="{CompiledBinding IsDownloading}" Text="{CompiledBinding ETA}" />
<TextPresenter FontSize="9" VerticalAlignment="Bottom" HorizontalAlignment="Right" IsVisible="{Binding IsDownloading}" Text="{Binding ETA}" />
</Panel>
</Grid>

View File

@@ -5,6 +5,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:LibationAvalonia.Views"
xmlns:viewModels="clr-namespace:LibationAvalonia.ViewModels"
xmlns:vmbase="clr-namespace:LibationUiBase.ProcessQueue;assembly=LibationUiBase"
x:DataType="vmbase:ProcessQueueViewModel"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="650"
Background="{DynamicResource SystemRegionColor}"

View File

@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Input.Platform;
using Avalonia.Threading;
using DataLayer;
using LibationUiBase;

View File

@@ -17,7 +17,7 @@
ClipboardCopyMode="IncludeHeader"
GridLinesVisibility="All"
AutoGenerateColumns="False"
ItemsSource="{CompiledBinding GridEntries}"
ItemsSource="{Binding GridEntries}"
CanUserSortColumns="True" BorderThickness="3"
CanUserResizeColumns="True"
LoadingRow="ProductsDisplay_LoadingRow"
@@ -85,7 +85,7 @@
<DataGridTemplateColumn
CanUserSort="True"
CanUserResize="False"
IsVisible="{CompiledBinding RemoveColumnVisible}"
IsVisible="{Binding RemoveColumnVisible}"
PropertyChanged="RemoveColumn_PropertyChanged"
Header="Remove"
IsReadOnly="False"
@@ -97,199 +97,255 @@
<CheckBox
HorizontalAlignment="Center"
IsThreeState="True"
IsChecked="{CompiledBinding Remove, Mode=TwoWay}" />
IsChecked="{Binding Remove, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<controls:DataGridTemplateColumnExt CanUserResize="False" CanUserSort="True" Header="Liberate" SortMemberPath="Liberate" ClipboardContentBinding="{Binding Liberate.ToolTip}">
<controls:DataGridTemplateColumnExt CanUserResize="False" CanUserSort="True" Header="Liberate" SortMemberPath="Liberate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<views:LiberateStatusButton
ToolTip.Tip="{CompiledBinding Liberate.ToolTip}"
BookStatus="{CompiledBinding Liberate.BookStatus}"
PdfStatus="{CompiledBinding Liberate.PdfStatus}"
IsUnavailable="{CompiledBinding Liberate.IsUnavailable}"
IsSeries="{CompiledBinding Liberate.IsSeries}"
Expanded="{CompiledBinding Liberate.Expanded}"
ToolTip.Tip="{Binding Liberate.ToolTip}"
BookStatus="{Binding Liberate.BookStatus}"
PdfStatus="{Binding Liberate.PdfStatus}"
IsUnavailable="{Binding Liberate.IsUnavailable}"
IsSeries="{Binding Liberate.IsSeries}"
Expanded="{Binding Liberate.Expanded}"
Click="LiberateButton_Click" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Liberate.ToolTip" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Cover" CanUserResize="False" CanUserSort="False" SortMemberPath="Cover" ClipboardContentBinding="{Binding LibraryBook.Book.PictureLarge}">
<controls:DataGridTemplateColumnExt Header="Cover" CanUserResize="False" CanUserSort="False" SortMemberPath="Cover">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Image Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Cover_Click" Source="{CompiledBinding Cover}" ToolTip.Tip="Click to see full size" />
<Image Opacity="{Binding Liberate.Opacity}" Tapped="Cover_Click" Source="{Binding Cover}" ToolTip.Tip="Click to see full size" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="LibraryBook.Book.PictureLarge" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Title" MinWidth="10" Width="{CompiledBinding TitleWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Title" ClipboardContentBinding="{Binding Title}">
<controls:DataGridTemplateColumnExt Header="Title" MinWidth="10" Width="{Binding TitleWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Title">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Classes="h1" Text="{CompiledBinding Title}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Classes="h1" Text="{Binding Title}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Title" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Authors" MinWidth="10" Width="{CompiledBinding AuthorsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Authors" ClipboardContentBinding="{Binding Authors}">
<controls:DataGridTemplateColumnExt Header="Authors" MinWidth="10" Width="{Binding AuthorsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Authors">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Authors}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Authors}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Authors" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Narrators" MinWidth="10" Width="{CompiledBinding NarratorsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Narrators" ClipboardContentBinding="{Binding Narrators}">
<controls:DataGridTemplateColumnExt Header="Narrators" MinWidth="10" Width="{Binding NarratorsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Narrators">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Narrators}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Narrators}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Narrators" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Length" MinWidth="10" Width="{CompiledBinding LengthWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Length" ClipboardContentBinding="{Binding Length}">
<controls:DataGridTemplateColumnExt Header="Length" MinWidth="10" Width="{Binding LengthWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Length">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Length}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Length}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Length" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Series" MinWidth="10" Width="{CompiledBinding SeriesWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Series" ClipboardContentBinding="{Binding Series}">
<controls:DataGridTemplateColumnExt Header="Series" MinWidth="10" Width="{Binding SeriesWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Series">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Series}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Series}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Series" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Series&#xA;Order" MinWidth="10" Width="{CompiledBinding SeriesOrderWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="SeriesOrder" ClipboardContentBinding="{Binding Series}">
<controls:DataGridTemplateColumnExt Header="Series&#xA;Order" MinWidth="10" Width="{Binding SeriesOrderWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="SeriesOrder">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding SeriesOrder}" HorizontalAlignment="Center" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding SeriesOrder}" HorizontalAlignment="Center" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="SeriesOrder" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Description" MinWidth="10" Width="{CompiledBinding DescriptionWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Description" ClipboardContentBinding="{Binding Description}">
<controls:DataGridTemplateColumnExt Header="Description" MinWidth="10" Width="{Binding DescriptionWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Description">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
<TextBlock Text="{CompiledBinding Description}" VerticalAlignment="Top" />
<Panel Opacity="{Binding Liberate.Opacity}" Tapped="Description_Click" ToolTip.Tip="Click to see full description" >
<TextBlock Text="{Binding Description}" VerticalAlignment="Top" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Description" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Category" MinWidth="10" Width="{CompiledBinding CategoryWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Category" ClipboardContentBinding="{Binding Category}">
<controls:DataGridTemplateColumnExt Header="Category" MinWidth="10" Width="{Binding CategoryWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Category">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Category}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Category}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Category" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridMyRatingColumn
x:DataType="uibase:GridEntry"
Header="Product&#xA;Rating"
IsReadOnly="true"
MinWidth="10" Width="{Binding ProductRatingWidth, Mode=TwoWay}"
MinWidth="10"
SortMemberPath="ProductRating" CanUserSort="True"
OpacityBinding="{CompiledBinding Liberate.Opacity}"
ClipboardContentBinding="{CompiledBinding ProductRating}"
Binding="{CompiledBinding ProductRating}" />
OpacityBinding="{Binding Liberate.Opacity}"
ClipboardContentBinding="{Binding ProductRating}"
Binding="{Binding ProductRating}">
<controls:DataGridMyRatingColumn.Width>
<Binding x:DataType="vm:ProductsDisplayViewModel" Path="ProductRatingWidth" Mode="TwoWay" />
</controls:DataGridMyRatingColumn.Width>
</controls:DataGridMyRatingColumn>
<controls:DataGridTemplateColumnExt Header="Purchase&#xA;Date" MinWidth="10" Width="{CompiledBinding PurchaseDateWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="PurchaseDate" ClipboardContentBinding="{Binding PurchaseDate}">
<controls:DataGridTemplateColumnExt Header="Purchase&#xA;Date" MinWidth="10" Width="{Binding PurchaseDateWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="PurchaseDate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding PurchaseDate}" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding PurchaseDate}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="PurchaseDate" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridMyRatingColumn
x:DataType="uibase:GridEntry"
Header="My Rating"
IsReadOnly="false"
MinWidth="10" Width="{Binding MyRatingWidth, Mode=TwoWay}"
MinWidth="10"
SortMemberPath="MyRating" CanUserSort="True"
OpacityBinding="{CompiledBinding Liberate.Opacity}"
ClipboardContentBinding="{CompiledBinding MyRating}"
Binding="{CompiledBinding MyRating, Mode=TwoWay}" />
OpacityBinding="{Binding Liberate.Opacity}"
ClipboardContentBinding="{Binding MyRating}"
Binding="{Binding MyRating, Mode=TwoWay}">
<controls:DataGridMyRatingColumn.Width>
<Binding x:DataType="vm:ProductsDisplayViewModel" Path="MyRatingWidth" Mode="TwoWay" />
</controls:DataGridMyRatingColumn.Width>
</controls:DataGridMyRatingColumn>
<controls:DataGridTemplateColumnExt Header="Misc" MinWidth="10" Width="{CompiledBinding MiscWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
<controls:DataGridTemplateColumnExt Header="Misc" MinWidth="10" Width="{Binding MiscWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Misc">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Misc}" TextWrapping="WrapWithOverflow" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Misc}" TextWrapping="WrapWithOverflow" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Misc" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Included&#xA;Until" MinWidth="10" Width="{CompiledBinding IncludedUntilWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="IncludedUntil" ClipboardContentBinding="{Binding IncludedUntil}">
<controls:DataGridTemplateColumnExt Header="Included&#xA;Until" MinWidth="10" Width="{Binding IncludedUntilWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="IncludedUntil">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding IncludedUntil}" TextWrapping="WrapWithOverflow" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding IncludedUntil}" TextWrapping="WrapWithOverflow" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="IncludedUntil" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Last&#xA;Download" MinWidth="10" Width="{CompiledBinding LastDownloadWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="LastDownload" ClipboardContentBinding="{Binding LastDownload}">
<controls:DataGridTemplateColumnExt Header="Last&#xA;Download" MinWidth="10" Width="{Binding LastDownloadWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="LastDownload">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}" ToolTip.Tip="{CompiledBinding LastDownload.ToolTipText}" DoubleTapped="Version_DoubleClick">
<TextBlock Text="{CompiledBinding LastDownload}" TextWrapping="WrapWithOverflow" />
<Panel Opacity="{Binding Liberate.Opacity}" ToolTip.Tip="{Binding LastDownload.ToolTipText}" DoubleTapped="Version_DoubleClick">
<TextBlock Text="{Binding LastDownload}" TextWrapping="WrapWithOverflow" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="LastDownload" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Is&#xA;Spatial" MinWidth="10" Width="{CompiledBinding IsSpatialWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="IsSpatial" ClipboardContentBinding="{Binding IsSpatial}">
<controls:DataGridTemplateColumnExt Header="Is&#xA;Spatial" MinWidth="10" Width="{Binding IsSpatialWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="IsSpatial">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<CheckBox IsChecked="{CompiledBinding IsSpatial}" IsEnabled="False" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Panel Opacity="{Binding Liberate.Opacity}">
<CheckBox IsChecked="{Binding IsSpatial}" IsEnabled="False" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="IsSpatial" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Account" MinWidth="10" Width="{CompiledBinding AccountWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Account" ClipboardContentBinding="{Binding Account}">
<controls:DataGridTemplateColumnExt Header="Account" MinWidth="10" Width="{Binding AccountWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="Account">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Panel Opacity="{CompiledBinding Liberate.Opacity}">
<TextBlock Text="{CompiledBinding Account}" TextWrapping="Wrap" />
<Panel Opacity="{Binding Liberate.Opacity}">
<TextBlock Text="{Binding Account}" TextWrapping="Wrap" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="Account" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
<controls:DataGridTemplateColumnExt Header="Tags" MinWidth="10" Width="{CompiledBinding BookTagsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="BookTags" ClipboardContentBinding="{Binding BookTags}">
<controls:DataGridTemplateColumnExt Header="Tags" MinWidth="10" Width="{Binding BookTagsWidth, Mode=TwoWay}" CanUserSort="True" SortMemberPath="BookTags">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate x:DataType="uibase:GridEntry">
<Button
IsVisible="{CompiledBinding !Liberate.IsSeries}"
IsVisible="{Binding !Liberate.IsSeries}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
VerticalContentAlignment="Stretch"
@@ -298,23 +354,26 @@
ToolTip.Tip="Click to edit tags">
<Grid
RowDefinitions="*,*,*"
Opacity="{CompiledBinding Liberate.Opacity}">
Opacity="{Binding Liberate.Opacity}">
<Viewbox
Grid.Row="1"
Stretch="Uniform"
IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNullOrEmpty}}">
IsVisible="{Binding BookTags, Converter={x:Static StringConverters.IsNullOrEmpty}}">
<Path Fill="{DynamicResource IconFill}" Data="{StaticResource EditTagsIcon}" />
</Viewbox>
<TextBlock
Classes="h2"
Grid.RowSpan="3"
IsVisible="{CompiledBinding BookTags, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" TextWrapping="WrapWithOverflow" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{CompiledBinding BookTags}"/>
IsVisible="{Binding BookTags, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" TextWrapping="WrapWithOverflow" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding BookTags}"/>
</Grid>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<controls:DataGridTemplateColumnExt.ClipboardContentBinding>
<Binding x:DataType="uibase:GridEntry" Path="BookTags" />
</controls:DataGridTemplateColumnExt.ClipboardContentBinding>
</controls:DataGridTemplateColumnExt>
</DataGrid.Columns>

View File

@@ -33,10 +33,10 @@ public partial class ProductsDisplay : UserControl
public static readonly StyledProperty<bool> DisableContextMenuProperty =
AvaloniaProperty.Register<GroupBox, bool>(nameof(DisableContextMenu));
AvaloniaProperty.Register<Controls.GroupBox, bool>(nameof(DisableContextMenu));
public static readonly StyledProperty<bool> DisableColumnCustomizationProperty =
AvaloniaProperty.Register<GroupBox, bool>(nameof(DisableColumnCustomization));
AvaloniaProperty.Register<Controls.GroupBox, bool>(nameof(DisableColumnCustomization));
public bool DisableContextMenu
{
@@ -495,7 +495,7 @@ public partial class ProductsDisplay : UserControl
#endregion
#region View Bookmarks/Clips (Single book only)
if (entries.Length == 1 && entries[0] is LibraryBookEntry entry3 && VisualRoot is Window window)
if (entries.Length == 1 && entries[0] is LibraryBookEntry entry3 && this.GetParentWindow() is Window window)
{
args.ContextMenuItems.Add(new MenuItem
{
@@ -658,7 +658,7 @@ public partial class ProductsDisplay : UserControl
var pictureId = gEntry.LibraryBook.Book.PictureLarge ?? gEntry.LibraryBook.Book.PictureId;
if (string.IsNullOrEmpty(pictureId))
{
await MessageBox.Show(VisualRoot as Window, "No cover art is available for this book.", "No Cover Art", MessageBoxButtons.OK, MessageBoxIcon.Information);
await MessageBox.Show(this.GetParentWindow(), "No cover art is available for this book.", "No Cover Art", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}

View File

@@ -3,11 +3,13 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:local="clr-namespace:LibationAvalonia.Views"
x:Class="LibationAvalonia.Views.SeriesViewDialog"
x:DataType="local:SeriesViewDialog"
Title="View All Items in Series">
<TabControl
ItemsSource="{Binding TabItems}"
ItemsSource="{Binding TabItems}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<TabControl.Styles>

View File

@@ -4,6 +4,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
xmlns:local="clr-namespace:LibationAvalonia.Views"
x:DataType="local:SeriesViewGrid"
xmlns:uibase="clr-namespace:LibationUiBase.SeriesView;assembly=LibationUiBase"
x:Class="LibationAvalonia.Views.SeriesViewGrid">
@@ -39,7 +41,7 @@
<Image
Tapped="Cover_Click"
Height="80"
Source="{CompiledBinding Cover}"
Source="{Binding Cover}"
ToolTip.Tip="Click to see full size" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
@@ -50,7 +52,7 @@
<DataTemplate x:DataType="uibase:SeriesItem">
<Panel>
<TextBlock
Text="{CompiledBinding Order}"
Text="{Binding Order}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Panel>
@@ -72,17 +74,17 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Click="Availability_Click"
IsVisible="{CompiledBinding Button.HasButtonAction}"
IsEnabled="{CompiledBinding Button.Enabled}">
IsVisible="{Binding Button.HasButtonAction}"
IsEnabled="{Binding Button.Enabled}">
<TextBlock
Text="{CompiledBinding Button.DisplayText}"
Text="{Binding Button.DisplayText}"
TextAlignment="Center"
VerticalAlignment="Center" />
</Button>
<TextBlock
HorizontalAlignment="Center"
IsVisible="{CompiledBinding !Button.HasButtonAction}"
Text="{CompiledBinding Button.DisplayText}" />
IsVisible="{Binding !Button.HasButtonAction}"
Text="{Binding Button.DisplayText}" />
</Panel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
@@ -94,7 +96,7 @@
<Panel ToolTip.Tip="Open Audible product page">
<controls:LinkLabel
VerticalAlignment="Center"
Text="{CompiledBinding Title}"
Text="{Binding Title}"
Tapped="Title_Click" />
</Panel>
</DataTemplate>

View File

@@ -60,7 +60,7 @@ public partial class SeriesViewGrid : UserControl
var pictureId = libraryBook.PictureLarge ?? libraryBook.PictureId;
if (string.IsNullOrEmpty(pictureId))
{
await MessageBox.Show(VisualRoot as Window, "No cover art is available for this book.", "No Cover Art", MessageBoxButtons.OK, MessageBoxIcon.Information);
await MessageBox.Show(this.GetParentWindow(), "No cover art is available for this book.", "No Cover Art", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}

View File

@@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="AudibleApi" Version="10.1.5.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
<PackageReference Include="NameParserSharp" Version="1.5.0" />
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
</ItemGroup>

View File

@@ -3,7 +3,7 @@ using System;
using System.Collections.Generic;
using FileManager.NamingTemplate;
namespace LibationFileManager.Templates;
namespace LibationFileManager.Templates;
public class ContributorDto(string name, string? audibleContributorId) : IFormattable
{

View File

@@ -48,9 +48,9 @@ public record CultureInfoDto : IFormattable
{
var cultures = CultureInfo.GetCultures(types);
return Match(cultures, input, c => c.Name) ??
Match(cultures, input, c => c.TwoLetterISOLanguageName) ??
Match(cultures, input, c => c.ThreeLetterISOLanguageName) ??
Match(cultures, input, c => c.EnglishName);
Match(cultures, input, c => c.TwoLetterISOLanguageName) ??
Match(cultures, input, c => c.ThreeLetterISOLanguageName) ??
Match(cultures, input, c => c.EnglishName);
}
private static CultureInfo? Match(IEnumerable<CultureInfo> cultures, string input, Func<CultureInfo, string?> selector, StringComparison cmp = StringComparison.OrdinalIgnoreCase)

View File

@@ -368,7 +368,7 @@ public abstract partial class Templates
{
return intVal;
}
// then check for property tags and retrieve their value
foreach (var c in allPropertyTags.OfType<PropertyTagCollection<LibraryBookDto>>())
{

View File

@@ -8,20 +8,20 @@ public static class WindowsDirectory
const int FolderIconMaxAttempts = 5;
public static void SetCoverAsFolderIcon(string? pictureId, string directory, CancellationToken cancellationToken)
{
//Currently only works for Windows and macOS
if (!Configuration.Instance.UseCoverAsFolderIcon)
{
//Currently only works for Windows and macOS
if (!Configuration.Instance.UseCoverAsFolderIcon)
return;
if (string.IsNullOrEmpty(pictureId))
{
Serilog.Log.Logger.Warning("No picture ID provided to set cover art as folder icon. {@DebugInfo}", new { directory });
return;
}
}
// Load JPEG bytes from Images cache (or download). Prefer bytes → ICO so we never depend on a
// path that might not exist when Amazon omits Content-Length or another downloader left a stale cache entry.
// Load JPEG bytes from Images cache (or download). Prefer bytes → ICO so we never depend on a
// path that might not exist when Amazon omits Content-Length or another downloader left a stale cache entry.
for (var attempt = 1; attempt <= FolderIconMaxAttempts; attempt++)
for (var attempt = 1; attempt <= FolderIconMaxAttempts; attempt++)
{
cancellationToken.ThrowIfCancellationRequested();

View File

@@ -86,9 +86,9 @@ public class SearchEngine
// Corruption (e.g. checksum mismatch in segments) is not fixed by waiting; clear and rebuild immediately.
var corruptRebuildAttemptsRemaining = 2;
// Exponential backoff retry: 400 ms, 800 ms, 1600 ms, etc
// Exponential backoff retry: 400 ms, 800 ms, 1600 ms, etc
// Total wait time before giving up: 12.4 sec
for (var attempt = 0; attempt < maxRetries; attempt++)
for (var attempt = 0; attempt < maxRetries; attempt++)
{
try
{
@@ -118,13 +118,13 @@ public class SearchEngine
}
}
/// <summary>
/// Lucene 3 parses <c>segments_*</c> filenames in the index directory. Cloud sync (e.g. OneDrive) can leave debris
/// or conflict copies whose names break that parser, throwing <see cref="ArgumentException"/> with this message shape.
/// Actual error is likely to be something like: Invalid or unsupported character in number, hence this string check.
/// <see cref="CorruptIndexException"/> (e.g. checksum mismatch in segments) is also recoverable by deleting the index and rebuilding.
/// </summary>
public static bool IsRecoverableCorruptIndexException(Exception ex)
/// <summary>
/// Lucene 3 parses <c>segments_*</c> filenames in the index directory. Cloud sync (e.g. OneDrive) can leave debris
/// or conflict copies whose names break that parser, throwing <see cref="ArgumentException"/> with this message shape.
/// Actual error is likely to be something like: Invalid or unsupported character in number, hence this string check.
/// <see cref="CorruptIndexException"/> (e.g. checksum mismatch in segments) is also recoverable by deleting the index and rebuilding.
/// </summary>
public static bool IsRecoverableCorruptIndexException(Exception ex)
=> ex is CorruptIndexException
|| (ex is ArgumentException aex && aex.Message.Contains("character in number", StringComparison.OrdinalIgnoreCase));

View File

@@ -42,7 +42,7 @@
<ItemGroup>
<PackageReference Include="Dinah.Core.WindowsDesktop" Version="10.0.0.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3719.77" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3912.50" />
</ItemGroup>
<ItemGroup>

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.2.2" />
</ItemGroup>
</Project>

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
<PackageReference Include="MSTest" Version="4.2.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
<PackageReference Include="MSTest" Version="4.2.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -321,7 +321,7 @@ public class CommonFormattersTests
// THEN
Assert.AreEqual(expected, unescaped);
}
private class TestClass
{

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
<PackageReference Include="MSTest" Version="4.2.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
<PackageReference Include="MSTest" Version="4.2.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
<PackageReference Include="MSTest" Version="4.2.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -74,7 +74,7 @@ public class FormatSearchQuery
public void FormattingTest(string input, string output)
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
using var analyzer = new StandardAnalyzer(SearchEngine.Version);
QuerySanitizer.Sanitize(input, analyzer).Should().Be(output);

View File

@@ -3,28 +3,28 @@
[TestClass]
public class ExceptionDisplayTests
{
/// <summary>Outer exception with a fixed <see cref="Exception.StackTrace"/> so golden-string tests are stable.</summary>
private sealed class ExceptionWithFixedStack : Exception
{
private string _fixedStack { get; }
public ExceptionWithFixedStack(string message, Exception? innerException, string fixedStack)
: base(message, innerException) => _fixedStack = fixedStack;
public override string? StackTrace => _fixedStack;
}
/// <summary>Outer exception with a fixed <see cref="Exception.StackTrace"/> so golden-string tests are stable.</summary>
private sealed class ExceptionWithFixedStack : Exception
{
private string _fixedStack { get; }
public ExceptionWithFixedStack(string message, Exception? innerException, string fixedStack)
: base(message, innerException) => _fixedStack = fixedStack;
public override string? StackTrace => _fixedStack;
}
/// <summary>
/// Golden output for <see cref="ExceptionDisplay.FormatMessageAndStackTrace"/> when there are fourteen
/// <see cref="Exception.InnerException"/> links (fifteen messages: outer L0 … deepest L14): first ten inners,
/// two omitted (L11L12), then the two deepest (L13L14), then the outer stack trace.
/// </summary>
[TestMethod]
public void _FullText_14Levels()
{
const string stack = "<<GOLDEN-TEST-STACK-TRACE>>";
var messages = Enumerable.Range(0, 15).Select(i => $"L{i}").ToArray();
var ex = CreateChainWithFixedStack(stack, messages);
/// <summary>
/// Golden output for <see cref="ExceptionDisplay.FormatMessageAndStackTrace"/> when there are fourteen
/// <see cref="Exception.InnerException"/> links (fifteen messages: outer L0 … deepest L14): first ten inners,
/// two omitted (L11L12), then the two deepest (L13L14), then the outer stack trace.
/// </summary>
[TestMethod]
public void _FullText_14Levels()
{
const string stack = "<<GOLDEN-TEST-STACK-TRACE>>";
var messages = Enumerable.Range(0, 15).Select(i => $"L{i}").ToArray();
var ex = CreateChainWithFixedStack(stack, messages);
const string expected = """
const string expected = """
L0
Inner exception: L1
@@ -55,129 +55,129 @@ Inner exception: L14
<<GOLDEN-TEST-STACK-TRACE>>
""";
Assert.AreEqual(expected.ReplaceLineEndings("\n"), Format(ex));
}
Assert.AreEqual(expected.ReplaceLineEndings("\n"), Format(ex));
}
/// <inheritdoc cref="CreateChain"/>
/// <remarks>Same chain shape as <see cref="CreateChain"/>, but the outer exception reports <paramref name="stackTrace"/> from <see cref="Exception.StackTrace"/>.</remarks>
private static Exception CreateChainWithFixedStack(string stackTrace, params string[] messages)
{
if (messages.Length == 0)
throw new ArgumentException("At least one message is required.", nameof(messages));
/// <inheritdoc cref="CreateChain"/>
/// <remarks>Same chain shape as <see cref="CreateChain"/>, but the outer exception reports <paramref name="stackTrace"/> from <see cref="Exception.StackTrace"/>.</remarks>
private static Exception CreateChainWithFixedStack(string stackTrace, params string[] messages)
{
if (messages.Length == 0)
throw new ArgumentException("At least one message is required.", nameof(messages));
var innermost = new Exception(messages[^1]);
for (var i = messages.Length - 2; i >= 1; i--)
innermost = new Exception(messages[i], innermost);
return new ExceptionWithFixedStack(messages[0], innermost, stackTrace);
}
var innermost = new Exception(messages[^1]);
for (var i = messages.Length - 2; i >= 1; i--)
innermost = new Exception(messages[i], innermost);
return new ExceptionWithFixedStack(messages[0], innermost, stackTrace);
}
/// <summary>messages[0] = outer; each following string is the next <see cref="Exception.InnerException"/> message.</summary>
private static Exception CreateChain(params string[] messages)
{
if (messages.Length == 0)
throw new ArgumentException("At least one message is required.", nameof(messages));
/// <summary>messages[0] = outer; each following string is the next <see cref="Exception.InnerException"/> message.</summary>
private static Exception CreateChain(params string[] messages)
{
if (messages.Length == 0)
throw new ArgumentException("At least one message is required.", nameof(messages));
var innermost = new Exception(messages[^1]);
for (var i = messages.Length - 2; i >= 0; i--)
innermost = new Exception(messages[i], innermost);
return innermost;
}
var innermost = new Exception(messages[^1]);
for (var i = messages.Length - 2; i >= 0; i--)
innermost = new Exception(messages[i], innermost);
return innermost;
}
private static string Format(Exception ex) => ExceptionDisplay.FormatMessageAndStackTrace(ex).ReplaceLineEndings("\n");
private static string Format(Exception ex) => ExceptionDisplay.FormatMessageAndStackTrace(ex).ReplaceLineEndings("\n");
[TestMethod]
public void NoInnerException_ContainsOuterMessageAndStack()
{
var ex = new Exception("outer only");
var text = Format(ex);
[TestMethod]
public void NoInnerException_ContainsOuterMessageAndStack()
{
var ex = new Exception("outer only");
var text = Format(ex);
Assert.StartsWith("outer only\n", text);
Assert.IsFalse(text.Contains("Inner exception:", StringComparison.Ordinal));
if (ex.StackTrace is not null)
Assert.IsTrue(text.Contains(ex.StackTrace, StringComparison.Ordinal));
}
Assert.StartsWith("outer only\n", text);
Assert.IsFalse(text.Contains("Inner exception:", StringComparison.Ordinal));
if (ex.StackTrace is not null)
Assert.IsTrue(text.Contains(ex.StackTrace, StringComparison.Ordinal));
}
[TestMethod]
public void OneInner_ShowsInnerLine()
{
var ex = CreateChain("outer", "inner-a");
var text = Format(ex);
[TestMethod]
public void OneInner_ShowsInnerLine()
{
var ex = CreateChain("outer", "inner-a");
var text = Format(ex);
var expectedHead = """
var expectedHead = """
outer
Inner exception: inner-a
""".ReplaceLineEndings("\n");
Assert.AreEqual(expectedHead + ex.StackTrace, text);
}
Assert.AreEqual(expectedHead + ex.StackTrace, text);
}
[TestMethod]
public void TenInners_ShowsAllTen()
{
var messages = new[] { "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10" };
var ex = CreateChain(messages);
var text = Format(ex);
[TestMethod]
public void TenInners_ShowsAllTen()
{
var messages = new[] { "m0", "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10" };
var ex = CreateChain(messages);
var text = Format(ex);
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: m{i}\n", StringComparison.Ordinal), $"missing inner m{i}");
Assert.IsFalse(text.Contains("omitted", StringComparison.OrdinalIgnoreCase));
}
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: m{i}\n", StringComparison.Ordinal), $"missing inner m{i}");
Assert.IsFalse(text.Contains("omitted", StringComparison.OrdinalIgnoreCase));
}
[TestMethod]
public void ElevenInners_FirstTenThenDeepestOnly_NoOmitLine()
{
var messages = Enumerable.Range(0, 12).Select(i => $"n{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
[TestMethod]
public void ElevenInners_FirstTenThenDeepestOnly_NoOmitLine()
{
var messages = Enumerable.Range(0, 12).Select(i => $"n{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: n{i}\n", StringComparison.Ordinal));
Assert.IsFalse(text.Contains("omitted", StringComparison.OrdinalIgnoreCase));
Assert.IsTrue(text.Contains("Inner exception: n11\n", StringComparison.Ordinal));
}
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: n{i}\n", StringComparison.Ordinal));
Assert.IsFalse(text.Contains("omitted", StringComparison.OrdinalIgnoreCase));
Assert.IsTrue(text.Contains("Inner exception: n11\n", StringComparison.Ordinal));
}
[TestMethod]
public void TwelveInners_FirstTenThenLastTwo_NoOmitLine()
{
var messages = Enumerable.Range(0, 13).Select(i => $"p{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
[TestMethod]
public void TwelveInners_FirstTenThenLastTwo_NoOmitLine()
{
var messages = Enumerable.Range(0, 13).Select(i => $"p{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: p{i}\n", StringComparison.Ordinal));
Assert.IsFalse(text.Contains("omitted", StringComparison.OrdinalIgnoreCase));
Assert.IsTrue(text.Contains("Inner exception: p11\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains("Inner exception: p12\n", StringComparison.Ordinal));
}
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: p{i}\n", StringComparison.Ordinal));
Assert.IsFalse(text.Contains("omitted", StringComparison.OrdinalIgnoreCase));
Assert.IsTrue(text.Contains("Inner exception: p11\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains("Inner exception: p12\n", StringComparison.Ordinal));
}
[TestMethod]
public void ThirteenInners_FirstTen_OmitOne_ThenLastTwo()
{
var messages = Enumerable.Range(0, 14).Select(i => $"q{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
[TestMethod]
public void ThirteenInners_FirstTen_OmitOne_ThenLastTwo()
{
var messages = Enumerable.Range(0, 14).Select(i => $"q{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: q{i}\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains("1 inner exception omitted.\n", StringComparison.Ordinal));
Assert.IsFalse(text.Contains("Inner exception: q11\n", StringComparison.Ordinal), "omitted inner should not appear");
Assert.IsTrue(text.Contains("Inner exception: q12\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains("Inner exception: q13\n", StringComparison.Ordinal));
}
for (var i = 1; i <= 10; i++)
Assert.IsTrue(text.Contains($"Inner exception: q{i}\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains("1 inner exception omitted.\n", StringComparison.Ordinal));
Assert.IsFalse(text.Contains("Inner exception: q11\n", StringComparison.Ordinal), "omitted inner should not appear");
Assert.IsTrue(text.Contains("Inner exception: q12\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains("Inner exception: q13\n", StringComparison.Ordinal));
}
[TestMethod]
public void ManyInners_OmitCountPlural()
{
var depth = 20;
var messages = Enumerable.Range(0, depth + 1).Select(i => $"x{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
[TestMethod]
public void ManyInners_OmitCountPlural()
{
var depth = 20;
var messages = Enumerable.Range(0, depth + 1).Select(i => $"x{i}").ToArray();
var ex = CreateChain(messages);
var text = Format(ex);
var omitted = depth - 10 - 2;
Assert.IsTrue(text.Contains($"{omitted} inner exceptions omitted.\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains($"Inner exception: x{depth - 1}\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains($"Inner exception: x{depth}\n", StringComparison.Ordinal));
}
var omitted = depth - 10 - 2;
Assert.IsTrue(text.Contains($"{omitted} inner exceptions omitted.\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains($"Inner exception: x{depth - 1}\n", StringComparison.Ordinal));
Assert.IsTrue(text.Contains($"Inner exception: x{depth}\n", StringComparison.Ordinal));
}
}

View File

@@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSTest" Version="4.1.0" />
<PackageReference Include="MSTest" Version="4.2.2" />
</ItemGroup>
<ItemGroup>