diff --git a/Source/FileManager/ReplacementCharacters.cs b/Source/FileManager/ReplacementCharacters.cs
index 550a54c6..c3982286 100644
--- a/Source/FileManager/ReplacementCharacters.cs
+++ b/Source/FileManager/ReplacementCharacters.cs
@@ -15,7 +15,7 @@ namespace FileManager
[JsonIgnore] public bool Mandatory { get; internal set; }
[JsonProperty] public char CharacterToReplace { get; private set; }
[JsonProperty] public string ReplacementString { get; set; }
- [JsonProperty] public string Description { get; private set; }
+ [JsonProperty] public string Description { get; set; }
public override string ToString() => $"{CharacterToReplace} → {ReplacementString} ({Description})";
public Replacement(char charToReplace, string replacementString, string description)
@@ -24,7 +24,7 @@ namespace FileManager
ReplacementString = replacementString;
Description = description;
}
- private Replacement(char charToReplace, string replacementString, string description, bool mandatory)
+ private Replacement(char charToReplace, string replacementString, string description, bool mandatory = false)
: this(charToReplace, replacementString, description)
{
Mandatory = mandatory;
@@ -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/LibationAvalonia/Dialogs/EditReplacementChars.axaml b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
index 84d7a3e5..4926794e 100644
--- a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
+++ b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml
@@ -2,60 +2,68 @@
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..59c91b25 100644
--- a/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs
+++ b/Source/LibationAvalonia/Dialogs/EditReplacementChars.axaml.cs
@@ -1,54 +1,185 @@
-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(config.ReplacementCharacters.Replacements.Select(r => new ReplacementsExt { Replacement = r }));
+ replacements = new(SOURCE);
+
+ if (Design.IsDesignMode)
+ {
+ LoadTable(ReplacementCharacters.Default.Replacements);
+ }
+
DataContext = this;
+
+ replacementGrid = this.FindControl(nameof(replacementGrid));
+ replacementGrid.BeginningEdit += ReplacementGrid_BeginningEdit;
+ replacementGrid.CellEditEnding += ReplacementGrid_CellEditEnding;
+ replacementGrid.KeyDown += ReplacementGrid_KeyDown;
+
}
+ 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))
+ .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();
+ }
+
+ private void ReplacementGrid_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
+ {
+ if (e.Key == Avalonia.Input.Key.Delete
+ && replacementGrid.SelectedItem is ReplacementsExt repl
+ && !repl.Mandatory
+ && !repl.IsDefault)
+ {
+ replacements.Remove(repl);
+ }
+ }
+
+ private 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;
+ }
+
+ private 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/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 @@