Jump Bar Testing (#1302)
* Implemented a basic jump bar for the library view. This currently just interacts with existing pagination controls and is not inlined with infinite scroll yet. This is a first pass implementation. * Refactored time estimates into the reading service. * Cleaned up when the jump bar is shown to mimic pagination controls * Cleanup up code in reader service. * Scroll to card when selecting a jump key that is shown on the current page. * Ensure estimated times always has the smaller number on left hand side. * Fixed a bug with a missing vertical rule * Fixed an off by 1 pixel for search overlay
This commit is contained in:
parent
64c0b5a71e
commit
742cfd3293
20 changed files with 319 additions and 120 deletions
|
@ -7,6 +7,7 @@ using API.Comparators;
|
|||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.Reader;
|
||||
using API.Entities;
|
||||
using API.Extensions;
|
||||
using API.SignalR;
|
||||
|
@ -28,6 +29,7 @@ public interface IReaderService
|
|||
Task<ChapterDto> GetContinuePoint(int seriesId, int userId);
|
||||
Task MarkChaptersUntilAsRead(AppUser user, int seriesId, float chapterNumber);
|
||||
Task MarkVolumesUntilAsRead(AppUser user, int seriesId, int volumeNumber);
|
||||
HourEstimateRangeDto GetTimeEstimate(long wordCount, int pageCount, bool isEpub, bool hasProgress = false);
|
||||
}
|
||||
|
||||
public class ReaderService : IReaderService
|
||||
|
@ -168,7 +170,7 @@ public class ReaderService : IReaderService
|
|||
var progresses = user.Progresses.Where(x => x.ChapterId == chapter.Id && x.AppUserId == user.Id).ToList();
|
||||
if (progresses.Count > 1)
|
||||
{
|
||||
user.Progresses = new List<AppUserProgress>()
|
||||
user.Progresses = new List<AppUserProgress>
|
||||
{
|
||||
user.Progresses.First()
|
||||
};
|
||||
|
@ -478,7 +480,7 @@ public class ReaderService : IReaderService
|
|||
/// <param name="chapterNumber"></param>
|
||||
public async Task MarkChaptersUntilAsRead(AppUser user, int seriesId, float chapterNumber)
|
||||
{
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List<int>() { seriesId }, true);
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List<int> { seriesId }, true);
|
||||
foreach (var volume in volumes.OrderBy(v => v.Number))
|
||||
{
|
||||
var chapters = volume.Chapters
|
||||
|
@ -490,10 +492,57 @@ public class ReaderService : IReaderService
|
|||
|
||||
public async Task MarkVolumesUntilAsRead(AppUser user, int seriesId, int volumeNumber)
|
||||
{
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List<int>() { seriesId }, true);
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(new List<int> { seriesId }, true);
|
||||
foreach (var volume in volumes.OrderBy(v => v.Number).Where(v => v.Number <= volumeNumber && v.Number > 0))
|
||||
{
|
||||
MarkChaptersAsRead(user, volume.SeriesId, volume.Chapters);
|
||||
}
|
||||
}
|
||||
|
||||
public HourEstimateRangeDto GetTimeEstimate(long wordCount, int pageCount, bool isEpub, bool hasProgress = false)
|
||||
{
|
||||
if (isEpub)
|
||||
{
|
||||
var minHours = Math.Max((int) Math.Round((wordCount / MinWordsPerHour)), 1);
|
||||
var maxHours = Math.Max((int) Math.Round((wordCount / MaxWordsPerHour)), 1);
|
||||
if (maxHours < minHours)
|
||||
{
|
||||
return new HourEstimateRangeDto
|
||||
{
|
||||
MinHours = maxHours,
|
||||
MaxHours = minHours,
|
||||
AvgHours = (int) Math.Round((wordCount / AvgWordsPerHour)),
|
||||
HasProgress = hasProgress
|
||||
};
|
||||
}
|
||||
return new HourEstimateRangeDto
|
||||
{
|
||||
MinHours = minHours,
|
||||
MaxHours = maxHours,
|
||||
AvgHours = (int) Math.Round((wordCount / AvgWordsPerHour)),
|
||||
HasProgress = hasProgress
|
||||
};
|
||||
}
|
||||
|
||||
var minHoursPages = Math.Max((int) Math.Round((pageCount / MinPagesPerMinute / 60F)), 1);
|
||||
var maxHoursPages = Math.Max((int) Math.Round((pageCount / MaxPagesPerMinute / 60F)), 1);
|
||||
if (maxHoursPages < minHoursPages)
|
||||
{
|
||||
return new HourEstimateRangeDto
|
||||
{
|
||||
MinHours = maxHoursPages,
|
||||
MaxHours = minHoursPages,
|
||||
AvgHours = (int) Math.Round((pageCount / AvgPagesPerMinute / 60F)),
|
||||
HasProgress = hasProgress
|
||||
};
|
||||
}
|
||||
|
||||
return new HourEstimateRangeDto
|
||||
{
|
||||
MinHours = minHoursPages,
|
||||
MaxHours = maxHoursPages,
|
||||
AvgHours = (int) Math.Round((pageCount / AvgPagesPerMinute / 60F)),
|
||||
HasProgress = hasProgress
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ using API.Data;
|
|||
using API.DTOs;
|
||||
using API.DTOs.CollectionTags;
|
||||
using API.DTOs.Metadata;
|
||||
using API.DTOs.SeriesDetail;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -98,7 +98,7 @@ public class SeriesService : ISeriesService
|
|||
series.Metadata.SummaryLocked = true;
|
||||
}
|
||||
|
||||
if (series.Metadata.Language != updateSeriesMetadataDto.SeriesMetadata.Language)
|
||||
if (series.Metadata.Language != updateSeriesMetadataDto.SeriesMetadata?.Language)
|
||||
{
|
||||
series.Metadata.Language = updateSeriesMetadataDto.SeriesMetadata?.Language;
|
||||
series.Metadata.LanguageLocked = true;
|
||||
|
@ -112,7 +112,7 @@ public class SeriesService : ISeriesService
|
|||
});
|
||||
|
||||
series.Metadata.Genres ??= new List<Genre>();
|
||||
UpdateGenreList(updateSeriesMetadataDto.SeriesMetadata.Genres, series, allGenres, (genre) =>
|
||||
UpdateGenreList(updateSeriesMetadataDto.SeriesMetadata?.Genres, series, allGenres, (genre) =>
|
||||
{
|
||||
series.Metadata.Genres.Add(genre);
|
||||
}, () => series.Metadata.GenresLocked = true);
|
||||
|
@ -521,11 +521,11 @@ public class SeriesService : ISeriesService
|
|||
/// <summary>
|
||||
/// Should we show the given chapter on the UI. We only show non-specials and non-zero chapters.
|
||||
/// </summary>
|
||||
/// <param name="c"></param>
|
||||
/// <param name="chapter"></param>
|
||||
/// <returns></returns>
|
||||
private static bool ShouldIncludeChapter(ChapterDto c)
|
||||
private static bool ShouldIncludeChapter(ChapterDto chapter)
|
||||
{
|
||||
return !c.IsSpecial && !c.Number.Equals(Parser.Parser.DefaultChapter);
|
||||
return !chapter.IsSpecial && !chapter.Number.Equals(Parser.Parser.DefaultChapter);
|
||||
}
|
||||
|
||||
public static void RenameVolumeName(ChapterDto firstChapter, VolumeDto volume, LibraryType libraryType)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue