77 lines
3.2 KiB
C#
77 lines
3.2 KiB
C#
using Ludarium.Domain;
|
|
|
|
namespace Ludarium.Application;
|
|
|
|
/// <summary>
|
|
/// Everything the library browser can ask of the catalog.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Filtering and ordering belong to the query, not to the page the browser happens to hold. The
|
|
/// library previously sorted the forty-eight games already on screen, which reordered a page rather
|
|
/// than the collection and quietly disagreed with what the operator asked for.
|
|
/// </remarks>
|
|
public sealed record GameQuery
|
|
{
|
|
public string? Search { get; init; }
|
|
public string? Platform { get; init; }
|
|
|
|
/// <summary>Ordering key. Unknown values fall back to title.</summary>
|
|
public string? Sort { get; init; }
|
|
|
|
public bool? Favorite { get; init; }
|
|
public GamePlayStatus? Status { get; init; }
|
|
public Guid? CollectionId { get; init; }
|
|
|
|
/// <summary>Normalized tag name, as stored by <see cref="LibraryExperiencePolicy.NormalizeTag"/>.</summary>
|
|
public string? Tag { get; init; }
|
|
|
|
/// <summary>Keep only games rated at least this highly.</summary>
|
|
public int? MinimumRating { get; init; }
|
|
|
|
/// <summary>
|
|
/// Keep only games with a linked, present copy in a format some player accepts.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is a property of the collection, not of the runtime: a sidecar that is switched off does
|
|
/// not make a game disappear from the library. Whether a specific game can start right now stays
|
|
/// the capability's answer, shown on the game itself.
|
|
/// </remarks>
|
|
public bool PlayableOnly { get; init; }
|
|
|
|
public int Page { get; init; } = 1;
|
|
public int PageSize { get; init; } = 50;
|
|
|
|
public static readonly IReadOnlyList<string> SortKeys =
|
|
["title", "recent", "updated", "played", "rating"];
|
|
|
|
public bool HasFilters => !string.IsNullOrWhiteSpace(Search) || !string.IsNullOrWhiteSpace(Platform) ||
|
|
Favorite is not null || Status is not null || CollectionId is not null ||
|
|
!string.IsNullOrWhiteSpace(Tag) || MinimumRating is not null || PlayableOnly;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The exact platform-and-container pairs some Ludarium player accepts.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Derived from the browser matrix and the native registry so the library's "playable copy" filter
|
|
/// can never claim a format no player takes, and can never drift from the policies that decide it.
|
|
/// </remarks>
|
|
public static class PlayableFormats
|
|
{
|
|
/// <summary>Each entry is <c>platform|.extension</c>, lower-cased.</summary>
|
|
public static IReadOnlyList<string> Pairs { get; } = BuildPairs();
|
|
|
|
private static string[] BuildPairs()
|
|
{
|
|
var pairs = new SortedSet<string>(StringComparer.Ordinal);
|
|
foreach (var platform in BrowserPlayPolicy.DescribePlatforms())
|
|
foreach (var extension in platform.Extensions.Concat(platform.CandidateExtensions ?? new HashSet<string>()))
|
|
pairs.Add($"{platform.Platform.ToLowerInvariant()}|{extension.ToLowerInvariant()}");
|
|
foreach (var player in NativeRemotePlayerRegistry.All)
|
|
foreach (var platform in player.Platforms)
|
|
foreach (var extension in player.Extensions)
|
|
pairs.Add($"{platform.ToLowerInvariant()}|{extension.ToLowerInvariant()}");
|
|
return [.. pairs];
|
|
}
|
|
}
|