diff --git a/Source/FileManager/ReplacementCharacters.cs b/Source/FileManager/ReplacementCharacters.cs
index 550a54c6..cc93451b 100644
--- a/Source/FileManager/ReplacementCharacters.cs
+++ b/Source/FileManager/ReplacementCharacters.cs
@@ -12,10 +12,10 @@ namespace FileManager
public const int FIXED_COUNT = 6;
internal const char QUOTE_MARK = '"';
- [JsonIgnore] public bool Mandatory { get; internal set; }
+ [JsonIgnore] public bool Mandatory { get; set; }
[JsonProperty] public char CharacterToReplace { get; private set; }
- [JsonProperty] public string ReplacementString { get; set; }
- [JsonProperty] public string Description { get; private set; }
+ [JsonProperty] public string ReplacementString { get; private set; }
+ [JsonProperty] public string Description { get; set; }
public override string ToString() => $"{CharacterToReplace} → {ReplacementString} ({Description})";
public Replacement(char charToReplace, string replacementString, string description)
@@ -169,9 +169,9 @@ namespace FileManager
public static bool ContainsInvalidPathChar(string path)
- => path.Any(c => invalidChars.Contains(c));
+ => path.Any(c => invalidChars?.Contains(c) == true);
public static bool ContainsInvalidFilenameChar(string path)
- => path.Any(c => invalidChars.Concat(new char[] { '\\', '/' }).Contains(c));
+ => path.Any(c => invalidChars?.Concat(new char[] { '\\', '/' })?.Contains(c) == true);
public string ReplaceInvalidFilenameChars(string fileName)
{
diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj
index 83d9607b..999e7fe2 100644
--- a/Source/HangoverAvalonia/HangoverAvalonia.csproj
+++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj
@@ -63,11 +63,13 @@
-
-
+
+
+
-
-
+
+
+
diff --git a/Source/LibationAvalonia/App.axaml b/Source/LibationAvalonia/App.axaml
index cbfd5ab2..9e8d399d 100644
--- a/Source/LibationAvalonia/App.axaml
+++ b/Source/LibationAvalonia/App.axaml
@@ -8,9 +8,9 @@
-
-
-
+
+
+
diff --git a/Source/LibationAvalonia/App.axaml.cs b/Source/LibationAvalonia/App.axaml.cs
index b4e42ae0..a7dcc392 100644
--- a/Source/LibationAvalonia/App.axaml.cs
+++ b/Source/LibationAvalonia/App.axaml.cs
@@ -42,9 +42,6 @@ namespace LibationAvalonia
{
LoadStyles();
- var SEGOEUI = new Typeface(new FontFamily(new Uri("avares://Libation/Assets/WINGDING.TTF"), "SEGOEUI_Local"));
- var gtf = FontManager.Current.GetOrAddGlyphTypeface(SEGOEUI);
-
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
if (SetupRequired)
diff --git a/Source/LibationAvalonia/Assets/SEGOEUI.TTF b/Source/LibationAvalonia/Assets/SEGOEUI.TTF
deleted file mode 100644
index 0f52cbd9..00000000
Binary files a/Source/LibationAvalonia/Assets/SEGOEUI.TTF and /dev/null differ
diff --git a/Source/LibationAvalonia/Assets/WINGDING.TTF b/Source/LibationAvalonia/Assets/WINGDING.TTF
deleted file mode 100644
index 6e38f7fd..00000000
Binary files a/Source/LibationAvalonia/Assets/WINGDING.TTF and /dev/null differ
diff --git a/Source/LibationAvalonia/Controls/LinkLabel.axaml.cs b/Source/LibationAvalonia/Controls/LinkLabel.axaml.cs
index 0d75021e..30b0d74a 100644
--- a/Source/LibationAvalonia/Controls/LinkLabel.axaml.cs
+++ b/Source/LibationAvalonia/Controls/LinkLabel.axaml.cs
@@ -15,15 +15,15 @@ namespace LibationAvalonia.Controls
{
InitializeComponent();
}
- protected override void OnPointerEnter(PointerEventArgs e)
+ protected override void OnPointerEntered(PointerEventArgs e)
{
this.Cursor = HandCursor;
- base.OnPointerEnter(e);
+ base.OnPointerEntered(e);
}
- protected override void OnPointerLeave(PointerEventArgs e)
+ protected override void OnPointerExited(PointerEventArgs e)
{
this.Cursor = Cursor.Default;
- base.OnPointerLeave(e);
+ base.OnPointerExited(e);
}
private void InitializeComponent()
diff --git a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs
index 180c736a..a48d2075 100644
--- a/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/BookDetailsDialog.axaml.cs
@@ -10,6 +10,7 @@ using LibationAvalonia.ViewModels;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
+using System;
namespace LibationAvalonia.Dialogs
{
@@ -54,7 +55,7 @@ namespace LibationAvalonia.Dialogs
base.SaveAndClose();
}
- public void GoToAudible_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ public void GoToAudible_Tapped(object sender, Avalonia.Input.TappedEventArgs e)
{
var locale = AudibleApi.Localization.Get(_libraryBook.Book.Locale);
var link = $"https://www.audible.{locale.TopDomain}/pd/{_libraryBook.Book.AudibleProductId}";
diff --git a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
index 84d7a3e5..e23fb97d 100644
--- a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
+++ b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
@@ -2,60 +2,71 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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"
+ mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="450"
+ MinWidth="500" MinHeight="450"
x:Class="LibationAvalonia.Dialogs.EditReplacementChars"
- Title="EditReplacementChars">
+ Title="Illegal Character Replacement"
+ Icon="/Assets/libation.ico">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs
index 698e8f7a..5524678e 100644
--- a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs
@@ -1,54 +1,179 @@
-using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using FileManager;
using LibationFileManager;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using ReactiveUI;
using System.Linq;
+using Avalonia.Collections;
+using Avalonia.Data;
namespace LibationAvalonia.Dialogs
{
public partial class EditReplacementChars : DialogWindow
{
- Configuration config = Configuration.Instance;
- public ObservableCollection replacements { get; }
+ Configuration config;
+
+ private readonly List SOURCE = new();
+ public DataGridCollectionView replacements { get; }
public EditReplacementChars()
{
InitializeComponent();
- if (Design.IsDesignMode)
- AudibleUtilities.AudibleApiStorage.EnsureAccountsSettingsFileExists();
+ replacements = new(SOURCE);
+
+ if (Design.IsDesignMode)
+ {
+ LoadTable(ReplacementCharacters.Default.Replacements);
+ }
- replacements = new(config.ReplacementCharacters.Replacements.Select(r => new ReplacementsExt { Replacement = r }));
DataContext = this;
}
+ public EditReplacementChars(Configuration config) : this()
+ {
+ this.config = config;
+ LoadTable(config.ReplacementCharacters.Replacements);
+ }
+
+ public void Defaults_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ => LoadTable(ReplacementCharacters.Default.Replacements);
+ public void LoFiDefaults_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ => LoadTable(ReplacementCharacters.LoFiDefault.Replacements);
+ public void Barebones_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ => LoadTable(ReplacementCharacters.Barebones.Replacements);
+ public void Save_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ => SaveAndClose();
+ public void Cancel_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ => Close();
+
+ protected override void SaveAndClose()
+ {
+ var replacements = SOURCE
+ .Where(r=> !r.IsDefault)
+ .Select(r => new Replacement(r.Character, r.ReplacementText, r.Description) { Mandatory = r.Mandatory })
+ .ToList();
+
+ if (config is not null)
+ config.ReplacementCharacters = new ReplacementCharacters { Replacements = replacements };
+ base.SaveAndClose();
+ }
+
+ private void LoadTable(IReadOnlyList replacements)
+ {
+ SOURCE.Clear();
+ SOURCE.AddRange(replacements.Select(r => new ReplacementsExt(r)));
+ SOURCE.Add(new ReplacementsExt());
+ this.replacements.Refresh();
+ }
+
+ public void ReplacementGrid_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
+ {
+ if (e.Key == Avalonia.Input.Key.Delete
+ && ((DataGrid)sender).SelectedItem is ReplacementsExt repl
+ && !repl.Mandatory
+ && !repl.IsDefault)
+ {
+ replacements.Remove(repl);
+ }
+ }
+
+ public void ReplacementGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
+ {
+ var replacement = e.Row.DataContext as ReplacementsExt;
+ var colBinding = columnBindingPath(e.Column);
+
+ //Prevent duplicate CharacterToReplace
+ if (e.EditingElement is TextBox tbox
+ && colBinding == nameof(replacement.CharacterToReplace)
+ && SOURCE.Any(r => r != replacement && r.CharacterToReplace == tbox.Text))
+ {
+ tbox.Text = replacement.CharacterToReplace;
+ }
+
+ //Add new blank row
+ void Replacement_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+ {
+ if (!SOURCE.Any(r => r.IsDefault))
+ {
+ var rewRepl = new ReplacementsExt();
+ SOURCE.Add(rewRepl);
+ }
+ replacement.PropertyChanged -= Replacement_PropertyChanged;
+ }
+
+ replacement.PropertyChanged += Replacement_PropertyChanged;
+ }
+
+ public void ReplacementGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
+ {
+ var replacement = e.Row.DataContext as ReplacementsExt;
+
+ //Disallow editing of Mandatory CharacterToReplace and Descriptions
+ if (replacement.Mandatory
+ && columnBindingPath(e.Column) != nameof(replacement.ReplacementText))
+ e.Cancel = true;
+ }
+
+ private static string columnBindingPath(DataGridColumn column)
+ => ((Binding)((DataGridBoundColumn)column).Binding).Path;
public class ReplacementsExt : ViewModels.ViewModelBase
{
- public Replacement Replacement { get; init; }
+ public ReplacementsExt()
+ {
+ _replacementText = string.Empty;
+ _description = string.Empty;
+ _characterToReplace = string.Empty;
+ IsDefault = true;
+ }
+ public ReplacementsExt(Replacement replacement)
+ {
+ _characterToReplace = replacement.CharacterToReplace == default ? "" : replacement.CharacterToReplace.ToString();
+ _replacementText = replacement.ReplacementString;
+ _description = replacement.Description;
+ Mandatory = replacement.Mandatory;
+ }
+ private string _replacementText;
+ private string _description;
+ private string _characterToReplace;
+ public bool Mandatory { get; }
public string ReplacementText
{
- get => Replacement.ReplacementString;
+ get => _replacementText;
set
{
- Replacement.ReplacementString = value;
- this.RaisePropertyChanged(nameof(ReplacementText));
+ if (ReplacementCharacters.ContainsInvalidPathChar(value))
+ this.RaisePropertyChanged(nameof(ReplacementText));
+ else
+ this.RaiseAndSetIfChanged(ref _replacementText, value);
}
}
+
+ public string Description { get => _description; set => this.RaiseAndSetIfChanged(ref _description, value); }
+
+ public string CharacterToReplace
+ {
+ get => _characterToReplace;
+
+ set
+ {
+ if (value?.Length != 1 || !ReplacementCharacters.ContainsInvalidPathChar(value))
+ this.RaisePropertyChanged(nameof(CharacterToReplace));
+ else
+ {
+ IsDefault = false;
+ this.RaiseAndSetIfChanged(ref _characterToReplace, value);
+ }
+ }
+ }
+ public char Character => string.IsNullOrEmpty(_characterToReplace) ? default : _characterToReplace[0];
+ public bool IsDefault { get; private set; }
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
-
-
- private void LoadTable(IReadOnlyList replacements)
- {
-
- }
}
}
diff --git a/Source/LibationAvalonia/Dialogs/Login/LoginChoiceEagerDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/Login/LoginChoiceEagerDialog.axaml.cs
index 4871ab16..bbc873d9 100644
--- a/Source/LibationAvalonia/Dialogs/Login/LoginChoiceEagerDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/Login/LoginChoiceEagerDialog.axaml.cs
@@ -31,7 +31,7 @@ namespace LibationAvalonia.Dialogs.Login
DataContext = this;
}
- public async void ExternalLoginLink_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ public async void ExternalLoginLink_Tapped(object sender, Avalonia.Input.TappedEventArgs e)
{
LoginMethod = LoginMethod.External;
await SaveAndCloseAsync();
diff --git a/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs
index e139605b..df263867 100644
--- a/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/MessageBoxAlertAdminDialog.axaml.cs
@@ -28,7 +28,7 @@ namespace LibationAvalonia.Dialogs
DataContext = this;
}
- private async void GoToGithub_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ private async void GoToGithub_Tapped(object sender, Avalonia.Input.TappedEventArgs e)
{
var url = "https://github.com/rmcrackan/Libation/issues";
try
@@ -41,7 +41,7 @@ namespace LibationAvalonia.Dialogs
}
}
- private async void GoToLogs_Tapped(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+ private async void GoToLogs_Tapped(object sender, Avalonia.Input.TappedEventArgs e)
{
LongPath dir = "";
try
diff --git a/Source/LibationAvalonia/Dialogs/MessageBoxWindow.axaml b/Source/LibationAvalonia/Dialogs/MessageBoxWindow.axaml
index 416eebb8..a911a335 100644
--- a/Source/LibationAvalonia/Dialogs/MessageBoxWindow.axaml
+++ b/Source/LibationAvalonia/Dialogs/MessageBoxWindow.axaml
@@ -6,7 +6,7 @@
mc:Ignorable="d" d:DesignWidth="265" d:DesignHeight="110"
MinWidth="265" MinHeight="110"
x:Class="LibationAvalonia.Dialogs.MessageBoxWindow"
- Title="{Binding Caption}" HasSystemDecorations="True" ShowInTaskbar="True"
+ Title="{Binding Caption}" ShowInTaskbar="True"
Icon="/Assets/1x1.png">
@@ -34,13 +34,13 @@
-
diff --git a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs
index 7ea20a55..e05f0da4 100644
--- a/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/SearchSyntaxDialog.axaml.cs
@@ -37,10 +37,13 @@ Find books that you haven't rated:
" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchBoolFields());
IdFields = @"
-Alice's Adventures in Wonderland (ID: B015D78L0U)
+Alice's Adventures in
+ Wonderland (ID: B015D78L0U)
+
id:B015D78L0U
-All of these are synonyms for the ID field
+All of these are synonyms
+for the ID field
" + string.Join("\r\n", LibationSearchEngine.SearchEngine.GetSearchIdFields());
diff --git a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml
index 8468cc15..0224c16c 100644
--- a/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml
+++ b/Source/LibationAvalonia/Dialogs/SettingsDialog.axaml
@@ -23,12 +23,12 @@
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
@@ -174,7 +181,6 @@
diff --git a/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs b/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs
index 7fde4711..788a189c 100644
--- a/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs
+++ b/Source/LibationAvalonia/Views/MainWindow/MainWindow.axaml.cs
@@ -10,6 +10,8 @@ using DataLayer;
using System.Collections.Generic;
using System.Threading.Tasks;
using AppScaffolding;
+using System.Linq;
+using LibationAvalonia.Dialogs;
namespace LibationAvalonia.Views
{
@@ -46,7 +48,6 @@ namespace LibationAvalonia.Views
// misc which belongs in winforms app but doesn't have a UI element
Configure_NonUI();
- _viewModel.ProductsDisplay.InitialLoaded += ProductsDisplay_Initialized;
_viewModel.ProductsDisplay.RemovableCountChanged += ProductsDisplay_RemovableCountChanged;
_viewModel.ProductsDisplay.VisibleCountChanged += ProductsDisplay_VisibleCountChanged;
@@ -172,15 +173,12 @@ namespace LibationAvalonia.Views
Environment.Exit(0);
}
- public void ProductsDisplay_Initialized1(object sender, EventArgs e)
+ private async void MainWindow_LibraryLoaded(object sender, List dbBooks)
{
- if (sender is ProductsDisplay products)
- _viewModel.ProductsDisplay.RegisterCollectionChanged(products);
- }
+ if (QuickFilters.UseDefault)
+ await performFilter(QuickFilters.Filters.FirstOrDefault());
- private void MainWindow_LibraryLoaded(object sender, List dbBooks)
- {
- _viewModel.ProductsDisplay.InitialDisplay(dbBooks);
+ await _viewModel.ProductsDisplay.DisplayBooks(dbBooks);
}
private void InitializeComponent()
@@ -196,10 +194,5 @@ namespace LibationAvalonia.Views
quickFiltersToolStripMenuItem = this.FindControl