Enhance PLib video library manager with new tabbed navigation for entities and metadata management. Introduce sections for videos, tags, actors, studios, collections, and metadata, each with dedicated search and sorting capabilities. Update UI components to reflect these changes, ensuring a cohesive user experience. Revise repository interfaces to support loading video items with labels and summaries for efficient browsing. Update README.md to document new features and usage instructions.

This commit is contained in:
Leonid Pershin
2026-08-09 08:58:07 +03:00
parent 61d01d1970
commit 5acb42d11d
26 changed files with 1434 additions and 18 deletions
@@ -0,0 +1,61 @@
using System.Globalization;
using PLib.Application.Library;
using PLib.Domain.Videos;
using ReactiveUI;
using RxVoid = ReactiveUI.Primitives.RxVoid;
namespace PLib.Desktop.ViewModels;
/// <summary>One tag, performer, studio or collection in a browsing tab.</summary>
public sealed class LabelSummaryViewModel
{
public LabelSummaryViewModel(LabelSummary summary, Action<LabelSummaryViewModel> open)
{
ArgumentNullException.ThrowIfNull(summary);
Id = summary.Id;
Name = summary.Name;
Kind = summary.Kind;
VideoCount = summary.VideoCount;
CountText = VideoCount.ToString(CultureInfo.CurrentCulture);
OpenCommand = ReactiveCommand.Create(() => open(this));
}
public Guid Id { get; }
public string Name { get; }
public LabelKind Kind { get; }
public int VideoCount { get; }
public string CountText { get; }
/// <summary>Narrows the video grid down to this label and switches to it.</summary>
public ReactiveCommand<RxVoid, RxVoid> OpenCommand { get; }
public bool Matches(string term) => Name.Contains(term, StringComparison.CurrentCultureIgnoreCase);
}
/// <summary>An order for the entity lists, and how to read it.</summary>
public sealed record EntitySortOption(string Label, Comparison<LabelSummaryViewModel> Compare)
{
public static IReadOnlyList<EntitySortOption> All { get; } =
[
new("Сначала частые", (x, y) =>
{
var byCount = y.VideoCount.CompareTo(x.VideoCount);
return byCount != 0 ? byCount : Name(x, y);
}),
new("По названию", Name),
];
/// <summary>
/// Culture-aware and case-insensitive, so Cyrillic and Latin names land where a reader
/// expects rather than in ordinal order.
/// </summary>
private static int Name(LabelSummaryViewModel x, LabelSummaryViewModel y) =>
string.Compare(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase);
}