Getting Ready for Release (#1180)

* One more unit test for Tachiyomi

* Removed some debug code in the manga reader menu

* Fixed a typeahead bug where using Enter on add new item or selected options could cause items to disappear from selected state or other visual glitches

* Actually fix the selection issue. We needed to filter out selected before we access element

* Cleaned up collection detail page to align to new side nav design

* Cleaned up some styling on the reading list page

* Fixed a bug where side nav would not be visible on the main app due to some weird redirect logic

* Fixed a bug where when paging to the last page, a page will be skipped and user will have to refresh manually to view

* Fixed some styling bugs on drawer for light themes. Added missing pagination colors on light themes

* On mobile screens, add some padding on series-detail page

* Fixed a bad test case helper
This commit is contained in:
Joseph Milazzo 2022-03-27 16:19:22 -05:00 committed by GitHub
parent f55dbc0a2a
commit d639360e3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 180 additions and 125 deletions

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
@ -25,12 +26,14 @@ namespace API.Tests.Helpers
public static Volume CreateVolume(string volumeNumber, List<Chapter> chapters = null)
{
var chaps = chapters ?? new List<Chapter>();
var pages = chaps.Count > 0 ? chaps.Max(c => c.Pages) : 0;
return new Volume()
{
Name = volumeNumber,
Number = (int) API.Parser.Parser.MinimumNumberFromRange(volumeNumber),
Pages = 0,
Chapters = chapters ?? new List<Chapter>()
Pages = pages,
Chapters = chaps
};
}

View File

@ -1353,6 +1353,84 @@ public class ReaderServiceTests
Assert.Equal("22", nextChapter.Range);
}
[Fact]
public async Task GetContinuePoint_ShouldReturnFirstNonSpecial2()
{
_context.Series.Add(new Series()
{
Name = "Test",
Library = new Library() {
Name = "Test LIb",
Type = LibraryType.Manga,
},
Volumes = new List<Volume>()
{
// Loose chapters
EntityFactory.CreateVolume("0", new List<Chapter>()
{
EntityFactory.CreateChapter("45", false, new List<MangaFile>(), 1),
EntityFactory.CreateChapter("46", false, new List<MangaFile>(), 1),
EntityFactory.CreateChapter("47", false, new List<MangaFile>(), 1),
EntityFactory.CreateChapter("48", false, new List<MangaFile>(), 1),
EntityFactory.CreateChapter("Some Special Title", true, new List<MangaFile>(), 1),
}),
// One file volume
EntityFactory.CreateVolume("1", new List<Chapter>()
{
EntityFactory.CreateChapter("0", false, new List<MangaFile>(), 1), // Read
}),
// Chapter-based volume
EntityFactory.CreateVolume("2", new List<Chapter>()
{
EntityFactory.CreateChapter("21", false, new List<MangaFile>(), 1), // Read
EntityFactory.CreateChapter("22", false, new List<MangaFile>(), 1),
}),
// Chapter-based volume
EntityFactory.CreateVolume("3", new List<Chapter>()
{
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
}),
}
});
_context.AppUser.Add(new AppUser()
{
UserName = "majora2007"
});
await _context.SaveChangesAsync();
var readerService = new ReaderService(_unitOfWork, Substitute.For<ILogger<ReaderService>>());
// Save progress on first volume and 1st chapter of second volume
await readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 6, // Chapter 0 volume 1 id
SeriesId = 1,
VolumeId = 2 // Volume 1 id
}, 1);
await readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 7, // Chapter 21 volume 2 id
SeriesId = 1,
VolumeId = 3 // Volume 2 id
}, 1);
await _context.SaveChangesAsync();
var nextChapter = await readerService.GetContinuePoint(1, 1);
Assert.Equal("22", nextChapter.Range);
}
[Fact]

View File

@ -5,11 +5,8 @@
<app-drawer #commentDrawer="drawer" [isOpen]="drawerOpen" [style.--drawer-width]="'300px'" [options]="{topOffset: topOffset}" [style.--drawer-background-color]="drawerBackgroundColor" (drawerClosed)="closeDrawer()">
<div header>
<h2 style="margin-top: 0.5rem">Book Settings
<button type="button" class="btn-close" aria-label="Close" (click)="commentDrawer.close()">
</button>
<button type="button" class="btn-close" aria-label="Close" (click)="commentDrawer.close()"></button>
</h2>
</div>
<div body class="drawer-body">
<div class="control-container">

View File

@ -782,13 +782,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
}
setPageNum(pageNum: number) {
if (pageNum < 0) {
this.pageNum = 0;
} else if (pageNum >= this.maxPages - 1) { // This case handles when we are using the pager to move to the next volume/chapter, the pageNum will get incremented past maxPages // NOTE: I made a change where I removed - 1 in comparison, it's breaking page progress
this.pageNum = this.maxPages; //
} else {
this.pageNum = pageNum;
}
this.pageNum = Math.max(Math.min(pageNum, this.maxPages), 0);
}
goBack() {

View File

@ -219,10 +219,10 @@ export class EditSeriesModalComponent implements OnInit, OnDestroy {
return {id: 0, title: title, promoted: false, coverImage: '', summary: '', coverImageLocked: false };
});
this.collectionTagSettings.compareFn = (options: CollectionTag[], filter: string) => {
console.log('compareFN:')
console.log('options: ', options);
console.log('filter: ', filter);
console.log('results: ', options.filter(m => this.utilityService.filter(m.title, filter)));
// console.log('compareFN:')
// console.log('options: ', options);
// console.log('filter: ', filter);
// console.log('results: ', options.filter(m => this.utilityService.filter(m.title, filter)));
return options.filter(m => this.utilityService.filter(m.title, filter));
}
this.collectionTagSettings.selectionCompareFn = (a: CollectionTag, b: CollectionTag) => {

View File

@ -1,26 +1,18 @@
<app-side-nav-companion-bar *ngIf="series !== undefined">
<ng-container title>
<h2 style="margin-bottom: 0px">
<app-card-actionables [disabled]="actionInProgress" (actionHandler)="performAction($event)" [actions]="collectionTagActions" [labelBy]="collectionTag.title" iconClass="fa-ellipsis-v"></app-card-actionables>
{{collectionTag.title}}
</h2>
</ng-container>
</app-side-nav-companion-bar>
<div class="container-fluid" *ngIf="collectionTag !== undefined" style="padding-top: 10px">
<div class="row mb-3">
<div class="col-md-2 col-xs-4 col-sm-6 poster">
<app-image maxWidth="481px" [imageUrl]="tagImage"></app-image>
</div>
<div class="col-md-10 col-xs-8 col-sm-6">
<div class="row g-0">
<h2>
{{collectionTag.title}}
</h2>
</div>
<div class="row g-0 mt-2 mb-2">
<div class="ms-2" *ngIf="isAdmin">
<button class="btn btn-secondary" (click)="openEditCollectionTagModal(collectionTag)" title="Edit Series information">
<span>
<i class="fa fa-pen" aria-hidden="true"></i>
</span>
</button>
</div>
</div>
<div class="row g-0">
<app-read-more [text]="summary" [maxLength]="250"></app-read-more>
</div>
<app-read-more [text]="summary" [maxLength]="250"></app-read-more>
</div>
</div>
<hr>

View File

@ -42,6 +42,9 @@ export class CollectionDetailComponent implements OnInit, OnDestroy {
filterSettings: FilterSettings = new FilterSettings();
summary: string = '';
actionInProgress: boolean = false;
private onDestory: Subject<void> = new Subject<void>();
bulkActionCallback = (action: Action, data: any) => {
@ -197,6 +200,12 @@ export class CollectionDetailComponent implements OnInit, OnDestroy {
}
}
performAction(action: ActionItem<any>) {
if (typeof action.callback === 'function') {
action.callback(action.action, this.collectionTag);
}
}
openEditCollectionTagModal(collectionTag: CollectionTag) {
const modalRef = this.modalService.open(EditCollectionTagsComponent, { size: 'lg', scrollable: true });
modalRef.componentInstance.tag = this.collectionTag;

View File

@ -19,7 +19,7 @@
<span class="visually-hidden">Keyboard Shortcuts Modal</span>
</button>
<!-- {{this.pageNum}} -->
{{readerService.imageUrlToPageNum(canvasImage.src)}}<ng-container *ngIf="ShouldRenderDoublePage && (this.pageNum + 1 <= maxPages - 1 && this.pageNum > 0)"> - {{PageNumber + 1}}</ng-container>
<!-- {{readerService.imageUrlToPageNum(canvasImage.src)}}<ng-container *ngIf="ShouldRenderDoublePage && (this.pageNum + 1 <= maxPages - 1 && this.pageNum > 0)"> - {{PageNumber + 1}}</ng-container> -->
<button class="btn btn-icon btn-small" role="checkbox" [attr.aria-checked]="isCurrentPageBookmarked" title="{{isCurrentPageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}" (click)="bookmarkPage()"><i class="{{isCurrentPageBookmarked ? 'fa' : 'far'}} fa-bookmark" aria-hidden="true"></i><span class="visually-hidden">{{isCurrentPageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}</span></button>
</div>

View File

@ -5,7 +5,7 @@
</div>
<div class="not-phone-hidden">
<app-drawer #commentDrawer="drawer" [isOpen]="!filteringCollapsed" [style.--drawer-width]="'300px'" [style.--drawer-background-color]="'#010409'" [options]="{topOffset: 56}" (drawerClosed)="filteringCollapsed = !filteringCollapsed">
<app-drawer #commentDrawer="drawer" [isOpen]="!filteringCollapsed" [style.--drawer-width]="'300px'" [options]="{topOffset: 56}" (drawerClosed)="filteringCollapsed = !filteringCollapsed">
<div header>
<h2 style="margin-top: 0.5rem">Book Settings
<button type="button" class="btn-close" aria-label="Close" (click)="commentDrawer.close()"></button>

View File

@ -8,7 +8,7 @@
<div class="align-middle" style="padding-top: 40px">
<label for="reorder-{{i}}" class="form-label visually-hidden">Reorder</label>
<input *ngIf="accessibilityMode" id="reorder-{{i}}" type="number" min="0" [max]="items.length - 1" [value]="i" style="width: 40px" (focusout)="updateIndex(i, item)" (keydown.enter)="updateIndex(i, item)" aria-describedby="instructions">
<input *ngIf="accessibilityMode" id="reorder-{{i}}" class="form-control" type="number" min="0" [max]="items.length - 1" [value]="i" style="width: 60px" (focusout)="updateIndex(i, item)" (keydown.enter)="updateIndex(i, item)" aria-describedby="instructions">
</div>
<button class="btn btn-icon pull-right" (click)="removeItem(item, i)">
<i class="fa fa-times" aria-hidden="true"></i>
@ -19,5 +19,5 @@
</div>
<p class="visually-hidden" id="instructions">
When you put a number in the reorder input, the item will be inserted at that location and all other items will have their order updated.
</p>

View File

@ -14,7 +14,7 @@
<div class="col-md-2 col-xs-4 col-sm-6">
<app-image class="poster" maxWidth="300px" [imageUrl]="seriesImage"></app-image>
</div>
<div class="col-md-10 col-xs-8 col-sm-6">
<div class="col-md-10 col-xs-8 col-sm-6 mt-2">
<div class="row g-0">
<div class="col-auto">
<button class="btn btn-primary" (click)="read()">

View File

@ -1,6 +1,6 @@
<div
class="drawer-container"
[ngStyle]="{'top': options.topOffset + 'px'}"
[ngStyle]="{'top': options.topOffset + 'px', 'padding-bottom': options.topOffset + 'px'}"
[class.is-open]="isOpen"
[class.position-right]="position === 'right'"
[class.position-left]="position === 'left'"

View File

@ -2,7 +2,7 @@
--drawer-height: 100vh;
--drawer-width: 400px;
--drawer-top-offset: 0px;
--drawer-background-color: '#fff';
//--drawer-background-color: #fff;
}
.drawer-container {
@ -11,7 +11,7 @@
right: 0;
width: var(--drawer-width);
height: 100vh;
background: var(--drawer-background-color);
background: var(--drawer-background-color, #fff);
transition: all 300ms;
box-shadow: 0 6px 4px 2px rgb(0 0 0 / 70%);
padding: 10px 10px;

View File

@ -1,3 +1,9 @@
.hide-if-empty:empty {
display: none;
}
::ng-deep .companion-bar {
h1, h2, h3, h4, h5, h6 {
margin-bottom: 0px;
}
}

View File

@ -80,6 +80,7 @@
}
&:hover {
color: var(--side-nav-hover-color);
background-color: var(--side-nav-hover-bg-color);
}
}
@ -136,71 +137,4 @@ a {
}
}
}
}
// @media (max-width: 576px) {
// .side-nav-item {
// align-items: center;
// display: flex;
// justify-content: space-between;
// padding: 15px 10px;
// width: 100%;
// height: 70px;
// min-height: 40px;
// overflow: hidden;
// font-size: 1rem;
// cursor: pointer;
// .side-nav-text {
// padding-left: 10px;
// opacity: 1;
// min-width: 100px;
// width: 100%;
// div {
// min-width: 102px;
// width: 100%
// }
// }
// .card-actions {
// opacity: 1;
// }
// div {
// align-items: center;
// display: flex;
// height: 100%;
// justify-content: inherit;
// min-width: 30px;
// width: 100%;
// padding-left: 5px;
// i {
// font-size: 2rem;
// width: 50px;
// }
// }
// &.closed {
// .side-nav-text {
// opacity: 0;
// }
// .card-actions {
// opacity: 0;
// font-size: inherit
// }
// }
// span {
// &:last-child {
// flex-grow: 1;
// justify-content: end;
// }
// }
// }
// }
}

View File

@ -223,6 +223,7 @@ export class TypeaheadComponent implements OnInit, OnDestroy {
switchMap(val => {
this.isLoadingOptions = true;
let results: Observable<any[]>;
console.log('val: ', val);
if (Array.isArray(this.settings.fetchFn)) {
const filteredArray = this.settings.compareFn(this.settings.fetchFn, val.trim());
results = of(filteredArray).pipe(takeUntil(this.onDestroy), map((items: any[]) => items.filter(item => this.filterSelected(item))));
@ -232,14 +233,14 @@ export class TypeaheadComponent implements OnInit, OnDestroy {
return results;
}),
tap((val) => {
tap((filteredOptions) => {
this.isLoadingOptions = false;
this.focusedIndex = 0;
this.updateShowAddItem(val);
// setTimeout(() => {
// this.updateShowAddItem(val);
// this.updateHighlight();
// }, 10);
//this.updateShowAddItem(filteredOptions);
setTimeout(() => {
this.updateShowAddItem(filteredOptions);
this.updateHighlight();
}, 10);
setTimeout(() => this.updateHighlight(), 20);
}),
shareReplay(),
@ -296,22 +297,29 @@ export class TypeaheadComponent implements OnInit, OnDestroy {
{
this.document.querySelectorAll('.list-group-item').forEach((item, index) => {
if (item.classList.contains('active')) {
this.filteredOptions.pipe(take(1)).subscribe((res: any[]) => {
this.filteredOptions.pipe(take(1)).subscribe((opts: any[]) => {
// This isn't giving back the filtered array, but everything
console.log(item.classList.contains('add-item'));
if (this.settings.addIfNonExisting && item.classList.contains('add-item')) {
this.addNewItem(this.typeaheadControl.value);
this.resetField();
this.focusedIndex = 0;
event.preventDefault();
event.stopPropagation();
return;
}
const result = this.settings.compareFn(res, (this.typeaheadControl.value || '').trim());
if (result.length === 1) {
this.toggleSelection(result[0]);
this.resetField();
this.focusedIndex = 0;
}
const filteredResults = opts.filter(item => this.filterSelected(item));
if (filteredResults.length < this.focusedIndex) return;
const option = filteredResults[this.focusedIndex];
this.toggleSelection(option);
this.resetField();
this.focusedIndex = 0;
event.preventDefault();
event.stopPropagation();
});
}
});
@ -445,6 +453,10 @@ export class TypeaheadComponent implements OnInit, OnDestroy {
&& this.typeaheadControl.value.trim().length >= Math.max(this.settings.minCharacters, 1)
&& this.typeaheadControl.dirty
&& (typeof this.settings.compareFn == 'function' && this.settings.compareFn(options, this.typeaheadControl.value.trim()).length === 0);
if (this.showAddItem) {
this.hasFocus = true;
}
console.log('show Add item: ', this.showAddItem);
console.log('compare func: ', this.settings.compareFn(options, this.typeaheadControl.value.trim()));

View File

@ -44,6 +44,7 @@ export class UserLoginComponent implements OnInit {
this.navService.hideSideNav();
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
if (user) {
this.navService.showSideNav();
this.router.navigateByUrl('/library');
}
});

View File

@ -208,4 +208,7 @@
--carousel-header-text-color: var(--body-text-color);
--carousel-header-text-decoration: none;
--carousel-hover-header-text-decoration: none;
/** Drawer */
--drawer-background-color: black;
}

View File

@ -143,5 +143,18 @@
--carousel-header-text-decoration: none;
--carousel-hover-header-text-decoration: none;
/** Drawer */
--drawer-background-color: white;
/* Pagination */
--pagination-active-link-border-color: var(--primary-color);
--pagination-active-link-bg-color: var(--primary-color);
--pagination-active-link-text-color: white;
--pagination-link-border-color: rgba(239, 239, 239, 1);
--pagination-link-text-color: black;
--pagination-link-bg-color: white;
--pagination-focus-border-color: var(--primary-color);
--pagination-link-hover-color: var(--primary-color);
}

View File

@ -135,4 +135,17 @@
--carousel-header-text-color: black;
--carousel-header-text-decoration: none;
--carousel-hover-header-text-decoration: underline;
}
/** Drawer */
--drawer-background-color: white;
/* Pagination */
--pagination-active-link-border-color: var(--primary-color);
--pagination-active-link-bg-color: var(--primary-color);
--pagination-active-link-text-color: white;
--pagination-link-border-color: rgba(239, 239, 239, 1);
--pagination-link-text-color: black;
--pagination-link-bg-color: white;
--pagination-focus-border-color: var(--primary-color);
--pagination-link-hover-color: var(--primary-color);
}