Michael Bucari-Tovo bff9b67b72 Remove GridEntry derrived types and interfaces
Use existing BaseUtil.LoadImage delegate, obviating need for derrived classes to load images

Since GridEntry types are no longer generic, interfaces are unnecessary and deleted.
2025-07-21 10:47:10 -06:00

177 lines
5.6 KiB
C#

using ApplicationServices;
using DataLayer;
using Dinah.Core;
using System;
using System.Collections.Generic;
namespace LibationUiBase.GridView
{
//This Class holds all book entry status info to help the grid properly render entries.
//The reason this info is in here instead of GridEntry is because all of this info is needed
//for the "Liberate" column's display and sorting functions.
public class EntryStatus : ReactiveObject, IComparable
{
public LiberatedStatus? PdfStatus => LibraryCommands.Pdf_Status(Book);
public LiberatedStatus BookStatus
{
get
{
if (IsSeries) return default;
if ((DateTime.Now - lastBookUpdate).TotalSeconds > 2)
{
//Cache the BookStatus so AudibleFileStorage.AaxcExists isn't
//called multiple times per book while sorting the solumn.
bookStatus = LibraryCommands.Liberated_Status(Book);
lastBookUpdate = DateTime.Now;
}
return bookStatus;
}
}
public bool Expanded
{
get => expanded;
set
{
if (value != expanded)
{
expanded = value;
Invalidate(nameof(Expanded), nameof(ButtonImage));
}
}
}
public bool IsSeries { get; }
public bool IsEpisode { get; }
public bool IsBook => !IsSeries && !IsEpisode;
public bool IsUnavailable
=> !IsSeries
& isAbsent
& (
BookStatus is not LiberatedStatus.Liberated
|| PdfStatus is not null and not LiberatedStatus.Liberated
);
public double Opacity => !IsSeries && Book.UserDefinedItem.Tags.ContainsInsensitive("hidden") ? 0.4 : 1;
public object ButtonImage => GetLiberateIcon();
public string ToolTip => GetTooltip();
private Book Book { get; }
private DateTime lastBookUpdate;
private LiberatedStatus bookStatus;
private bool expanded;
private readonly bool isAbsent;
private static readonly Dictionary<string, object> iconCache = new();
internal EntryStatus(LibraryBook libraryBook)
{
Book = ArgumentValidator.EnsureNotNull(libraryBook, nameof(libraryBook)).Book;
isAbsent = libraryBook.AbsentFromLastScan is true;
IsEpisode = Book.ContentType is ContentType.Episode;
IsSeries = Book.ContentType is ContentType.Parent;
}
/// <summary>Refresh BookStatus (so partial download files are checked again in the filesystem) and raise PropertyChanged for property names.</summary>
public void Invalidate(params string[] properties)
{
lastBookUpdate = default;
foreach (var property in properties)
RaisePropertyChanged(property);
}
/// <summary> Defines the Liberate column's sorting behavior </summary>
public int CompareTo(object obj)
{
if (obj is not EntryStatus second) return -1;
if (IsSeries && !second.IsSeries) return -1;
else if (!IsSeries && second.IsSeries) return 1;
else if (IsSeries && second.IsSeries) return 0;
else if (IsUnavailable && !second.IsUnavailable) return 1;
else if (!IsUnavailable && second.IsUnavailable) return -1;
else if (BookStatus == LiberatedStatus.Liberated && second.BookStatus != LiberatedStatus.Liberated) return -1;
else if (BookStatus != LiberatedStatus.Liberated && second.BookStatus == LiberatedStatus.Liberated) return 1;
var statusCompare = BookStatus.CompareTo(second.BookStatus);
if (statusCompare != 0) return statusCompare;
else if (PdfStatus is null && second.PdfStatus is null) return 0;
else if (PdfStatus is null && second.PdfStatus is not null) return 1;
else if (PdfStatus is not null && second.PdfStatus is null) return -1;
else return PdfStatus.Value.CompareTo(second.PdfStatus.Value);
}
private object GetLiberateIcon()
{
if (IsSeries)
return Expanded ? GetAndCacheResource("minus") : GetAndCacheResource("plus");
if (BookStatus == LiberatedStatus.Error)
return GetAndCacheResource("error");
string image_lib = BookStatus switch
{
LiberatedStatus.Liberated => "green",
LiberatedStatus.PartialDownload => "yellow",
LiberatedStatus.NotLiberated => "red",
_ => throw new Exception("Unexpected liberation state")
};
string image_pdf = PdfStatus switch
{
LiberatedStatus.Liberated => "_pdf_yes",
LiberatedStatus.NotLiberated => "_pdf_no",
LiberatedStatus.Error => "_pdf_no",
null => "",
_ => throw new Exception("Unexpected PDF state")
};
return GetAndCacheResource($"liberate_{image_lib}{image_pdf}");
}
private string GetTooltip()
{
if (IsSeries)
return Expanded ? "Click to Collapse" : "Click to Expand";
if (IsUnavailable)
return "This book cannot be downloaded\nbecause it wasn't found during\nthe most recent library scan";
if (BookStatus == LiberatedStatus.Error)
return "Book downloaded ERROR";
string libState = BookStatus switch
{
LiberatedStatus.Liberated => "Liberated",
LiberatedStatus.PartialDownload => "File has been at least\r\npartially downloaded",
LiberatedStatus.NotLiberated => "Book NOT downloaded",
_ => throw new Exception("Unexpected liberation state")
};
string pdfState = PdfStatus switch
{
LiberatedStatus.Liberated => "\r\nPDF downloaded",
LiberatedStatus.NotLiberated => "\r\nPDF NOT downloaded",
LiberatedStatus.Error => "\r\nPDF downloaded ERROR",
null => "",
_ => throw new Exception("Unexpected PDF state")
};
var mouseoverText = libState + pdfState;
if (BookStatus == LiberatedStatus.NotLiberated ||
BookStatus == LiberatedStatus.PartialDownload ||
PdfStatus == LiberatedStatus.NotLiberated)
mouseoverText += "\r\nClick to complete";
return mouseoverText;
}
private object GetAndCacheResource(string rescName)
{
if (!iconCache.ContainsKey(rescName))
iconCache[rescName] = BaseUtil.LoadResourceImage(rescName);
return iconCache[rescName];
}
}
}