Bookmark Refactor (#893)
* Fixed a bug which didn't take sort direction when not changing sort field * Added foundation for Bookmark refactor * Code broken, need to take a break. Issue is Getting bookmark image needs authentication but UI doesn't send. * Implemented the ability to send bookmarked files to the web. Implemented ability to clear bookmarks on disk on a re-occuring basis. * Updated the bookmark design to have it's own card that is self contained. View bookmarks modal has been updated to better lay out the cards. * Refactored download bookmark codes to select files from bookmark directory directly rather than open underlying files. * Wrote the basic logic to kick start the bookmark migration. Added Installed Version into the DB to allow us to know more accurately when to run migrations * Implemented the ability to change the bookmarks directory * Updated all references to BookmarkDirectory to use setting from the DB. Updated Server Settings page to use 2 col for some rows. * Refactored some code to DirectoryService (hasWriteAccess) and fixed up some unit tests from a previous PR. * Treat folders that start with ._ as blacklisted. * Implemented Reset User preferences. Some extra code to prep for the migration. * Implemented a migration for existing bookmarks to using new filesystem based bookmarks
This commit is contained in:
parent
04ffd1ef6f
commit
a1a6333f09
45 changed files with 2006 additions and 103 deletions
|
|
@ -5,15 +5,16 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<ul class="list-unstyled">
|
||||
<li class="list-group-item" *ngIf="bookmarks.length > 0">
|
||||
There are {{bookmarks.length}} pages bookmarked over {{uniqueChapters}} files.
|
||||
</li>
|
||||
<li class="list-group-item" *ngIf="bookmarks.length === 0">
|
||||
No bookmarks yet
|
||||
</li>
|
||||
</ul>
|
||||
<p *ngIf="bookmarks.length > 0; else noBookmarks">
|
||||
There are {{bookmarks.length}} pages bookmarked over {{uniqueChapters}} files.
|
||||
</p>
|
||||
<ng-template #noBookmarks>No bookmarks yet</ng-template>
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div *ngFor="let bookmark of bookmarks; let idx = index">
|
||||
<app-bookmark [bookmark]="bookmark" (bookmarkRemoved)="removeBookmark(bookmark, idx)" class="col-auto"></app-bookmark>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" (click)="clearBookmarks()" [disabled]="(isDownloading || isClearing) || bookmarks.length === 0">
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ export class BookmarksModalComponent implements OnInit {
|
|||
this.modal.close();
|
||||
}
|
||||
|
||||
removeBookmark(bookmark: PageBookmark, index: number) {
|
||||
this.bookmarks.splice(index, 1);
|
||||
}
|
||||
|
||||
downloadBookmarks() {
|
||||
this.isDownloading = true;
|
||||
this.downloadService.downloadBookmarks(this.bookmarks).pipe(
|
||||
|
|
|
|||
28
UI/Web/src/app/cards/bookmark/bookmark.component.html
Normal file
28
UI/Web/src/app/cards/bookmark/bookmark.component.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<div class="card" *ngIf="bookmark != undefined">
|
||||
<img class="img-top lazyload" [src]="imageService.placeholderImage" [attr.data-src]="imageService.getBookmarkedImage(bookmark.chapterId, bookmark.page)"
|
||||
(error)="imageService.updateErroredImage($event)" aria-hidden="true" height="230px" width="170px">
|
||||
|
||||
<div class="card-body" *ngIf="bookmark.page >= 0">
|
||||
<div class="header-row">
|
||||
<span class="card-title" tabindex="0">
|
||||
Page {{bookmark.page + 1}}
|
||||
</span>
|
||||
<span class="card-actions float-right" *ngIf="series != undefined">
|
||||
<button attr.aria-labelledby="series--{{series.name}}" class="btn btn-danger btn-sm" (click)="removeBookmark()"
|
||||
[disabled]="isClearing" placement="top" ngbTooltip="Remove Bookmark" attr.aria-label="Remove Bookmark">
|
||||
<ng-container *ngIf="isClearing; else notClearing">
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
<span class="sr-only">Loading...</span>
|
||||
</ng-container>
|
||||
<ng-template #notClearing>
|
||||
<i class="fa fa-trash-alt" aria-hidden="true"></i>
|
||||
</ng-template>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<a *ngIf="series != undefined" class="title-overflow library" href="/library/{{series.libraryId}}/series/{{series.id}}"
|
||||
placement="top" id="bookmark_card_{{series.name}}_{{bookmark.id}}" [ngbTooltip]="series.name | titlecase">{{series.name | titlecase}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
UI/Web/src/app/cards/bookmark/bookmark.component.scss
Normal file
25
UI/Web/src/app/cards/bookmark/bookmark.component.scss
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
.card-body {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.title-overflow {
|
||||
font-size: 13px;
|
||||
width: 130px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
43
UI/Web/src/app/cards/bookmark/bookmark.component.ts
Normal file
43
UI/Web/src/app/cards/bookmark/bookmark.component.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Series } from 'src/app/_models/series';
|
||||
import { ImageService } from 'src/app/_services/image.service';
|
||||
import { ReaderService } from 'src/app/_services/reader.service';
|
||||
import { SeriesService } from 'src/app/_services/series.service';
|
||||
import { PageBookmark } from '../../_models/page-bookmark';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bookmark',
|
||||
templateUrl: './bookmark.component.html',
|
||||
styleUrls: ['./bookmark.component.scss']
|
||||
})
|
||||
export class BookmarkComponent implements OnInit {
|
||||
|
||||
@Input() bookmark: PageBookmark | undefined;
|
||||
@Output() bookmarkRemoved: EventEmitter<PageBookmark> = new EventEmitter<PageBookmark>();
|
||||
series: Series | undefined;
|
||||
|
||||
isClearing: boolean = false;
|
||||
isDownloading: boolean = false;
|
||||
|
||||
constructor(public imageService: ImageService, private seriesService: SeriesService, private readerService: ReaderService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.bookmark) {
|
||||
this.seriesService.getSeries(this.bookmark.seriesId).subscribe(series => {
|
||||
this.series = series;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(event: any) {
|
||||
|
||||
}
|
||||
|
||||
removeBookmark() {
|
||||
if (this.bookmark === undefined) return;
|
||||
this.readerService.unbookmark(this.bookmark.seriesId, this.bookmark.volumeId, this.bookmark.chapterId, this.bookmark.page).subscribe(res => {
|
||||
this.bookmarkRemoved.emit(this.bookmark);
|
||||
this.bookmark = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@
|
|||
|
||||
<div class="not-read-badge" *ngIf="read === 0 && total > 0"></div>
|
||||
<div class="bulk-mode {{bulkSelectionService.hasSelections() ? 'always-show' : ''}}" (click)="handleSelection($event)" *ngIf="allowSelection">
|
||||
<input type="checkbox" attr.aria-labelledby="{{title}}_{{entity.id}}" [ngModel]="selected" [ngModelOptions]="{standalone: true}">
|
||||
<input type="checkbox" attr.aria-labelledby="{{title}}_{{entity?.id}}" [ngModel]="selected" [ngModelOptions]="{standalone: true}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body" *ngIf="title.length > 0 || actions.length > 0">
|
||||
<div>
|
||||
<span class="card-title" placement="top" id="{{title}}_{{entity.id}}" [ngbTooltip]="tooltipTitle" (click)="handleClick()" tabindex="0">
|
||||
<span class="card-title" placement="top" id="{{title}}_{{entity?.id}}" [ngbTooltip]="tooltipTitle" (click)="handleClick()" tabindex="0">
|
||||
<span *ngIf="isPromoted()">
|
||||
<i class="fa fa-angle-double-up" aria-hidden="true"></i>
|
||||
<span class="sr-only">(promoted)</span>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { UtilityService } from 'src/app/shared/_services/utility.service';
|
|||
import { Chapter } from 'src/app/_models/chapter';
|
||||
import { CollectionTag } from 'src/app/_models/collection-tag';
|
||||
import { MangaFormat } from 'src/app/_models/manga-format';
|
||||
import { PageBookmark } from 'src/app/_models/page-bookmark';
|
||||
import { Series } from 'src/app/_models/series';
|
||||
import { Volume } from 'src/app/_models/volume';
|
||||
import { Action, ActionItem } from 'src/app/_services/action-factory.service';
|
||||
|
|
@ -49,7 +50,7 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||
/**
|
||||
* This is the entity we are representing. It will be returned if an action is executed.
|
||||
*/
|
||||
@Input() entity!: Series | Volume | Chapter | CollectionTag;
|
||||
@Input() entity!: Series | Volume | Chapter | CollectionTag | PageBookmark;
|
||||
/**
|
||||
* If the entity is selected or not.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { EditCollectionTagsComponent } from './_modals/edit-collection-tags/edit
|
|||
import { ChangeCoverImageModalComponent } from './_modals/change-cover-image/change-cover-image-modal.component';
|
||||
import { BookmarksModalComponent } from './_modals/bookmarks-modal/bookmarks-modal.component';
|
||||
import { LazyLoadImageModule } from 'ng-lazyload-image';
|
||||
import { NgbTooltipModule, NgbCollapseModule, NgbPaginationModule, NgbDropdownModule, NgbProgressbarModule, NgbNavModule, NgbAccordionModule, NgbRatingModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgbTooltipModule, NgbCollapseModule, NgbPaginationModule, NgbDropdownModule, NgbProgressbarModule, NgbNavModule, NgbRatingModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { CardActionablesComponent } from './card-item/card-actionables/card-actionables.component';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { NgxFileDropModule } from 'ngx-file-drop';
|
||||
|
|
@ -23,6 +23,7 @@ import { BulkAddToCollectionComponent } from './_modals/bulk-add-to-collection/b
|
|||
import { PipeModule } from '../pipe/pipe.module';
|
||||
import { ChapterMetadataDetailComponent } from './chapter-metadata-detail/chapter-metadata-detail.component';
|
||||
import { FileInfoComponent } from './file-info/file-info.component';
|
||||
import { BookmarkComponent } from './bookmark/bookmark.component';
|
||||
|
||||
|
||||
|
||||
|
|
@ -42,7 +43,8 @@ import { FileInfoComponent } from './file-info/file-info.component';
|
|||
BulkOperationsComponent,
|
||||
BulkAddToCollectionComponent,
|
||||
ChapterMetadataDetailComponent,
|
||||
FileInfoComponent
|
||||
FileInfoComponent,
|
||||
BookmarkComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue