Label chapter chips by kind, not raw number
Beats, tags, locations, open questions, and character/arc-stage responses that reference a chapter now carry a ChapterLabel/DisplayNumber alongside the raw Number, computed via the new ChapterDisplayNumberLookup. Front/back matter chips show their title; body chapters show "Chapter N: Title".
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Novelly.Api.Data;
|
||||
|
||||
namespace Novelly.Api.Chapters;
|
||||
|
||||
public class ChapterDisplayNumberLookup(INovelDbContext db)
|
||||
{
|
||||
public async Task<IReadOnlyDictionary<Guid, int>> ForNovelAsync(Guid novelId, CancellationToken ct = default)
|
||||
{
|
||||
var chapters = await db.Chapters.AsNoTracking().Where(c => c.NovelId == novelId).ToListAsync(ct);
|
||||
return ChapterNumbering.DisplayNumbers(chapters);
|
||||
}
|
||||
|
||||
public async Task<int?> ForChapterAsync(Chapter chapter, CancellationToken ct = default)
|
||||
{
|
||||
if (chapter.Kind != ChapterKind.Body)
|
||||
return null;
|
||||
|
||||
return await db.Chapters.CountAsync(
|
||||
c => c.NovelId == chapter.NovelId && c.Kind == ChapterKind.Body && c.Number <= chapter.Number, ct);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyDictionary<Guid, int>> ForChaptersAsync(IEnumerable<Chapter> chapters, CancellationToken ct = default)
|
||||
{
|
||||
var displayNumbers = new Dictionary<Guid, int>();
|
||||
|
||||
foreach (var chapter in chapters.DistinctBy(c => c.Id))
|
||||
{
|
||||
if (await ForChapterAsync(chapter, ct) is { } number)
|
||||
displayNumbers[chapter.Id] = number;
|
||||
}
|
||||
|
||||
return displayNumbers;
|
||||
}
|
||||
|
||||
public string LabelFor(Chapter chapter, IReadOnlyDictionary<Guid, int> displayNumbers) =>
|
||||
ChapterNumbering.Label(chapter.Kind, displayNumbers.TryGetValue(chapter.Id, out var n) ? n : null, chapter.Title);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public class ChapterService(
|
||||
NovelAccessService access,
|
||||
TagService tags,
|
||||
LocationService locations,
|
||||
ChapterDisplayNumberLookup displayNumbers,
|
||||
ActivityLog activity,
|
||||
ILogger<ChapterService> logger,
|
||||
IModelValidator<CreateChapterRequest> createValidator,
|
||||
@@ -168,14 +169,8 @@ public class ChapterService(
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<int?> DisplayNumberAsync(Chapter chapter, CancellationToken ct = default)
|
||||
{
|
||||
if (chapter.Kind != ChapterKind.Body)
|
||||
return null;
|
||||
|
||||
return await db.Chapters.CountAsync(
|
||||
c => c.NovelId == chapter.NovelId && c.Kind == ChapterKind.Body && c.Number <= chapter.Number, ct);
|
||||
}
|
||||
public Task<int?> DisplayNumberAsync(Chapter chapter, CancellationToken ct = default) =>
|
||||
displayNumbers.ForChapterAsync(chapter, ct);
|
||||
|
||||
private async Task<int> NextChapterNumberAsync(Guid novelId, CancellationToken ct)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user