using DynamicData.Binding; namespace PLib.Desktop.ViewModels; /// /// A sort order, its label, and the comparer DynamicData keeps the bound collection in. /// /// /// Every comparer ends with the identifier so the order is total. Ties would otherwise let /// DynamicData move equal items around on each refresh, which the user sees as cards /// twitching while a scan streams in. /// public sealed record SortOption(string Label, IComparer Comparer) { public static IReadOnlyList All { get; } = [ new("Недавно добавленные", SortExpressionComparer .Descending(x => x.AddedAt) .ThenByAscending(x => x.Id)), new("По названию", new TitleComparer()), new("Сначала длинные", SortExpressionComparer .Descending(x => x.RawDuration ?? TimeSpan.Zero) .ThenByAscending(x => x.Id)), new("Сначала большие", SortExpressionComparer .Descending(x => x.RawSizeInBytes) .ThenByAscending(x => x.Id)), ]; /// /// Culture-aware, case-insensitive title order. /// would fall back to ordinal comparison, which puts Cyrillic and Latin titles in an /// order no reader expects. /// private sealed class TitleComparer : IComparer { public int Compare(VideoCardViewModel? x, VideoCardViewModel? y) { var byTitle = string.Compare(x?.Title, y?.Title, StringComparison.CurrentCultureIgnoreCase); return byTitle != 0 ? byTitle : Comparer.Default.Compare(x?.Id ?? Guid.Empty, y?.Id ?? Guid.Empty); } } }