From bff49c0e7ac6012551d56b9cc52ba258c7300c65 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Thu, 17 Mar 2022 20:27:39 -0500 Subject: [PATCH] More Bugfixes from Side Nav (#1162) * Fixed a bug where the bottom of the page could be cut off * Adjusted all the headings to h2, which looks better * Refactored GetSeriesDetail to actually map the names inside the code so the UI just displays. * Put in some basic improvements to OPDS by using Series Detail type layout, but this only reduces one click. * Fixed a bug where offset from scrollbar fix causes readers to be cutoff. --- API.Tests/Services/SeriesServiceTests.cs | 2 +- API/Controllers/OPDSController.cs | 65 ++++++++++++++----- API/Services/SeriesService.cs | 28 ++++++-- UI/Web/src/app/_services/nav.service.ts | 10 ++- .../admin/dashboard/dashboard.component.html | 4 +- .../app/all-series/all-series.component.html | 4 +- UI/Web/src/app/app.component.html | 15 +++-- .../all-collections.component.html | 4 +- .../library-detail.component.html | 4 +- UI/Web/src/app/on-deck/on-deck.component.html | 4 +- .../reading-list-detail.component.html | 4 +- .../reading-lists.component.html | 4 +- .../recently-added.component.html | 4 +- .../series-detail.component.html | 10 +-- .../user-preferences.component.html | 4 +- UI/Web/src/theme/utilities/_global.scss | 2 +- 16 files changed, 114 insertions(+), 54 deletions(-) diff --git a/API.Tests/Services/SeriesServiceTests.cs b/API.Tests/Services/SeriesServiceTests.cs index c8655eaba..42b586e1f 100644 --- a/API.Tests/Services/SeriesServiceTests.cs +++ b/API.Tests/Services/SeriesServiceTests.cs @@ -202,7 +202,7 @@ public class SeriesServiceTests Assert.NotEmpty(detail.Volumes); Assert.Equal(2, detail.Volumes.Count()); // Volume 0 shouldn't be sent in Volumes - Assert.All(detail.Volumes, dto => Assert.Contains(dto.Name, new[] {"2", "3"})); + Assert.All(detail.Volumes, dto => Assert.Contains(dto.Name, new[] {"Volume 2", "Volume 3"})); // Volumes get names mapped } [Fact] diff --git a/API/Controllers/OPDSController.cs b/API/Controllers/OPDSController.cs index 21e184e33..2a58d75f2 100644 --- a/API/Controllers/OPDSController.cs +++ b/API/Controllers/OPDSController.cs @@ -28,6 +28,7 @@ public class OpdsController : BaseApiController private readonly IDirectoryService _directoryService; private readonly ICacheService _cacheService; private readonly IReaderService _readerService; + private readonly ISeriesService _seriesService; private readonly XmlSerializer _xmlSerializer; @@ -61,13 +62,14 @@ public class OpdsController : BaseApiController public OpdsController(IUnitOfWork unitOfWork, IDownloadService downloadService, IDirectoryService directoryService, ICacheService cacheService, - IReaderService readerService) + IReaderService readerService, ISeriesService seriesService) { _unitOfWork = unitOfWork; _downloadService = downloadService; _directoryService = directoryService; _cacheService = cacheService; _readerService = readerService; + _seriesService = seriesService; _xmlSerializer = new XmlSerializer(typeof(Feed)); _xmlOpenSearchSerializer = new XmlSerializer(typeof(OpenSearchDescription)); @@ -314,16 +316,17 @@ public class OpdsController : BaseApiController var items = (await _unitOfWork.ReadingListRepository.GetReadingListItemDtosByIdAsync(readingListId, userId)).ToList(); foreach (var item in items) { - feed.Entries.Add(new FeedEntry() - { - Id = item.ChapterId.ToString(), - Title = $"{item.SeriesName} Chapter {item.ChapterNumber}", - Links = new List() - { - CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"), - CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}") - } - }); + feed.Entries.Add(CreateChapter(apiKey, $"{item.SeriesName} Chapter {item.ChapterNumber}", item.ChapterId, item.VolumeId, item.SeriesId)); + // new FeedEntry() + // { + // Id = item.ChapterId.ToString(), + // Title = $"{item.SeriesName} Chapter {item.ChapterNumber}", + // Links = new List() + // { + // CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, Prefix + $"{apiKey}/series/{item.SeriesId}/volume/{item.VolumeId}/chapter/{item.ChapterId}"), + // CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/chapter-cover?chapterId={item.ChapterId}") + // } + // } } return CreateXmlResult(SerializeXml(feed)); @@ -521,15 +524,30 @@ public class OpdsController : BaseApiController return BadRequest("OPDS is not enabled on this server"); var userId = await GetUser(apiKey); var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); - var volumes = await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId); - var feed = CreateFeed(series.Name + " - Volumes", $"{apiKey}/series/{series.Id}", apiKey); + + var feed = CreateFeed(series.Name + " - Storyline", $"{apiKey}/series/{series.Id}", apiKey); SetFeedId(feed, $"series-{series.Id}"); feed.Links.Add(CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, $"/api/image/series-cover?seriesId={seriesId}")); - foreach (var volumeDto in volumes) + + // NOTE: I want to try and use ReaderService to get SeriesDetails. + var seriesDetail = await _seriesService.GetSeriesDetail(seriesId, userId); + foreach (var volume in seriesDetail.Volumes) { - feed.Entries.Add(CreateVolume(volumeDto, seriesId, apiKey)); + feed.Entries.Add(CreateVolume(volume, seriesId, apiKey)); // We might want to emulate a volume but make this a chapter } + foreach (var storylineChapter in seriesDetail.StorylineChapters.Where(c => !c.IsSpecial)) + { + feed.Entries.Add(CreateChapter(apiKey, storylineChapter.Title, storylineChapter.Id, storylineChapter.VolumeId, seriesId)); + } + + foreach (var special in seriesDetail.Specials) + { + feed.Entries.Add(CreateChapter(apiKey, special.Title, special.Id, special.VolumeId, seriesId)); + } + + + return CreateXmlResult(SerializeXml(feed)); } @@ -698,6 +716,23 @@ public class OpdsController : BaseApiController }; } + private static FeedEntry CreateChapter(string apiKey, string title, int chapterId, int volumeId, int seriesId) + { + + return new FeedEntry() + { + Id = chapterId.ToString(), + Title = title, + Links = new List() + { + CreateLink(FeedLinkRelation.SubSection, FeedLinkType.AtomNavigation, + Prefix + $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}"), + CreateLink(FeedLinkRelation.Image, FeedLinkType.Image, + $"/api/image/chapter-cover?chapterId={chapterId}") + } + }; + } + private FeedEntry CreateChapter(int seriesId, int volumeId, int chapterId, MangaFile mangaFile, SeriesDto series, Volume volume, ChapterDto chapter, string apiKey) { var fileSize = diff --git a/API/Services/SeriesService.cs b/API/Services/SeriesService.cs index 0dcbc4f3b..30556ad26 100644 --- a/API/Services/SeriesService.cs +++ b/API/Services/SeriesService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -14,7 +13,6 @@ using API.Entities.Enums; using API.Helpers; using API.SignalR; using Microsoft.Extensions.Logging; -using Microsoft.VisualBasic; namespace API.Services; @@ -460,22 +458,40 @@ public class SeriesService : ISeriesService { volume.Name += $" - {firstChapter.TitleName}"; } + processedVolumes.Add(volume); } } else { processedVolumes = volumes.Where(v => v.Number > 0).ToList(); + processedVolumes.ForEach(v => v.Name = $"Volume {v.Name}"); } var specials = new List(); - foreach (var chapter in chapters.Where(c => c.IsSpecial)) + foreach (var chapter in chapters) { - chapter.Title = Parser.Parser.CleanSpecialTitle(chapter.Title); - specials.Add(chapter); + if (chapter.IsSpecial) + { + chapter.Title = Parser.Parser.CleanSpecialTitle(chapter.Title); + specials.Add(chapter); + } + else + { + var title = libraryType switch + { + LibraryType.Book => $"Book {chapter.Title}", + LibraryType.Comic => $"Issue #{chapter.Title}", + LibraryType.Manga => $"Chapter {chapter.Title}", + _ => "Chapter " + }; + chapter.Title = title; + } + } + // Don't show chapter 0 (aka single volume chapters) in the Chapters tab or books that are just single numbers (they show as volumes) IEnumerable retChapters; if (libraryType == LibraryType.Book) @@ -497,7 +513,7 @@ public class SeriesService : ISeriesService Volumes = processedVolumes, StorylineChapters = volumes .Where(v => v.Number == 0) - .SelectMany(v => v.Chapters) + .SelectMany(v => v.Chapters.Where(c => !c.IsSpecial)) .OrderBy(c => float.Parse(c.Number), new ChapterSortComparer()) }; diff --git a/UI/Web/src/app/_services/nav.service.ts b/UI/Web/src/app/_services/nav.service.ts index 816098c73..a30e963e6 100644 --- a/UI/Web/src/app/_services/nav.service.ts +++ b/UI/Web/src/app/_services/nav.service.ts @@ -1,4 +1,5 @@ -import { Injectable } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { Inject, Injectable, Renderer2, RendererFactory2 } from '@angular/core'; import { ReplaySubject, take } from 'rxjs'; @Injectable({ @@ -25,7 +26,10 @@ export class NavService { */ sideNavVisibility$ = this.sideNavVisibilitySource.asObservable(); - constructor() { + private renderer: Renderer2; + + constructor(@Inject(DOCUMENT) private document: Document, rendererFactory: RendererFactory2) { + this.renderer = rendererFactory.createRenderer(null, null); this.showNavBar(); const sideNavState = (localStorage.getItem(this.localStorageSideNavKey) === 'true') || false; this.sideNavCollapseSource.next(sideNavState); @@ -36,6 +40,7 @@ export class NavService { * Shows the top nav bar. This should be visible on all pages except the reader. */ showNavBar() { + this.renderer.setStyle(this.document.querySelector('body'), 'margin-top', '56px'); this.navbarVisibleSource.next(true); } @@ -43,6 +48,7 @@ export class NavService { * Hides the top nav bar. */ hideNavBar() { + this.renderer.setStyle(this.document.querySelector('body'), 'margin-top', '0px'); this.navbarVisibleSource.next(false); } diff --git a/UI/Web/src/app/admin/dashboard/dashboard.component.html b/UI/Web/src/app/admin/dashboard/dashboard.component.html index 7db5206ea..bfbad082b 100644 --- a/UI/Web/src/app/admin/dashboard/dashboard.component.html +++ b/UI/Web/src/app/admin/dashboard/dashboard.component.html @@ -1,7 +1,7 @@ -

+

Admin Dashboard -

+