mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Recently Added Chapters/Volumes (#1007)
* Working on adding recently added chapter/volumes to dashboard. Have some progress, need to tweak grouping logic. * Tweaked the logic to work well for grouping. Now to incorporate information for UI to provide seamless integration * Implemented UI part for Recently Added.
This commit is contained in:
parent
81562b7d41
commit
2d59580aef
@ -237,6 +237,13 @@ namespace API.Controllers
|
|||||||
return Ok(series);
|
return Ok(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("recently-added-chapters")]
|
||||||
|
public async Task<ActionResult<IEnumerable<RecentlyAddedItemDto>>> GetRecentlyAddedChapters()
|
||||||
|
{
|
||||||
|
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
|
||||||
|
return Ok(await _unitOfWork.SeriesRepository.GetRecentlyAddedChapters(userId));
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("all")]
|
[HttpPost("all")]
|
||||||
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetAllSeries(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0)
|
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetAllSeries(FilterDto filterDto, [FromQuery] UserParams userParams, [FromQuery] int libraryId = 0)
|
||||||
{
|
{
|
||||||
|
34
API/DTOs/RecentlyAddedItemDto.cs
Normal file
34
API/DTOs/RecentlyAddedItemDto.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using API.Entities.Enums;
|
||||||
|
|
||||||
|
namespace API.DTOs;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A mesh of data for Recently added volume/chapters
|
||||||
|
/// </summary>
|
||||||
|
public class RecentlyAddedItemDto
|
||||||
|
{
|
||||||
|
public string SeriesName { get; set; }
|
||||||
|
public int SeriesId { get; set; }
|
||||||
|
public int LibraryId { get; set; }
|
||||||
|
public LibraryType LibraryType { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// This will automatically map to Volume X, Chapter Y, etc.
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime Created { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Chapter Id if this is a chapter. Not guaranteed to be set.
|
||||||
|
/// </summary>
|
||||||
|
public int ChapterId { get; set; } = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// Volume Id if this is a chapter. Not guaranteed to be set.
|
||||||
|
/// </summary>
|
||||||
|
public int VolumeId { get; set; } = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// This is used only on the UI. It is just index of being added.
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
public MangaFormat Format { get; set; }
|
||||||
|
|
||||||
|
}
|
@ -73,6 +73,7 @@ public interface ISeriesRepository
|
|||||||
Task<IList<AgeRatingDto>> GetAllAgeRatingsDtosForLibrariesAsync(List<int> libraryIds);
|
Task<IList<AgeRatingDto>> GetAllAgeRatingsDtosForLibrariesAsync(List<int> libraryIds);
|
||||||
Task<IList<LanguageDto>> GetAllLanguagesForLibrariesAsync(List<int> libraryIds);
|
Task<IList<LanguageDto>> GetAllLanguagesForLibrariesAsync(List<int> libraryIds);
|
||||||
Task<IList<PublicationStatusDto>> GetAllPublicationStatusesDtosForLibrariesAsync(List<int> libraryIds);
|
Task<IList<PublicationStatusDto>> GetAllPublicationStatusesDtosForLibrariesAsync(List<int> libraryIds);
|
||||||
|
Task<IList<RecentlyAddedItemDto>> GetRecentlyAddedChapters(int userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SeriesRepository : ISeriesRepository
|
public class SeriesRepository : ISeriesRepository
|
||||||
@ -802,4 +803,151 @@ public class SeriesRepository : ISeriesRepository
|
|||||||
})
|
})
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IList<RecentlyAddedItemDto>> GetRecentlyAddedChapters(int userId)
|
||||||
|
{
|
||||||
|
var libraries = await _context.AppUser
|
||||||
|
.Where(u => u.Id == userId)
|
||||||
|
.SelectMany(u => u.Libraries.Select(l => new {LibraryId = l.Id, LibraryType = l.Type}))
|
||||||
|
.ToListAsync();
|
||||||
|
var libraryIds = libraries.Select(l => l.LibraryId).ToList();
|
||||||
|
|
||||||
|
var withinLastWeek = DateTime.Now - TimeSpan.FromDays(12);
|
||||||
|
|
||||||
|
var ret = await _context.Series
|
||||||
|
.Where(s => libraryIds.Contains(s.LibraryId) && s.LastModified >= withinLastWeek)
|
||||||
|
.Include(s => s.Volumes)
|
||||||
|
.ThenInclude(v => v.Chapters)
|
||||||
|
.Select(s => new
|
||||||
|
{
|
||||||
|
s.LibraryId,
|
||||||
|
LibraryType = s.Library.Type,
|
||||||
|
s.Created,
|
||||||
|
SeriesId = s.Id,
|
||||||
|
SeriesName = s.Name,
|
||||||
|
Series = s,
|
||||||
|
Chapters = s.Volumes.SelectMany(v => v.Chapters)
|
||||||
|
})
|
||||||
|
.Take(50)
|
||||||
|
.AsNoTracking()
|
||||||
|
.AsSplitQuery()
|
||||||
|
.OrderByDescending(item => item.Created)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var items = new List<RecentlyAddedItemDto>();
|
||||||
|
foreach (var series in ret)
|
||||||
|
{
|
||||||
|
if (items.Count >= 50) return items;
|
||||||
|
var chaptersThatMeetCutoff = series.Chapters.Where(c => c.Created >= withinLastWeek)
|
||||||
|
.OrderByDescending(c => c.Created);
|
||||||
|
var chapterMap = chaptersThatMeetCutoff.GroupBy(c => c.VolumeId)
|
||||||
|
.ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
|
||||||
|
foreach (var (volumeId, chapters) in chapterMap)
|
||||||
|
{
|
||||||
|
// If a single chapter
|
||||||
|
if (chapters.Count == 1)
|
||||||
|
{
|
||||||
|
// Create a chapter ReadingListItemDto
|
||||||
|
var chapterTitle = "Chapter";
|
||||||
|
switch (series.LibraryType)
|
||||||
|
{
|
||||||
|
case LibraryType.Book:
|
||||||
|
chapterTitle = "";
|
||||||
|
break;
|
||||||
|
case LibraryType.Comic:
|
||||||
|
chapterTitle = "Issue";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If chapter is 0, then it means it's really a volume, so show it that way
|
||||||
|
var firstChapter = chapters.First();
|
||||||
|
string title;
|
||||||
|
if (firstChapter.Number.Equals(Parser.Parser.DefaultChapter))
|
||||||
|
{
|
||||||
|
title = "Volume " + series.Series.Volumes.FirstOrDefault(v => v.Id == volumeId)?.Number;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title = chapters.First().IsSpecial
|
||||||
|
? chapters.FirstOrDefault()?.Range
|
||||||
|
: $"{chapterTitle} {chapters.FirstOrDefault()?.Range}";
|
||||||
|
}
|
||||||
|
|
||||||
|
items.Add(new RecentlyAddedItemDto()
|
||||||
|
{
|
||||||
|
LibraryId = series.LibraryId,
|
||||||
|
LibraryType = series.LibraryType,
|
||||||
|
SeriesId = series.SeriesId,
|
||||||
|
SeriesName = series.SeriesName,
|
||||||
|
Created = chapters.Max(c => c.Created),
|
||||||
|
Title = title,
|
||||||
|
ChapterId = firstChapter.Id,
|
||||||
|
Id = items.Count,
|
||||||
|
Format = series.Series.Format
|
||||||
|
});
|
||||||
|
if (items.Count >= 50) return items;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Multiple chapters, so let's show as a volume
|
||||||
|
var volumeNumber = series.Series.Volumes.FirstOrDefault(v => v.Id == volumeId)?.Number;
|
||||||
|
if (volumeNumber == 0)
|
||||||
|
{
|
||||||
|
var volumeChapters = chapters.Where(c => c.Created >= withinLastWeek).ToList();
|
||||||
|
foreach (var chap in volumeChapters)
|
||||||
|
{
|
||||||
|
// Create a chapter ReadingListItemDto
|
||||||
|
var chapterTitle = "Chapter";
|
||||||
|
switch (series.LibraryType)
|
||||||
|
{
|
||||||
|
case LibraryType.Book:
|
||||||
|
chapterTitle = "";
|
||||||
|
break;
|
||||||
|
case LibraryType.Comic:
|
||||||
|
chapterTitle = "Issue";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var title = volumeChapters.First().IsSpecial
|
||||||
|
? volumeChapters.FirstOrDefault()?.Range
|
||||||
|
: $"{chapterTitle} {volumeChapters.FirstOrDefault()?.Range}";
|
||||||
|
items.Add(new RecentlyAddedItemDto()
|
||||||
|
{
|
||||||
|
LibraryId = series.LibraryId,
|
||||||
|
LibraryType = series.LibraryType,
|
||||||
|
SeriesId = series.SeriesId,
|
||||||
|
SeriesName = series.SeriesName,
|
||||||
|
Created = chap.Created,
|
||||||
|
Title = title,
|
||||||
|
ChapterId = chap.Id,
|
||||||
|
Id = items.Count,
|
||||||
|
Format = series.Series.Format
|
||||||
|
});
|
||||||
|
if (items.Count >= 50) return items;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a volume ReadingListItemDto
|
||||||
|
var theVolume = series.Series.Volumes.First(v => v.Id == volumeId);
|
||||||
|
items.Add(new RecentlyAddedItemDto()
|
||||||
|
{
|
||||||
|
LibraryId = series.LibraryId,
|
||||||
|
LibraryType = series.LibraryType,
|
||||||
|
SeriesId = series.SeriesId,
|
||||||
|
SeriesName = series.SeriesName,
|
||||||
|
Created = chapters.Max(c => c.Created),
|
||||||
|
Title = "Volume " + theVolume.Number,
|
||||||
|
VolumeId = theVolume.Id,
|
||||||
|
Id = items.Count,
|
||||||
|
Format = series.Series.Format
|
||||||
|
});
|
||||||
|
if (items.Count >= 50) return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
export interface InProgressChapter {
|
|
||||||
id: number;
|
|
||||||
range: string;
|
|
||||||
number: string;
|
|
||||||
pages: number;
|
|
||||||
volumeId: number;
|
|
||||||
pagesRead: number;
|
|
||||||
seriesId: number;
|
|
||||||
seriesName: string;
|
|
||||||
coverImage: string;
|
|
||||||
libraryId: number;
|
|
||||||
libraryName: string;
|
|
||||||
}
|
|
13
UI/Web/src/app/_models/recently-added-item.ts
Normal file
13
UI/Web/src/app/_models/recently-added-item.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { LibraryType } from "./library";
|
||||||
|
|
||||||
|
export interface RecentlyAddedItem {
|
||||||
|
seriesId: number;
|
||||||
|
seriesName: string;
|
||||||
|
created: string;
|
||||||
|
title: string;
|
||||||
|
libraryId: number;
|
||||||
|
libraryType: LibraryType;
|
||||||
|
volumeId: number;
|
||||||
|
chapterId: number;
|
||||||
|
id: number; // This is UI only
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { Injectable, OnDestroy } from '@angular/core';
|
|||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
import { environment } from 'src/environments/environment';
|
import { environment } from 'src/environments/environment';
|
||||||
|
import { RecentlyAddedItem } from '../_models/recently-added-item';
|
||||||
import { AccountService } from './account.service';
|
import { AccountService } from './account.service';
|
||||||
import { NavService } from './nav.service';
|
import { NavService } from './nav.service';
|
||||||
|
|
||||||
@ -41,6 +42,13 @@ export class ImageService implements OnDestroy {
|
|||||||
this.onDestroy.complete();
|
this.onDestroy.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRecentlyAddedItem(item: RecentlyAddedItem) {
|
||||||
|
if (item.chapterId === 0) {
|
||||||
|
return this.getVolumeCoverImage(item.volumeId);
|
||||||
|
}
|
||||||
|
return this.getChapterCoverImage(item.chapterId);
|
||||||
|
}
|
||||||
|
|
||||||
getVolumeCoverImage(volumeId: number) {
|
getVolumeCoverImage(volumeId: number) {
|
||||||
return this.baseUrl + 'image/volume-cover?volumeId=' + volumeId;
|
return this.baseUrl + 'image/volume-cover?volumeId=' + volumeId;
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@ import { map } from 'rxjs/operators';
|
|||||||
import { environment } from 'src/environments/environment';
|
import { environment } from 'src/environments/environment';
|
||||||
import { Chapter } from '../_models/chapter';
|
import { Chapter } from '../_models/chapter';
|
||||||
import { CollectionTag } from '../_models/collection-tag';
|
import { CollectionTag } from '../_models/collection-tag';
|
||||||
import { InProgressChapter } from '../_models/in-progress-chapter';
|
|
||||||
import { PaginatedResult } from '../_models/pagination';
|
import { PaginatedResult } from '../_models/pagination';
|
||||||
|
import { RecentlyAddedItem } from '../_models/recently-added-item';
|
||||||
import { Series } from '../_models/series';
|
import { Series } from '../_models/series';
|
||||||
import { ReadStatus, SeriesFilter } from '../_models/series-filter';
|
import { SeriesFilter } from '../_models/series-filter';
|
||||||
import { SeriesMetadata } from '../_models/series-metadata';
|
import { SeriesMetadata } from '../_models/series-metadata';
|
||||||
import { Volume } from '../_models/volume';
|
import { Volume } from '../_models/volume';
|
||||||
import { ImageService } from './image.service';
|
import { ImageService } from './image.service';
|
||||||
@ -123,6 +123,15 @@ export class SeriesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRecentlyAddedChapters() {
|
||||||
|
return this.httpClient.post<RecentlyAddedItem[]>(this.baseUrl + 'series/recently-added-chapters', {}).pipe(
|
||||||
|
map(items => {
|
||||||
|
items.forEach((item, i) => item.id = i);
|
||||||
|
return items;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
|
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
|
||||||
const data = this.createSeriesFilter(filter);
|
const data = this.createSeriesFilter(filter);
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="title"></app-card-actionables>
|
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="title"></app-card-actionables>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="card-title library" [ngbTooltip]="subtitle" placement="top" *ngIf="subtitle.length > 0">{{subtitle}}</span>
|
||||||
<a class="card-title library" [routerLink]="['/library', libraryId]" routerLinkActive="router-link-active" *ngIf="!supressLibraryLink && libraryName">{{libraryName | sentenceCase}}</a>
|
<a class="card-title library" [routerLink]="['/library', libraryId]" routerLinkActive="router-link-active" *ngIf="!supressLibraryLink && libraryName">{{libraryName | sentenceCase}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -9,6 +9,7 @@ import { Chapter } from 'src/app/_models/chapter';
|
|||||||
import { CollectionTag } from 'src/app/_models/collection-tag';
|
import { CollectionTag } from 'src/app/_models/collection-tag';
|
||||||
import { MangaFormat } from 'src/app/_models/manga-format';
|
import { MangaFormat } from 'src/app/_models/manga-format';
|
||||||
import { PageBookmark } from 'src/app/_models/page-bookmark';
|
import { PageBookmark } from 'src/app/_models/page-bookmark';
|
||||||
|
import { RecentlyAddedItem } from 'src/app/_models/recently-added-item';
|
||||||
import { Series } from 'src/app/_models/series';
|
import { Series } from 'src/app/_models/series';
|
||||||
import { Volume } from 'src/app/_models/volume';
|
import { Volume } from 'src/app/_models/volume';
|
||||||
import { Action, ActionItem } from 'src/app/_services/action-factory.service';
|
import { Action, ActionItem } from 'src/app/_services/action-factory.service';
|
||||||
@ -31,6 +32,10 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||||||
* Name of the card
|
* Name of the card
|
||||||
*/
|
*/
|
||||||
@Input() title = '';
|
@Input() title = '';
|
||||||
|
/**
|
||||||
|
* Shows below the title. Defaults to not visible
|
||||||
|
*/
|
||||||
|
@Input() subtitle = '';
|
||||||
/**
|
/**
|
||||||
* Any actions to perform on the card
|
* Any actions to perform on the card
|
||||||
*/
|
*/
|
||||||
@ -50,7 +55,7 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||||||
/**
|
/**
|
||||||
* This is the entity we are representing. It will be returned if an action is executed.
|
* This is the entity we are representing. It will be returned if an action is executed.
|
||||||
*/
|
*/
|
||||||
@Input() entity!: Series | Volume | Chapter | CollectionTag | PageBookmark;
|
@Input() entity!: Series | Volume | Chapter | CollectionTag | PageBookmark | RecentlyAddedItem;
|
||||||
/**
|
/**
|
||||||
* If the entity is selected or not.
|
* If the entity is selected or not.
|
||||||
*/
|
*/
|
||||||
@ -59,6 +64,10 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||||||
* If the entity should show selection code
|
* If the entity should show selection code
|
||||||
*/
|
*/
|
||||||
@Input() allowSelection: boolean = false;
|
@Input() allowSelection: boolean = false;
|
||||||
|
/**
|
||||||
|
* This will supress the cannot read archive warning when total pages is 0
|
||||||
|
*/
|
||||||
|
@Input() supressArchiveWarning: boolean = false;
|
||||||
/**
|
/**
|
||||||
* Event emitted when item is clicked
|
* Event emitted when item is clicked
|
||||||
*/
|
*/
|
||||||
@ -72,10 +81,6 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||||||
*/
|
*/
|
||||||
libraryName: string | undefined = undefined;
|
libraryName: string | undefined = undefined;
|
||||||
libraryId: number | undefined = undefined;
|
libraryId: number | undefined = undefined;
|
||||||
/**
|
|
||||||
* This will supress the cannot read archive warning when total pages is 0
|
|
||||||
*/
|
|
||||||
supressArchiveWarning: boolean = false;
|
|
||||||
/**
|
/**
|
||||||
* Format of the entity (only applies to Series)
|
* Format of the entity (only applies to Series)
|
||||||
*/
|
*/
|
||||||
|
@ -11,7 +11,14 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</app-carousel-reel>
|
</app-carousel-reel>
|
||||||
|
|
||||||
<app-carousel-reel [items]="recentlyAdded" title="Recently Added" (sectionClick)="handleSectionClick($event)">
|
<app-carousel-reel [items]="recentlyAddedChapters" title="Recently Added">
|
||||||
|
<ng-template #carouselItem let-item let-position="idx">
|
||||||
|
<app-card-item [entity]="item" [title]="item.title" [subtitle]="item.seriesName" [imageUrl]="imageService.getRecentlyAddedItem(item)"
|
||||||
|
[supressArchiveWarning]="true" (clicked)="handleRecentlyAddedChapterClick(item)"></app-card-item>
|
||||||
|
</ng-template>
|
||||||
|
</app-carousel-reel>
|
||||||
|
|
||||||
|
<app-carousel-reel [items]="recentlyAdded" title="Recently Added Series" (sectionClick)="handleSectionClick($event)">
|
||||||
<ng-template #carouselItem let-item let-position="idx">
|
<ng-template #carouselItem let-item let-position="idx">
|
||||||
<app-series-card [data]="item" [libraryId]="item.libraryId" (dataChanged)="loadRecentlyAdded()"></app-series-card>
|
<app-series-card [data]="item" [libraryId]="item.libraryId" (dataChanged)="loadRecentlyAdded()"></app-series-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -5,8 +5,8 @@ import { Subject } from 'rxjs';
|
|||||||
import { take, takeUntil } from 'rxjs/operators';
|
import { take, takeUntil } from 'rxjs/operators';
|
||||||
import { SeriesAddedEvent } from '../_models/events/series-added-event';
|
import { SeriesAddedEvent } from '../_models/events/series-added-event';
|
||||||
import { SeriesRemovedEvent } from '../_models/events/series-removed-event';
|
import { SeriesRemovedEvent } from '../_models/events/series-removed-event';
|
||||||
import { InProgressChapter } from '../_models/in-progress-chapter';
|
|
||||||
import { Library } from '../_models/library';
|
import { Library } from '../_models/library';
|
||||||
|
import { RecentlyAddedItem } from '../_models/recently-added-item';
|
||||||
import { Series } from '../_models/series';
|
import { Series } from '../_models/series';
|
||||||
import { User } from '../_models/user';
|
import { User } from '../_models/user';
|
||||||
import { AccountService } from '../_services/account.service';
|
import { AccountService } from '../_services/account.service';
|
||||||
@ -28,8 +28,8 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
|||||||
isAdmin = false;
|
isAdmin = false;
|
||||||
|
|
||||||
recentlyAdded: Series[] = [];
|
recentlyAdded: Series[] = [];
|
||||||
|
recentlyAddedChapters: RecentlyAddedItem[] = [];
|
||||||
inProgress: Series[] = [];
|
inProgress: Series[] = [];
|
||||||
continueReading: InProgressChapter[] = [];
|
|
||||||
|
|
||||||
private readonly onDestroy = new Subject<void>();
|
private readonly onDestroy = new Subject<void>();
|
||||||
|
|
||||||
@ -76,6 +76,7 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
|||||||
reloadSeries() {
|
reloadSeries() {
|
||||||
this.loadRecentlyAdded();
|
this.loadRecentlyAdded();
|
||||||
this.loadOnDeck();
|
this.loadOnDeck();
|
||||||
|
this.loadRecentlyAddedChapters();
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadInProgress(series: Series | boolean) {
|
reloadInProgress(series: Series | boolean) {
|
||||||
@ -103,6 +104,16 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadRecentlyAddedChapters() {
|
||||||
|
this.seriesService.getRecentlyAddedChapters().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
|
||||||
|
this.recentlyAddedChapters = updatedSeries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRecentlyAddedChapterClick(item: RecentlyAddedItem) {
|
||||||
|
this.router.navigate(['library', item.libraryId, 'series', item.seriesId]);
|
||||||
|
}
|
||||||
|
|
||||||
handleSectionClick(sectionTitle: string) {
|
handleSectionClick(sectionTitle: string) {
|
||||||
if (sectionTitle.toLowerCase() === 'collections') {
|
if (sectionTitle.toLowerCase() === 'collections') {
|
||||||
this.router.navigate(['collections']);
|
this.router.navigate(['collections']);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user