Use ReactiveUI.
Sort of fix remove book checkbox column.
This commit is contained in:
parent
5f45d28b9f
commit
6e091230cf
@ -1,35 +1,15 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Utils;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using LibationWinForms.AvaloniaUI.ViewModels;
|
using LibationWinForms.AvaloniaUI.ViewModels;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace LibationWinForms.AvaloniaUI.Controls
|
namespace LibationWinForms.AvaloniaUI.Controls
|
||||||
{
|
{
|
||||||
/// <summary> The purpose of this extension is to immediately commit any check state changes to the viewmodel </summary>
|
/// <summary> The purpose of this extension WAS to immediately commit any check state changes to the viewmodel, but for the life of me I cannot get it to work! </summary>
|
||||||
public partial class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn
|
public partial class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn
|
||||||
{
|
{
|
||||||
protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem)
|
|
||||||
{
|
|
||||||
var ele = base.GenerateEditingElementDirect(cell, dataItem) as CheckBox;
|
|
||||||
ele.Checked += EditingElement_Checked;
|
|
||||||
ele.Unchecked += EditingElement_Checked;
|
|
||||||
ele.Indeterminate += EditingElement_Checked;
|
|
||||||
return ele;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EditingElement_Checked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is CheckBox cbox && cbox.DataContext is GridEntry2 gentry)
|
|
||||||
{
|
|
||||||
gentry.Remove = cbox.IsChecked;
|
|
||||||
FindDataGridParent(cbox)?.CommitEdit(DataGridEditingUnit.Cell, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DataGrid? FindDataGridParent(IControl? control)
|
|
||||||
{
|
|
||||||
if (control?.Parent is null) return null;
|
|
||||||
else if (control?.Parent is DataGrid dg) return dg;
|
|
||||||
else return FindDataGridParent(control?.Parent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
public class BookTags
|
public class BookTags
|
||||||
{
|
{
|
||||||
public string Tags { get; init; }
|
private string _tags;
|
||||||
public bool IsSeries { get; init; }
|
public string Tags { get => _tags; init { _tags = value; HasTags = !string.IsNullOrEmpty(_tags); } }
|
||||||
public bool HasTags => !string.IsNullOrEmpty(Tags);
|
public bool HasTags { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
SomeRemoved
|
SomeRemoved
|
||||||
}
|
}
|
||||||
/// <summary>The View Model base for the DataGridView</summary>
|
/// <summary>The View Model base for the DataGridView</summary>
|
||||||
public abstract class GridEntry2 : AsyncNotifyPropertyChanged2, IMemberComparable
|
public abstract class GridEntry2 : ViewModelBase
|
||||||
{
|
{
|
||||||
[Browsable(false)] public string AudibleProductId => Book.AudibleProductId;
|
[Browsable(false)] public string AudibleProductId => Book.AudibleProductId;
|
||||||
[Browsable(false)] public LibraryBook LibraryBook { get; protected set; }
|
[Browsable(false)] public LibraryBook LibraryBook { get; protected set; }
|
||||||
@ -32,30 +32,35 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
|
|
||||||
#region Model properties exposed to the view
|
#region Model properties exposed to the view
|
||||||
|
|
||||||
|
private Avalonia.Media.Imaging.Bitmap _cover;
|
||||||
|
private string _purchaseDate;
|
||||||
|
private string _series;
|
||||||
|
private string _title;
|
||||||
|
private string _length;
|
||||||
|
private string _authors;
|
||||||
|
private string _narrators;
|
||||||
|
private string _category;
|
||||||
|
private string _misc;
|
||||||
|
private string _description;
|
||||||
|
private string _productRating;
|
||||||
|
private string _myRating;
|
||||||
|
public Avalonia.Media.Imaging.Bitmap Cover { get => _cover; protected set { this.RaiseAndSetIfChanged(ref _cover, value); } }
|
||||||
|
public string PurchaseDate { get => _purchaseDate; protected set { this.RaiseAndSetIfChanged(ref _purchaseDate, value); } }
|
||||||
|
public string Series { get => _series; protected set { this.RaiseAndSetIfChanged(ref _series, value); } }
|
||||||
|
public string Title { get => _title; protected set { this.RaiseAndSetIfChanged(ref _title, value); } }
|
||||||
|
public string Length { get => _length; protected set { this.RaiseAndSetIfChanged(ref _length, value); } }
|
||||||
|
public string Authors { get => _authors; protected set { this.RaiseAndSetIfChanged(ref _authors, value); } }
|
||||||
|
public string Narrators { get => _narrators; protected set { this.RaiseAndSetIfChanged(ref _narrators, value); } }
|
||||||
|
public string Category { get => _category; protected set { this.RaiseAndSetIfChanged(ref _category, value); } }
|
||||||
|
public string Misc { get => _misc; protected set { this.RaiseAndSetIfChanged(ref _misc, value); } }
|
||||||
|
public string Description { get => _description; protected set { this.RaiseAndSetIfChanged(ref _description, value); } }
|
||||||
|
public string ProductRating { get => _productRating; protected set { this.RaiseAndSetIfChanged(ref _productRating, value); } }
|
||||||
|
public string MyRating { get => _myRating; protected set { this.RaiseAndSetIfChanged(ref _myRating, value); } }
|
||||||
|
|
||||||
|
|
||||||
protected bool? _remove = false;
|
protected bool? _remove = false;
|
||||||
public abstract bool? Remove { get; set; }
|
public abstract bool? Remove { get; set; }
|
||||||
|
|
||||||
public abstract LiberateButtonStatus2 Liberate { get; }
|
public abstract LiberateButtonStatus2 Liberate { get; }
|
||||||
public Avalonia.Media.Imaging.Bitmap Cover
|
|
||||||
{
|
|
||||||
get => _cover;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
_cover = value;
|
|
||||||
NotifyPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string PurchaseDate { get; protected set; }
|
|
||||||
public string Series { get; protected set; }
|
|
||||||
public string Title { get; protected set; }
|
|
||||||
public string Length { get; protected set; }
|
|
||||||
public string Authors { get; set; }
|
|
||||||
public string Narrators { get; protected set; }
|
|
||||||
public string Category { get; protected set; }
|
|
||||||
public string Misc { get; protected set; }
|
|
||||||
public string Description { get; protected set; }
|
|
||||||
public string ProductRating { get; protected set; }
|
|
||||||
public string MyRating { get; protected set; }
|
|
||||||
public abstract BookTags BookTags { get; }
|
public abstract BookTags BookTags { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -87,7 +92,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
|
|
||||||
#region Cover Art
|
#region Cover Art
|
||||||
|
|
||||||
private Avalonia.Media.Imaging.Bitmap _cover;
|
|
||||||
protected void LoadCover()
|
protected void LoadCover()
|
||||||
{
|
{
|
||||||
// Get cover art. If it's default, subscribe to PictureCached
|
// Get cover art. If it's default, subscribe to PictureCached
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using DataLayer;
|
using DataLayer;
|
||||||
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace LibationWinForms.AvaloniaUI.ViewModels
|
namespace LibationWinForms.AvaloniaUI.ViewModels
|
||||||
{
|
{
|
||||||
public class LiberateButtonStatus2 : IComparable, INotifyPropertyChanged
|
public class LiberateButtonStatus2 : ViewModelBase, IComparable
|
||||||
{
|
{
|
||||||
public LiberatedStatus BookStatus { get; set; }
|
public LiberatedStatus BookStatus { get; set; }
|
||||||
public LiberatedStatus? PdfStatus { get; set; }
|
public LiberatedStatus? PdfStatus { get; set; }
|
||||||
@ -18,10 +17,9 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
get => _expanded;
|
get => _expanded;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_expanded = value;
|
this.RaiseAndSetIfChanged(ref _expanded, value);
|
||||||
NotifyPropertyChanged();
|
this.RaisePropertyChanged(nameof(Image));
|
||||||
NotifyPropertyChanged(nameof(Image));
|
this.RaisePropertyChanged(nameof(ToolTip));
|
||||||
NotifyPropertyChanged(nameof(ToolTip));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public bool IsSeries { get; init; }
|
public bool IsSeries { get; init; }
|
||||||
@ -30,13 +28,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
|
|
||||||
static Dictionary<string, Bitmap> images = new();
|
static Dictionary<string, Bitmap> images = new();
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
/// <summary> Defines the Liberate column's sorting behavior </summary>
|
||||||
|
|
||||||
public void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the Liberate column's sorting behavior
|
|
||||||
/// </summary>
|
|
||||||
public int CompareTo(object obj)
|
public int CompareTo(object obj)
|
||||||
{
|
{
|
||||||
if (obj is not LiberateButtonStatus2 second) return -1;
|
if (obj is not LiberateButtonStatus2 second) return -1;
|
||||||
@ -49,14 +41,13 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
else return BookStatus.CompareTo(second.BookStatus);
|
else return BookStatus.CompareTo(second.BookStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Bitmap GetLiberateIcon()
|
private Bitmap GetLiberateIcon()
|
||||||
{
|
{
|
||||||
if (IsSeries)
|
if (IsSeries)
|
||||||
return Expanded ? GetFromresc("minus") : GetFromresc("plus");
|
return Expanded ? GetFromResources("minus") : GetFromResources("plus");
|
||||||
|
|
||||||
if (BookStatus == LiberatedStatus.Error)
|
if (BookStatus == LiberatedStatus.Error)
|
||||||
return GetFromresc("error");
|
return GetFromResources("error");
|
||||||
|
|
||||||
string image_lib = BookStatus switch
|
string image_lib = BookStatus switch
|
||||||
{
|
{
|
||||||
@ -75,7 +66,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
_ => throw new Exception("Unexpected PDF state")
|
_ => throw new Exception("Unexpected PDF state")
|
||||||
};
|
};
|
||||||
|
|
||||||
return GetFromresc($"liberate_{image_lib}{image_pdf}");
|
return GetFromResources($"liberate_{image_lib}{image_pdf}");
|
||||||
}
|
}
|
||||||
private string GetTooltip()
|
private string GetTooltip()
|
||||||
{
|
{
|
||||||
@ -113,7 +104,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
return mouseoverText;
|
return mouseoverText;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap GetFromresc(string rescName)
|
private static Bitmap GetFromResources(string rescName)
|
||||||
{
|
{
|
||||||
if (images.ContainsKey(rescName)) return images[rescName];
|
if (images.ContainsKey(rescName)) return images[rescName];
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using LibationWinForms.GridView;
|
using LibationWinForms.GridView;
|
||||||
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@ -27,8 +28,9 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_remove = value.HasValue ? value.Value : false;
|
_remove = value.HasValue ? value.Value : false;
|
||||||
|
|
||||||
Parent?.ChildRemoveUpdate();
|
Parent?.ChildRemoveUpdate();
|
||||||
NotifyPropertyChanged();
|
this.RaisePropertyChanged(nameof(Remove));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,20 +86,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
Description = TrimTextToWord(LongDescription, 62);
|
Description = TrimTextToWord(LongDescription, 62);
|
||||||
SeriesIndex = Book.SeriesLink.FirstOrDefault()?.Index ?? 0;
|
SeriesIndex = Book.SeriesLink.FirstOrDefault()?.Index ?? 0;
|
||||||
|
|
||||||
NotifyPropertyChanged(nameof(Title));
|
|
||||||
NotifyPropertyChanged(nameof(Series));
|
|
||||||
NotifyPropertyChanged(nameof(Length));
|
|
||||||
NotifyPropertyChanged(nameof(MyRating));
|
|
||||||
NotifyPropertyChanged(nameof(PurchaseDate));
|
|
||||||
NotifyPropertyChanged(nameof(ProductRating));
|
|
||||||
NotifyPropertyChanged(nameof(Authors));
|
|
||||||
NotifyPropertyChanged(nameof(Narrators));
|
|
||||||
NotifyPropertyChanged(nameof(Category));
|
|
||||||
NotifyPropertyChanged(nameof(Misc));
|
|
||||||
NotifyPropertyChanged(nameof(LongDescription));
|
|
||||||
NotifyPropertyChanged(nameof(Description));
|
|
||||||
NotifyPropertyChanged(nameof(SeriesIndex));
|
|
||||||
|
|
||||||
UserDefinedItem.ItemChanged += UserDefinedItem_ItemChanged;
|
UserDefinedItem.ItemChanged += UserDefinedItem_ItemChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,17 +109,17 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
{
|
{
|
||||||
case nameof(udi.Tags):
|
case nameof(udi.Tags):
|
||||||
Book.UserDefinedItem.Tags = udi.Tags;
|
Book.UserDefinedItem.Tags = udi.Tags;
|
||||||
NotifyPropertyChanged(nameof(BookTags));
|
this.RaisePropertyChanged(nameof(BookTags));
|
||||||
break;
|
break;
|
||||||
case nameof(udi.BookStatus):
|
case nameof(udi.BookStatus):
|
||||||
Book.UserDefinedItem.BookStatus = udi.BookStatus;
|
Book.UserDefinedItem.BookStatus = udi.BookStatus;
|
||||||
_bookStatus = udi.BookStatus;
|
_bookStatus = udi.BookStatus;
|
||||||
NotifyPropertyChanged(nameof(Liberate));
|
this.RaisePropertyChanged(nameof(Liberate));
|
||||||
break;
|
break;
|
||||||
case nameof(udi.PdfStatus):
|
case nameof(udi.PdfStatus):
|
||||||
Book.UserDefinedItem.PdfStatus = udi.PdfStatus;
|
Book.UserDefinedItem.PdfStatus = udi.PdfStatus;
|
||||||
_pdfStatus = udi.PdfStatus;
|
_pdfStatus = udi.PdfStatus;
|
||||||
NotifyPropertyChanged(nameof(Liberate));
|
this.RaisePropertyChanged(nameof(Liberate));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ApplicationServices;
|
using ApplicationServices;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
@ -10,6 +8,7 @@ using DataLayer;
|
|||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using FileLiberator;
|
using FileLiberator;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace LibationWinForms.AvaloniaUI.ViewModels
|
namespace LibationWinForms.AvaloniaUI.ViewModels
|
||||||
{
|
{
|
||||||
@ -36,10 +35,9 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is the viewmodel for queued processables
|
/// This is the viewmodel for queued processables
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProcessBook2 : INotifyPropertyChanged
|
public class ProcessBook2 : ViewModelBase
|
||||||
{
|
{
|
||||||
public event EventHandler Completed;
|
public event EventHandler Completed;
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
public LibraryBook LibraryBook { get; private set; }
|
public LibraryBook LibraryBook { get; private set; }
|
||||||
|
|
||||||
@ -53,14 +51,14 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
private Bitmap _cover;
|
private Bitmap _cover;
|
||||||
|
|
||||||
#region Properties exposed to the view
|
#region Properties exposed to the view
|
||||||
public ProcessBookResult Result { get => _result; set { _result = value; NotifyPropertyChanged(); NotifyPropertyChanged(nameof(StatusText)); } }
|
public ProcessBookResult Result { get => _result; set { this.RaiseAndSetIfChanged(ref _result, value); this.RaisePropertyChanged(nameof(StatusText)); } }
|
||||||
public ProcessBookStatus Status { get => _status; set { _status = value; NotifyPropertyChanged(); NotifyPropertyChanged(nameof(BackgroundColor)); NotifyPropertyChanged(nameof(IsFinished)); NotifyPropertyChanged(nameof(IsDownloading)); NotifyPropertyChanged(nameof(Queued)); } }
|
public ProcessBookStatus Status { get => _status; set { this.RaiseAndSetIfChanged(ref _status, value); this.RaisePropertyChanged(nameof(BackgroundColor)); this.RaisePropertyChanged(nameof(IsFinished)); this.RaisePropertyChanged(nameof(IsDownloading)); this.RaisePropertyChanged(nameof(Queued)); } }
|
||||||
public string Narrator { get => _narrator; set { _narrator = value; NotifyPropertyChanged(); } }
|
public string Narrator { get => _narrator; set { this.RaiseAndSetIfChanged(ref _narrator, value); } }
|
||||||
public string Author { get => _author; set { _author = value; NotifyPropertyChanged(); } }
|
public string Author { get => _author; set { this.RaiseAndSetIfChanged(ref _author, value); } }
|
||||||
public string Title { get => _title; set { _title = value; NotifyPropertyChanged(); } }
|
public string Title { get => _title; set { this.RaiseAndSetIfChanged(ref _title, value); } }
|
||||||
public int Progress { get => _progress; private set { _progress = value; NotifyPropertyChanged(); } }
|
public int Progress { get => _progress; private set { this.RaiseAndSetIfChanged(ref _progress, value); } }
|
||||||
public string ETA { get => _eta; private set { _eta = value; NotifyPropertyChanged(); } }
|
public string ETA { get => _eta; private set { this.RaiseAndSetIfChanged(ref _eta, value); } }
|
||||||
public Bitmap Cover { get => _cover; private set { _cover = value; NotifyPropertyChanged(); } }
|
public Bitmap Cover { get => _cover; private set { this.RaiseAndSetIfChanged(ref _cover, value); } }
|
||||||
public bool IsFinished => Status is not ProcessBookStatus.Queued and not ProcessBookStatus.Working;
|
public bool IsFinished => Status is not ProcessBookStatus.Queued and not ProcessBookStatus.Working;
|
||||||
public bool IsDownloading => Status is ProcessBookStatus.Working;
|
public bool IsDownloading => Status is ProcessBookStatus.Working;
|
||||||
public bool Queued => Status is ProcessBookStatus.Queued;
|
public bool Queued => Status is ProcessBookStatus.Queued;
|
||||||
@ -91,8 +89,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
private Processable _currentProcessable;
|
private Processable _currentProcessable;
|
||||||
private readonly Queue<Func<Processable>> Processes = new();
|
private readonly Queue<Func<Processable>> Processes = new();
|
||||||
private readonly ProcessQueue.LogMe Logger;
|
private readonly ProcessQueue.LogMe Logger;
|
||||||
public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
|
||||||
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
|
|
||||||
public ProcessBook2(LibraryBook libraryBook, ProcessQueue.LogMe logme)
|
public ProcessBook2(LibraryBook libraryBook, ProcessQueue.LogMe logme)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -7,19 +7,14 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
{
|
{
|
||||||
public class ProcessQueueViewModel : ViewModelBase, ProcessQueue.ILogForm
|
public class ProcessQueueViewModel : ViewModelBase, ProcessQueue.ILogForm
|
||||||
{
|
{
|
||||||
|
public ObservableCollection<LogEntry> LogEntries { get; } = new();
|
||||||
public string QueueHeader => "this is a header!";
|
|
||||||
private TrackedQueue2<ProcessBook2> _items = new();
|
private TrackedQueue2<ProcessBook2> _items = new();
|
||||||
public ProcessQueueViewModel() { }
|
|
||||||
public TrackedQueue2<ProcessBook2> Items
|
public TrackedQueue2<ProcessBook2> Items
|
||||||
{
|
{
|
||||||
get => _items;
|
get => _items;
|
||||||
set => this.RaiseAndSetIfChanged(ref _items, value);
|
set => this.RaiseAndSetIfChanged(ref _items, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ObservableCollection<LogEntry> LogEntries { get; } = new();
|
|
||||||
|
|
||||||
public ProcessBook2 SelectedItem { get; set; }
|
public ProcessBook2 SelectedItem { get; set; }
|
||||||
|
|
||||||
public void WriteLine(string text)
|
public void WriteLine(string text)
|
||||||
@ -31,7 +26,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
LogMessage = text.Trim()
|
LogMessage = text.Trim()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LogEntry
|
public class LogEntry
|
||||||
@ -40,5 +34,4 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
public string LogDateString => LogDate.ToShortTimeString();
|
public string LogDateString => LogDate.ToShortTimeString();
|
||||||
public string LogMessage { get; init; }
|
public string LogMessage { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
using DataLayer;
|
using DataLayer;
|
||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using LibationWinForms.GridView;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@ -21,13 +21,8 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
|
|
||||||
var removeCount = Children.Count(c => c.Remove == true);
|
var removeCount = Children.Count(c => c.Remove == true);
|
||||||
|
|
||||||
if (removeCount == 0)
|
_remove = removeCount == 0 ? false : (removeCount == Children.Count ? true : null);
|
||||||
_remove = false;
|
this.RaisePropertyChanged(nameof(Remove));
|
||||||
else if (removeCount == Children.Count)
|
|
||||||
_remove = true;
|
|
||||||
else
|
|
||||||
_remove = null;
|
|
||||||
NotifyPropertyChanged(nameof(Remove));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Model properties exposed to the view
|
#region Model properties exposed to the view
|
||||||
@ -36,7 +31,7 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
get => _remove;
|
get => _remove;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_remove = value.HasValue ? value : false;
|
_remove = value.HasValue ? value.Value : false;
|
||||||
|
|
||||||
suspendCounting = true;
|
suspendCounting = true;
|
||||||
|
|
||||||
@ -44,13 +39,12 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
item.Remove = value;
|
item.Remove = value;
|
||||||
|
|
||||||
suspendCounting = false;
|
suspendCounting = false;
|
||||||
|
this.RaisePropertyChanged(nameof(Remove));
|
||||||
NotifyPropertyChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override LiberateButtonStatus2 Liberate { get; }
|
public override LiberateButtonStatus2 Liberate { get; }
|
||||||
public override BookTags BookTags { get; } = new() { IsSeries = true };
|
public override BookTags BookTags { get; } = new();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -95,19 +89,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
|
|
||||||
int bookLenMins = Children.Sum(c => c.LibraryBook.Book.LengthInMinutes);
|
int bookLenMins = Children.Sum(c => c.LibraryBook.Book.LengthInMinutes);
|
||||||
Length = bookLenMins == 0 ? "" : $"{bookLenMins / 60} hr {bookLenMins % 60} min";
|
Length = bookLenMins == 0 ? "" : $"{bookLenMins / 60} hr {bookLenMins % 60} min";
|
||||||
|
|
||||||
NotifyPropertyChanged(nameof(Title));
|
|
||||||
NotifyPropertyChanged(nameof(Series));
|
|
||||||
NotifyPropertyChanged(nameof(Length));
|
|
||||||
NotifyPropertyChanged(nameof(MyRating));
|
|
||||||
NotifyPropertyChanged(nameof(PurchaseDate));
|
|
||||||
NotifyPropertyChanged(nameof(ProductRating));
|
|
||||||
NotifyPropertyChanged(nameof(Authors));
|
|
||||||
NotifyPropertyChanged(nameof(Narrators));
|
|
||||||
NotifyPropertyChanged(nameof(Category));
|
|
||||||
NotifyPropertyChanged(nameof(Misc));
|
|
||||||
NotifyPropertyChanged(nameof(LongDescription));
|
|
||||||
NotifyPropertyChanged(nameof(Description));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Data Sorting
|
#region Data Sorting
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -7,5 +8,6 @@ namespace LibationWinForms.AvaloniaUI.ViewModels
|
|||||||
{
|
{
|
||||||
public class ViewModelBase : ReactiveObject
|
public class ViewModelBase : ReactiveObject
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<DataGrid Name="productsGrid" AutoGenerateColumns="False" Items="{Binding GridEntries}">
|
<DataGrid Name="productsGrid" AutoGenerateColumns="False" Items="{Binding GridEntries}">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
|
|
||||||
<controls:DataGridCheckBoxColumnExt IsVisible="False" Header="Remove" IsThreeState="True" IsReadOnly="False" CanUserSort="True" Binding="{Binding Remove, Mode=TwoWay}" Width="70" SortMemberPath="Remove"/>
|
<controls:DataGridCheckBoxColumnExt IsVisible="True" Header="Remove" IsThreeState="True" IsReadOnly="False" CanUserSort="True" Binding="{Binding Remove, Mode=TwoWay}" Width="70" SortMemberPath="Remove"/>
|
||||||
|
|
||||||
<DataGridTemplateColumn CanUserSort="True" Width="75" Header="Liberate" SortMemberPath="Liberate">
|
<DataGridTemplateColumn CanUserSort="True" Width="75" Header="Liberate" SortMemberPath="Liberate">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
@ -147,7 +147,7 @@
|
|||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Button IsVisible="{Binding !BookTags.IsSeries}" Width="100" Height="80" Click="OnTagsButtonClick" ToolTip.Tip="Click to edit tags" >
|
<Button IsVisible="{Binding !Liberate.IsSeries}" Width="100" Height="80" Click="OnTagsButtonClick" ToolTip.Tip="Click to edit tags" >
|
||||||
<Panel>
|
<Panel>
|
||||||
<Image IsVisible="{Binding !BookTags.HasTags}" Stretch="None" Source="/AvaloniaUI/Assets/edit_25x25.png" />
|
<Image IsVisible="{Binding !BookTags.HasTags}" Stretch="None" Source="/AvaloniaUI/Assets/edit_25x25.png" />
|
||||||
<TextBlock IsVisible="{Binding BookTags.HasTags}" FontSize="12" TextWrapping="WrapWithOverflow" Text="{Binding BookTags.Tags}"/>
|
<TextBlock IsVisible="{Binding BookTags.HasTags}" FontSize="12" TextWrapping="WrapWithOverflow" Text="{Binding BookTags.Tags}"/>
|
||||||
|
|||||||
@ -9,6 +9,7 @@ using Dinah.Core.DataBinding;
|
|||||||
using FileLiberator;
|
using FileLiberator;
|
||||||
using LibationFileManager;
|
using LibationFileManager;
|
||||||
using LibationWinForms.AvaloniaUI.ViewModels;
|
using LibationWinForms.AvaloniaUI.ViewModels;
|
||||||
|
using ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -38,6 +39,20 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
DataGridColumn removeGVColumn;
|
DataGridColumn removeGVColumn;
|
||||||
|
DataGridColumn liberateGVColumn;
|
||||||
|
DataGridColumn coverGVColumn;
|
||||||
|
DataGridColumn titleGVColumn;
|
||||||
|
DataGridColumn authorsGVColumn;
|
||||||
|
DataGridColumn narratorsGVColumn;
|
||||||
|
DataGridColumn lengthGVColumn;
|
||||||
|
DataGridColumn seriesGVColumn;
|
||||||
|
DataGridColumn descriptionGVColumn;
|
||||||
|
DataGridColumn categoryGVColumn;
|
||||||
|
DataGridColumn productRatingGVColumn;
|
||||||
|
DataGridColumn purchaseDateGVColumn;
|
||||||
|
DataGridColumn myRatingGVColumn;
|
||||||
|
DataGridColumn miscGVColumn;
|
||||||
|
DataGridColumn tagAndDetailsGVColumn;
|
||||||
public ProductsDisplay2()
|
public ProductsDisplay2()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@ -45,16 +60,79 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
productsGrid = this.FindControl<DataGrid>(nameof(productsGrid));
|
productsGrid = this.FindControl<DataGrid>(nameof(productsGrid));
|
||||||
productsGrid.Sorting += Dg1_Sorting;
|
productsGrid.Sorting += Dg1_Sorting;
|
||||||
productsGrid.CanUserSortColumns = true;
|
productsGrid.CanUserSortColumns = true;
|
||||||
|
productsGrid.LoadingRow += ProductsGrid_LoadingRow;
|
||||||
|
|
||||||
removeGVColumn = productsGrid.Columns[0];
|
removeGVColumn = productsGrid.Columns[0];
|
||||||
|
liberateGVColumn = productsGrid.Columns[1];
|
||||||
|
coverGVColumn = productsGrid.Columns[2];
|
||||||
|
titleGVColumn = productsGrid.Columns[3];
|
||||||
|
authorsGVColumn = productsGrid.Columns[4];
|
||||||
|
narratorsGVColumn = productsGrid.Columns[5];
|
||||||
|
lengthGVColumn = productsGrid.Columns[6];
|
||||||
|
seriesGVColumn = productsGrid.Columns[7];
|
||||||
|
descriptionGVColumn = productsGrid.Columns[8];
|
||||||
|
categoryGVColumn = productsGrid.Columns[9];
|
||||||
|
productRatingGVColumn = productsGrid.Columns[10];
|
||||||
|
purchaseDateGVColumn = productsGrid.Columns[11];
|
||||||
|
myRatingGVColumn = productsGrid.Columns[12];
|
||||||
|
miscGVColumn = productsGrid.Columns[13];
|
||||||
|
tagAndDetailsGVColumn = productsGrid.Columns[14];
|
||||||
|
|
||||||
|
removeGVColumn.CustomSortComparer = new RowComparer(removeGVColumn);
|
||||||
|
liberateGVColumn.CustomSortComparer = new RowComparer(liberateGVColumn);
|
||||||
|
titleGVColumn.CustomSortComparer = new RowComparer(titleGVColumn);
|
||||||
|
authorsGVColumn.CustomSortComparer = new RowComparer(authorsGVColumn);
|
||||||
|
narratorsGVColumn.CustomSortComparer = new RowComparer(narratorsGVColumn);
|
||||||
|
lengthGVColumn.CustomSortComparer = new RowComparer(lengthGVColumn);
|
||||||
|
seriesGVColumn.CustomSortComparer = new RowComparer(seriesGVColumn);
|
||||||
|
descriptionGVColumn.CustomSortComparer = new RowComparer(descriptionGVColumn);
|
||||||
|
categoryGVColumn.CustomSortComparer = new RowComparer(categoryGVColumn);
|
||||||
|
productRatingGVColumn.CustomSortComparer = new RowComparer(productRatingGVColumn);
|
||||||
|
purchaseDateGVColumn.CustomSortComparer = new RowComparer(purchaseDateGVColumn);
|
||||||
|
myRatingGVColumn.CustomSortComparer = new RowComparer(myRatingGVColumn);
|
||||||
|
miscGVColumn.CustomSortComparer = new RowComparer(miscGVColumn);
|
||||||
|
tagAndDetailsGVColumn.CustomSortComparer = new RowComparer(tagAndDetailsGVColumn);
|
||||||
|
|
||||||
|
removeGVColumn.PropertyChanged += RemoveGVColumn_PropertyChanged;
|
||||||
|
|
||||||
if (Design.IsDesignMode)
|
if (Design.IsDesignMode)
|
||||||
{
|
{
|
||||||
using var context = DbContexts.GetContext();
|
using var context = DbContexts.GetContext();
|
||||||
var book = context.GetLibraryBook_Flat_NoTracking("B017V4IM1G");
|
var book = context.GetLibraryBook_Flat_NoTracking("B017V4IM1G");
|
||||||
productsGrid.DataContext = _viewModel = new ProductsDisplayViewModel(new List<LibraryBook> { book });
|
productsGrid.DataContext = _viewModel = new ProductsDisplayViewModel(new List<LibraryBook> { book });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RemoveGVColumn_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object tagObj = new();
|
||||||
|
private static readonly IBrush SeriesBgColor = Brush.Parse("#ffe6ffe6");
|
||||||
|
|
||||||
|
private void ProductsGrid_LoadingRow(object sender, DataGridRowEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Row.Tag == tagObj)
|
||||||
|
return;
|
||||||
|
e.Row.Tag = tagObj;
|
||||||
|
|
||||||
|
static IBrush GetRowColor(DataGridRow row)
|
||||||
|
=> row.DataContext is GridEntry2 gEntry
|
||||||
|
&& gEntry is LibraryBookEntry2 lbEntry
|
||||||
|
&& lbEntry.Parent is not null
|
||||||
|
? SeriesBgColor
|
||||||
|
: null;
|
||||||
|
|
||||||
|
e.Row.Background = GetRowColor(e.Row);
|
||||||
|
e.Row.DataContextChanged += (sender, e) =>
|
||||||
|
{
|
||||||
|
var row = sender as DataGridRow;
|
||||||
|
row.Background = GetRowColor(row);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
@ -69,6 +147,12 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
public string PropertyName { get; init; }
|
public string PropertyName { get; init; }
|
||||||
public ListSortDirection? SortDirection { get; set; }
|
public ListSortDirection? SortDirection { get; set; }
|
||||||
|
|
||||||
|
public RowComparer(DataGridColumn column)
|
||||||
|
{
|
||||||
|
Column = column;
|
||||||
|
PropertyName = column.SortMemberPath;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This compare method ensures that all top-level grid entries (standalone books or series parents)
|
/// This compare method ensures that all top-level grid entries (standalone books or series parents)
|
||||||
/// are sorted by PropertyName while all episodes remain immediately beneath their parents and remain
|
/// are sorted by PropertyName while all episodes remain immediately beneath their parents and remain
|
||||||
@ -137,24 +221,15 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<DataGridColumn, RowComparer> ColumnComparers = new();
|
|
||||||
DataGridColumn CurrentSortColumn;
|
DataGridColumn CurrentSortColumn;
|
||||||
|
|
||||||
private void Dg1_Sorting(object sender, DataGridColumnEventArgs e)
|
private void Dg1_Sorting(object sender, DataGridColumnEventArgs e)
|
||||||
{
|
{
|
||||||
if (!ColumnComparers.ContainsKey(e.Column))
|
var comparer = e.Column.CustomSortComparer as RowComparer;
|
||||||
ColumnComparers[e.Column] = new RowComparer
|
|
||||||
{
|
|
||||||
Column = e.Column,
|
|
||||||
PropertyName = e.Column.SortMemberPath
|
|
||||||
};
|
|
||||||
|
|
||||||
//Force the comparer to get the current sort order. We can't
|
//Force the comparer to get the current sort order. We can't
|
||||||
//retrieve it from inside this event handler because Avalonia
|
//retrieve it from inside this event handler because Avalonia
|
||||||
//doesn't set the property until after this event.
|
//doesn't set the property until after this event.
|
||||||
ColumnComparers[e.Column].SortDirection = null;
|
comparer.SortDirection = null;
|
||||||
|
|
||||||
e.Column.CustomSortComparer = ColumnComparers[e.Column];
|
|
||||||
CurrentSortColumn = e.Column;
|
CurrentSortColumn = e.Column;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,8 +466,8 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
|
|
||||||
//In Avalonia, if you fire PropertyChanged with an empty or invalid property name, nothing is updated.
|
//In Avalonia, if you fire PropertyChanged with an empty or invalid property name, nothing is updated.
|
||||||
//So we must notify for specific properties that we believed changed.
|
//So we must notify for specific properties that we believed changed.
|
||||||
removed.Parent.NotifyPropertyChanged(nameof(SeriesEntrys2.Length));
|
removed.Parent.RaisePropertyChanged(nameof(SeriesEntrys2.Length));
|
||||||
removed.Parent.NotifyPropertyChanged(nameof(SeriesEntrys2.PurchaseDate));
|
removed.Parent.RaisePropertyChanged(nameof(SeriesEntrys2.PurchaseDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove series that have no children
|
//Remove series that have no children
|
||||||
@ -466,8 +541,8 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
else
|
else
|
||||||
bindingList.CollapseItem(seriesEntry);
|
bindingList.CollapseItem(seriesEntry);
|
||||||
|
|
||||||
seriesEntry.NotifyPropertyChanged(nameof(SeriesEntrys2.Length));
|
seriesEntry.RaisePropertyChanged(nameof(SeriesEntrys2.Length));
|
||||||
seriesEntry.NotifyPropertyChanged(nameof(SeriesEntrys2.PurchaseDate));
|
seriesEntry.RaisePropertyChanged(nameof(SeriesEntrys2.PurchaseDate));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
existingEpisodeEntry.UpdateLibraryBook(episodeBook);
|
existingEpisodeEntry.UpdateLibraryBook(episodeBook);
|
||||||
@ -493,7 +568,9 @@ namespace LibationWinForms.AvaloniaUI.Views
|
|||||||
if (CurrentSortColumn is null)
|
if (CurrentSortColumn is null)
|
||||||
bindingList.InternalList.Sort((i1, i2) => i2.DateAdded.CompareTo(i1.DateAdded));
|
bindingList.InternalList.Sort((i1, i2) => i2.DateAdded.CompareTo(i1.DateAdded));
|
||||||
else
|
else
|
||||||
CurrentSortColumn?.Sort(ColumnComparers[CurrentSortColumn].SortDirection.Value);
|
{
|
||||||
|
CurrentSortColumn.Sort(((RowComparer)CurrentSortColumn.CustomSortComparer).SortDirection ?? ListSortDirection.Ascending);
|
||||||
|
}
|
||||||
|
|
||||||
bindingList.ResetCollection();
|
bindingList.ResetCollection();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user