diff --git a/Source/FileManager/FileNamingTemplate.cs b/Source/FileManager/FileNamingTemplate.cs index 7b98b5e9..203b9acf 100644 --- a/Source/FileManager/FileNamingTemplate.cs +++ b/Source/FileManager/FileNamingTemplate.cs @@ -105,7 +105,7 @@ namespace FileManager // Other illegal characters will be taken care of later. Must take care of slashes now so params can't introduce new folders. // Esp important for file templates. - return replacements.ReplaceInvalidFilenameChars(value.ToString()); + return replacements.ReplaceFilenameChars(value.ToString()); } } } diff --git a/Source/FileManager/FileUtility.cs b/Source/FileManager/FileUtility.cs index c5476258..03c4f872 100644 --- a/Source/FileManager/FileUtility.cs +++ b/Source/FileManager/FileUtility.cs @@ -84,7 +84,7 @@ namespace FileManager var pathNoPrefix = path.PathWithoutPrefix; - pathNoPrefix = replacements.ReplaceInvalidPathChars(pathNoPrefix); + pathNoPrefix = replacements.ReplacePathChars(pathNoPrefix); pathNoPrefix = removeDoubleSlashes(pathNoPrefix); return pathNoPrefix; diff --git a/Source/FileManager/ReplacementCharacters.cs b/Source/FileManager/ReplacementCharacters.cs index cc93451b..85b65317 100644 --- a/Source/FileManager/ReplacementCharacters.cs +++ b/Source/FileManager/ReplacementCharacters.cs @@ -61,59 +61,108 @@ namespace FileManager [JsonConverter(typeof(ReplacementCharactersConverter))] public class ReplacementCharacters { - public static readonly ReplacementCharacters Default = new() + static ReplacementCharacters() { - Replacements = new List() - { - Replacement.OtherInvalid("_"), - Replacement.FilenameForwardSlash("∕"), - Replacement.FilenameBackSlash(""), - Replacement.OpenQuote("“"), - Replacement.CloseQuote("”"), - Replacement.OtherQuote("""), - Replacement.OpenAngleBracket("<"), - Replacement.CloseAngleBracket(">"), - Replacement.Colon("꞉"), - Replacement.Asterisk("✱"), - Replacement.QuestionMark("?"), - Replacement.Pipe("⏐"), - } - }; - public static readonly ReplacementCharacters LoFiDefault = new() - { - Replacements = new List() + } + public static readonly ReplacementCharacters Default + = IsWindows + ? new() { - Replacement.OtherInvalid("_"), - Replacement.FilenameForwardSlash("_"), - Replacement.FilenameBackSlash("_"), - Replacement.OpenQuote("'"), - Replacement.CloseQuote("'"), - Replacement.OtherQuote("'"), - Replacement.OpenAngleBracket("{"), - Replacement.CloseAngleBracket("}"), - Replacement.Colon("-"), + Replacements = new Replacement[] + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("∕"), + Replacement.FilenameBackSlash(""), + Replacement.OpenQuote("“"), + Replacement.CloseQuote("”"), + Replacement.OtherQuote("""), + Replacement.OpenAngleBracket("<"), + Replacement.CloseAngleBracket(">"), + Replacement.Colon("꞉"), + Replacement.Asterisk("✱"), + Replacement.QuestionMark("?"), + Replacement.Pipe("⏐"), + } } - }; - - public static readonly ReplacementCharacters Barebones = new() - { - Replacements = new List() + : new() { - Replacement.OtherInvalid("_"), - Replacement.FilenameForwardSlash("_"), - Replacement.FilenameBackSlash("_"), - Replacement.OpenQuote("_"), - Replacement.CloseQuote("_"), - Replacement.OtherQuote("_"), - } - }; + Replacements = new Replacement[] + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("∕"), + Replacement.FilenameBackSlash("\\"), + Replacement.OpenQuote("“"), + Replacement.CloseQuote("”"), + Replacement.OtherQuote("\"") + } + }; - private static readonly char[] invalidChars = Path.GetInvalidPathChars().Union(new[] { - '*', '?', ':', - // these are weird. If you run Path.GetInvalidPathChars() in Visual Studio's "C# Interactive", then these characters are included. - // In live code, Path.GetInvalidPathChars() does not include them - '"', '<', '>' + public static readonly ReplacementCharacters LoFiDefault + = IsWindows + ? new() + { + Replacements = new Replacement[] + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("_"), + Replacement.OpenQuote("'"), + Replacement.CloseQuote("'"), + Replacement.OtherQuote("'"), + Replacement.OpenAngleBracket("{"), + Replacement.CloseAngleBracket("}"), + Replacement.Colon("-"), + } + } + : new () + { + Replacements = new Replacement[] + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("\\"), + Replacement.OpenQuote("\""), + Replacement.CloseQuote("\""), + Replacement.OtherQuote("\"") + } + }; + + public static readonly ReplacementCharacters Barebones + = IsWindows + ? new () + { + Replacements = new Replacement[] + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("_"), + Replacement.OpenQuote("_"), + Replacement.CloseQuote("_"), + Replacement.OtherQuote("_") + } + } + : new () + { + Replacements = new Replacement[] + { + Replacement.OtherInvalid("_"), + Replacement.FilenameForwardSlash("_"), + Replacement.FilenameBackSlash("\\"), + Replacement.OpenQuote("\""), + Replacement.CloseQuote("\""), + Replacement.OtherQuote("\"") + } + }; + + private static bool IsWindows => Environment.OSVersion.Platform is PlatformID.Win32NT; + + private static readonly char[] invalidPathChars = Path.GetInvalidFileNameChars().Except(new[] { + Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar + }).ToArray(); + + private static readonly char[] invalidSlashes = Path.GetInvalidFileNameChars().Intersect(new[] { + Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }).ToArray(); public IReadOnlyList Replacements { get; init; } @@ -158,6 +207,10 @@ namespace FileManager return OtherQuote; } + if (!IsWindows && toReplace == BackSlash.CharacterToReplace) + return BackSlash.ReplacementString; + + //Replace any other non-mandatory characters for (int i = Replacement.FIXED_COUNT; i < Replacements.Count; i++) { var r = Replacements[i]; @@ -167,13 +220,12 @@ namespace FileManager return DefaultReplacement; } - public static bool ContainsInvalidPathChar(string path) - => path.Any(c => invalidChars?.Contains(c) == true); + => path.Any(c => invalidPathChars.Contains(c)); public static bool ContainsInvalidFilenameChar(string path) - => path.Any(c => invalidChars?.Concat(new char[] { '\\', '/' })?.Contains(c) == true); + => ContainsInvalidPathChar(path) || path.Any(c => invalidSlashes.Contains(c)); - public string ReplaceInvalidFilenameChars(string fileName) + public string ReplaceFilenameChars(string fileName) { if (string.IsNullOrEmpty(fileName)) return string.Empty; var builder = new System.Text.StringBuilder(); @@ -181,7 +233,9 @@ namespace FileManager { var c = fileName[i]; - if (invalidChars.Contains(c) || c == ForwardSlash.CharacterToReplace || c == BackSlash.CharacterToReplace) + if (invalidPathChars.Contains(c) + || invalidSlashes.Contains(c) + || Replacements.Any(r => r.CharacterToReplace == c) /* Replace any other legal characters that they user wants. */ ) { char preceding = i > 0 ? fileName[i - 1] : default; char succeeding = i < fileName.Length - 1 ? fileName[i + 1] : default; @@ -189,30 +243,42 @@ namespace FileManager } else builder.Append(c); - } return builder.ToString(); } - public string ReplaceInvalidPathChars(string pathStr) + public string ReplacePathChars(string pathStr) { if (string.IsNullOrEmpty(pathStr)) return string.Empty; - // replace all colons except within the first 2 chars var builder = new System.Text.StringBuilder(); for (var i = 0; i < pathStr.Length; i++) { var c = pathStr[i]; - if (!invalidChars.Contains(c) || (c == ':' && i == 1 && Path.IsPathRooted(pathStr))) - builder.Append(c); - else + if ( + ( + invalidPathChars.Contains(c) + || ( // Replace any other legal characters that they user wants. + c != Path.DirectorySeparatorChar + && c != Path.AltDirectorySeparatorChar + && Replacements.Any(r => r.CharacterToReplace == c) + ) + ) + && !( // replace all colons except drive letter designator on Windows + c == ':' + && i == 1 + && Path.IsPathRooted(pathStr) + && IsWindows + ) + ) { - char preceding = i > 0 ? pathStr[i - 1] : default; - char succeeding = i < pathStr.Length - 1 ? pathStr[i + 1] : default; - builder.Append(GetPathCharReplacement(c, preceding, succeeding)); + char preceding = i > 0 ? pathStr[i - 1] : default; + char succeeding = i < pathStr.Length - 1 ? pathStr[i + 1] : default; + builder.Append(GetPathCharReplacement(c, preceding, succeeding)); } - + else + builder.Append(c); } return builder.ToString(); } @@ -234,28 +300,19 @@ namespace FileManager //Ensure that the first 6 replacements are for the expected chars and that all replacement strings are valid. //If not, reset to default. - var default0 = Replacement.OtherInvalid(""); - var default1 = Replacement.FilenameForwardSlash(""); - var default2 = Replacement.FilenameBackSlash(""); - var default3 = Replacement.OpenQuote(""); - var default4 = Replacement.CloseQuote(""); - var default5 = Replacement.OtherQuote(""); - - if (dict.Count < Replacement.FIXED_COUNT || - dict[0].CharacterToReplace != default0.CharacterToReplace || dict[0].Description != default0.Description || - dict[1].CharacterToReplace != default1.CharacterToReplace || dict[1].Description != default1.Description || - dict[2].CharacterToReplace != default2.CharacterToReplace || dict[2].Description != default2.Description || - dict[3].CharacterToReplace != default3.CharacterToReplace || dict[3].Description != default3.Description || - dict[4].CharacterToReplace != default4.CharacterToReplace || dict[4].Description != default4.Description || - dict[5].CharacterToReplace != default5.CharacterToReplace || dict[5].Description != default5.Description || - dict.Any(r => ReplacementCharacters.ContainsInvalidPathChar(r.ReplacementString)) - ) - { - dict = ReplacementCharacters.Default.Replacements; - } - //First FIXED_COUNT are mandatory for (int i = 0; i < Replacement.FIXED_COUNT; i++) + { + if (dict.Count < Replacement.FIXED_COUNT + || dict[i].CharacterToReplace != ReplacementCharacters.Barebones.Replacements[i].CharacterToReplace + || dict[i].Description != ReplacementCharacters.Barebones.Replacements[i].Description) + { + dict = ReplacementCharacters.Default.Replacements; + break; + } + + //First FIXED_COUNT are mandatory dict[i].Mandatory = true; + } return new ReplacementCharacters { Replacements = dict }; } @@ -265,7 +322,7 @@ namespace FileManager ReplacementCharacters replacements = (ReplacementCharacters)value; var propertyNames = replacements.Replacements - .Select(c => JObject.FromObject(c)).ToList(); + .Select(JObject.FromObject).ToList(); var prop = new JProperty(nameof(Replacement), new JArray(propertyNames)); diff --git a/Source/HangoverAvalonia/App.axaml.cs b/Source/HangoverAvalonia/App.axaml.cs index a64b8e22..158a427e 100644 --- a/Source/HangoverAvalonia/App.axaml.cs +++ b/Source/HangoverAvalonia/App.axaml.cs @@ -17,10 +17,12 @@ namespace HangoverAvalonia { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - desktop.MainWindow = new MainWindow + var mainWindow = new MainWindow { - DataContext = new MainWindowViewModel(), + DataContext = new MainVM(), }; + desktop.MainWindow = mainWindow; + mainWindow.OnLoad(); } base.OnFrameworkInitializationCompleted(); diff --git a/Source/HangoverAvalonia/Controls/CheckedListBox.axaml b/Source/HangoverAvalonia/Controls/CheckedListBox.axaml new file mode 100644 index 00000000..f797e06b --- /dev/null +++ b/Source/HangoverAvalonia/Controls/CheckedListBox.axaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/Source/HangoverAvalonia/Controls/CheckedListBox.axaml.cs b/Source/HangoverAvalonia/Controls/CheckedListBox.axaml.cs new file mode 100644 index 00000000..bdcfcf61 --- /dev/null +++ b/Source/HangoverAvalonia/Controls/CheckedListBox.axaml.cs @@ -0,0 +1,104 @@ +using Avalonia; +using Avalonia.Collections; +using Avalonia.Controls; +using HangoverAvalonia.ViewModels; +using ReactiveUI; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace HangoverAvalonia.Controls +{ + public partial class CheckedListBox : UserControl + { + public event EventHandler ItemCheck; + + public static readonly StyledProperty ItemsProperty = + AvaloniaProperty.Register(nameof(Items)); + + public IEnumerable Items { get => GetValue(ItemsProperty); set => SetValue(ItemsProperty, value); } + private CheckedListBoxViewModel _viewModel = new(); + + public IEnumerable CheckedItems => + _viewModel + .CheckboxItems + .Where(i => i.IsChecked) + .Select(i => i.Item); + + public void SetItemChecked(int i, bool isChecked) => _viewModel.CheckboxItems[i].IsChecked = isChecked; + public void SetItemChecked(object item, bool isChecked) + { + var obj = _viewModel.CheckboxItems.SingleOrDefault(i => i.Item == item); + if (obj is not null) + obj.IsChecked = isChecked; + } + + public CheckedListBox() + { + InitializeComponent(); + scroller.DataContext = _viewModel; + _viewModel.CheckedChanged += _viewModel_CheckedChanged; + } + + private void _viewModel_CheckedChanged(object sender, CheckBoxViewModel e) + { + var args = new ItemCheckEventArgs { Item = e.Item, ItemIndex = _viewModel.CheckboxItems.IndexOf(e), IsChecked = e.IsChecked }; + ItemCheck?.Invoke(this, args); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + if (change.Property.Name == nameof(Items) && Items != null) + _viewModel.SetItems(Items); + base.OnPropertyChanged(change); + } + + public class CheckedListBoxViewModel : ViewModelBase + { + public event EventHandler CheckedChanged; + public AvaloniaList CheckboxItems { get; private set; } + + public void SetItems(IEnumerable items) + { + UnsubscribeFromItems(CheckboxItems); + CheckboxItems = new(items.OfType().Select(o => new CheckBoxViewModel { Item = o })); + SubscribeToItems(CheckboxItems); + this.RaisePropertyChanged(nameof(CheckboxItems)); + } + + private void SubscribeToItems(IEnumerable objects) + { + foreach (var i in objects.OfType()) + i.PropertyChanged += I_PropertyChanged; + } + + private void UnsubscribeFromItems(AvaloniaList objects) + { + if (objects is null) return; + + foreach (var i in objects) + i.PropertyChanged -= I_PropertyChanged; + } + private void I_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + CheckedChanged?.Invoke(this, (CheckBoxViewModel)sender); + } + } + public class CheckBoxViewModel : ViewModelBase + { + private bool _isChecked; + public bool IsChecked { get => _isChecked; set => this.RaiseAndSetIfChanged(ref _isChecked, value); } + private object _bookText; + public object Item { get => _bookText; set => this.RaiseAndSetIfChanged(ref _bookText, value); } + } + } + + public class ItemCheckEventArgs : EventArgs + { + public int ItemIndex { get; init; } + public bool IsChecked { get; init; } + public object Item { get; init; } + } +} diff --git a/Source/HangoverAvalonia/HangoverAvalonia.csproj b/Source/HangoverAvalonia/HangoverAvalonia.csproj index 999e7fe2..40795aff 100644 --- a/Source/HangoverAvalonia/HangoverAvalonia.csproj +++ b/Source/HangoverAvalonia/HangoverAvalonia.csproj @@ -50,7 +50,12 @@ - + + + + MainVM.cs + + diff --git a/Source/HangoverAvalonia/Program.cs b/Source/HangoverAvalonia/Program.cs index 426b6853..037d6c57 100644 --- a/Source/HangoverAvalonia/Program.cs +++ b/Source/HangoverAvalonia/Program.cs @@ -1,5 +1,4 @@ using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; using Avalonia.ReactiveUI; using System; diff --git a/Source/HangoverAvalonia/ViewModels/MainVM.Database.cs b/Source/HangoverAvalonia/ViewModels/MainVM.Database.cs new file mode 100644 index 00000000..0e11d5b4 --- /dev/null +++ b/Source/HangoverAvalonia/ViewModels/MainVM.Database.cs @@ -0,0 +1,36 @@ +using HangoverBase; +using ReactiveUI; + +namespace HangoverAvalonia.ViewModels +{ + public partial class MainVM + { + private DatabaseTab _tab; + + private string _databaseFileText; + private bool _databaseFound; + private string _sqlResults; + public string DatabaseFileText { get => _databaseFileText; set => this.RaiseAndSetIfChanged(ref _databaseFileText, value); } + public string SqlQuery { get; set; } + public bool DatabaseFound { get => _databaseFound; set => this.RaiseAndSetIfChanged(ref _databaseFound, value); } + public string SqlResults { get => _sqlResults; set => this.RaiseAndSetIfChanged(ref _sqlResults, value); } + + private void Load_databaseVM() + { + _tab = new(new(() => SqlQuery, s => SqlResults = s, s => SqlResults = s)); + + _tab.LoadDatabaseFile(); + if (_tab.DbFile is null) + { + DatabaseFileText = $"Database file not found"; + DatabaseFound = false; + return; + } + + DatabaseFileText = $"Database file: {_tab.DbFile}"; + DatabaseFound = true; + } + + public void ExecuteQuery() => _tab.ExecuteQuery(); + } +} diff --git a/Source/HangoverAvalonia/ViewModels/MainVM.Deleted.cs b/Source/HangoverAvalonia/ViewModels/MainVM.Deleted.cs new file mode 100644 index 00000000..2c376fd7 --- /dev/null +++ b/Source/HangoverAvalonia/ViewModels/MainVM.Deleted.cs @@ -0,0 +1,41 @@ +using ApplicationServices; +using DataLayer; +using ReactiveUI; +using System.Collections.Generic; + +namespace HangoverAvalonia.ViewModels +{ + public partial class MainVM + { + private List _deletedBooks; + public List DeletedBooks { get => _deletedBooks; set => this.RaiseAndSetIfChanged(ref _deletedBooks, value); } + public string CheckedCountText => $"Checked : {_checkedBooksCount} of {_totalBooksCount}"; + + private int _totalBooksCount = 0; + private int _checkedBooksCount = 0; + public int CheckedBooksCount + { + get => _checkedBooksCount; + set + { + if (_checkedBooksCount != value) + { + _checkedBooksCount = value; + this.RaisePropertyChanged(nameof(CheckedCountText)); + } + } + } + private void Load_deletedVM() + { + reload(); + } + + public void reload() + { + DeletedBooks = DbContexts.GetContext().GetDeletedLibraryBooks(); + _checkedBooksCount = 0; + _totalBooksCount = DeletedBooks.Count; + this.RaisePropertyChanged(nameof(CheckedCountText)); + } + } +} diff --git a/Source/HangoverAvalonia/ViewModels/MainVM.cs b/Source/HangoverAvalonia/ViewModels/MainVM.cs new file mode 100644 index 00000000..340f4a15 --- /dev/null +++ b/Source/HangoverAvalonia/ViewModels/MainVM.cs @@ -0,0 +1,11 @@ +namespace HangoverAvalonia.ViewModels +{ + public partial class MainVM : ViewModelBase + { + public MainVM() + { + Load_databaseVM(); + Load_deletedVM(); + } + } +} diff --git a/Source/HangoverAvalonia/ViewModels/MainWindowViewModel.cs b/Source/HangoverAvalonia/ViewModels/MainWindowViewModel.cs deleted file mode 100644 index a578811b..00000000 --- a/Source/HangoverAvalonia/ViewModels/MainWindowViewModel.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using HangoverBase; -using ReactiveUI; - -namespace HangoverAvalonia.ViewModels -{ - public class MainWindowViewModel : ViewModelBase - { - private DatabaseTab _tab; - - private string _databaseFileText; - private bool _databaseFound; - private string _sqlResults; - public string DatabaseFileText { get => _databaseFileText; set => this.RaiseAndSetIfChanged(ref _databaseFileText, value); } - public string SqlQuery { get; set; } - public bool DatabaseFound { get => _databaseFound; set => this.RaiseAndSetIfChanged(ref _databaseFound, value); } - public string SqlResults { get => _sqlResults; set => this.RaiseAndSetIfChanged(ref _sqlResults, value); } - - public MainWindowViewModel() - { - _tab = new(new(() => SqlQuery, s => SqlResults = s, s => SqlResults = s)); - - _tab.LoadDatabaseFile(); - if (_tab.DbFile is null) - { - DatabaseFileText = $"Database file not found"; - DatabaseFound = false; - return; - } - - DatabaseFileText = $"Database file: {_tab.DbFile}"; - DatabaseFound = true; - } - - public void ExecuteQuery() => _tab.ExecuteQuery(); - } -} diff --git a/Source/HangoverAvalonia/ViewModels/ViewModelBase.cs b/Source/HangoverAvalonia/ViewModels/ViewModelBase.cs index 50908ee3..7425a30b 100644 --- a/Source/HangoverAvalonia/ViewModels/ViewModelBase.cs +++ b/Source/HangoverAvalonia/ViewModels/ViewModelBase.cs @@ -1,7 +1,4 @@ using ReactiveUI; -using System; -using System.Collections.Generic; -using System.Text; namespace HangoverAvalonia.ViewModels { diff --git a/Source/HangoverAvalonia/Views/MainWindow.CLI.cs b/Source/HangoverAvalonia/Views/MainWindow.CLI.cs new file mode 100644 index 00000000..116297f8 --- /dev/null +++ b/Source/HangoverAvalonia/Views/MainWindow.CLI.cs @@ -0,0 +1,11 @@ +namespace HangoverAvalonia.Views +{ + public partial class MainWindow + { + private void cliTab_VisibleChanged(bool isVisible) + { + if (!isVisible) + return; + } + } +} diff --git a/Source/HangoverAvalonia/Views/MainWindow.Database.cs b/Source/HangoverAvalonia/Views/MainWindow.Database.cs new file mode 100644 index 00000000..88f10b4a --- /dev/null +++ b/Source/HangoverAvalonia/Views/MainWindow.Database.cs @@ -0,0 +1,16 @@ +namespace HangoverAvalonia.Views +{ + public partial class MainWindow + { + private void databaseTab_VisibleChanged(bool isVisible) + { + if (!isVisible) + return; + } + + public void Execute_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + _viewModel.ExecuteQuery(); + } + } +} diff --git a/Source/HangoverAvalonia/Views/MainWindow.Deleted.cs b/Source/HangoverAvalonia/Views/MainWindow.Deleted.cs new file mode 100644 index 00000000..2c2341e4 --- /dev/null +++ b/Source/HangoverAvalonia/Views/MainWindow.Deleted.cs @@ -0,0 +1,40 @@ +using ApplicationServices; +using DataLayer; +using HangoverAvalonia.Controls; +using System.Linq; + +namespace HangoverAvalonia.Views +{ + public partial class MainWindow + { + private void deletedTab_VisibleChanged(bool isVisible) + { + if (!isVisible) + return; + + if (_viewModel.DeletedBooks.Count == 0) + _viewModel.reload(); + } + public void Deleted_CheckedListBox_ItemCheck(object sender, ItemCheckEventArgs args) + { + _viewModel.CheckedBooksCount = deletedCbl.CheckedItems.Count(); + } + public void Deleted_CheckAll_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + foreach (var item in deletedCbl.Items) + deletedCbl.SetItemChecked(item, true); + } + public void Deleted_UncheckAll_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + foreach (var item in deletedCbl.Items) + deletedCbl.SetItemChecked(item, false); + } + public void Deleted_Save_Click(object sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var libraryBooksToRestore = deletedCbl.CheckedItems.Cast().ToList(); + var qtyChanges = libraryBooksToRestore.RestoreBooks(); + if (qtyChanges > 0) + _viewModel.reload(); + } + } +} diff --git a/Source/HangoverAvalonia/Views/MainWindow.axaml b/Source/HangoverAvalonia/Views/MainWindow.axaml index b32eb8de..1b849ddf 100644 --- a/Source/HangoverAvalonia/Views/MainWindow.axaml +++ b/Source/HangoverAvalonia/Views/MainWindow.axaml @@ -3,33 +3,36 @@ xmlns:vm="using:HangoverAvalonia.ViewModels" 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="500" + xmlns:controls="clr-namespace:HangoverAvalonia.Controls" + mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="500" Width="800" Height="500" x:Class="HangoverAvalonia.Views.MainWindow" Icon="/Assets/hangover.ico " Title="Hangover: Libation debug and recovery tool"> - - + - - + + + - + Database @@ -52,7 +55,6 @@