Files
Cursor Agentandrmcrackan cb01b9b3b1 Keep pointing at the trash when the library itself is empty
Two states were wrong, both when the live library is empty but the trash is not.
GetLibrary() filters IsDeleted, so an all-trashed library reads as empty and the
getting-started panel took over.

Without a filter it said 'Libation is empty' while 29 books sat in the trash -
the books are not gone, they are one click away. The panel now carries a trash
line when there is anything in there.

With a filter it was worse: searching for a book that IS in the trash showed
'Libation is empty. Add your Audible account' and suppressed the trash hint
entirely, which is the exact failure #1925 was about, reintroduced in the one
case where the library is empty.

The rule is now that someone searching is not someone getting started, so a
filter always answers for itself. That leaves one merely-suboptimal case, an
empty library filtered to something in neither place, which says 'no books
match' - true, and better than claiming the library is empty when it is being
filtered.

Also fixes what made this invisible while testing: GettingStartedVisible depends
on the filter but nothing raised it when the filter changed, so the panel never
re-evaluated.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-18 20:17:32 +00:00

66 lines
2.5 KiB
C#

namespace LibationUiBase;
/// <summary>
/// What to show in the middle of the grid when it has no rows to draw. Shared so both frontends word it
/// identically, and kept in one place so a third empty state does not become a third scattered set of strings.
/// </summary>
public static class GridEmptyStateUi
{
#region A filter matched nothing
/// <summary>Headline for a filter that matched nothing in the library.</summary>
public static string NoMatchesText(string? searchString)
=> string.IsNullOrWhiteSpace(searchString)
? "No books match the current filter."
: $"No books match \"{searchString.Trim()}\".";
/// <summary>
/// Follow-up naming matches hiding in the trash. Only worth saying when the filter matched something in
/// there; "nothing here, and by the way the trash has things in it" would just be noise.
/// </summary>
public static string NoMatchesTrashHintText(int matchesInTrash)
=> matchesInTrash == 1
? "1 matching book is in the trash."
: $"{matchesInTrash} matching books are in the trash.";
public const string OpenTrashBinButton = "Open Trash Bin";
#endregion
#region The library itself is empty
/// <summary>
/// An empty library has two causes with different next steps, and telling someone with no account to scan
/// their library is a dead end. <paramref name="anyAccounts"/> is what tells them apart.
/// </summary>
public static string EmptyLibraryHeadline(bool anyAccounts)
=> anyAccounts
? "No books in your library yet."
: "Libation is empty.";
public static string EmptyLibraryDetail(bool anyAccounts)
=> anyAccounts
? "Scan your Audible account to bring your books in."
: "Add your Audible account, then scan your library to bring your books in.";
/// <summary>
/// Books in the trash while the library itself is empty. Without this the headline above reads as though
/// the books were never there, when in fact they are one click away.
/// </summary>
public static string EmptyLibraryTrashHintText(int booksInTrash)
=> booksInTrash == 1
? "1 book is in the trash."
: $"{booksInTrash} books are in the trash.";
public const string AddAccountButton = "Add Account";
public const string ScanLibraryButton = "Scan Library";
/// <summary>
/// The walkthrough is offered once, on first launch, and never again once that is declined. A permanent
/// way back in costs one button and is the only one a new user is likely to find.
/// </summary>
public const string TakeTheTourButton = "Take a Guided Tour";
#endregion
}