mirror of
https://github.com/booklore-app/booklore.git
synced 2025-12-23 22:28:11 -05:00
Checkpoint
This commit is contained in:
@@ -2,6 +2,7 @@ package com.adityachandel.booklore.controller;
|
||||
|
||||
import com.adityachandel.booklore.model.dto.BookDTO;
|
||||
import com.adityachandel.booklore.model.dto.BookViewerSettingDTO;
|
||||
import com.adityachandel.booklore.model.dto.BookWithNeighborsDTO;
|
||||
import com.adityachandel.booklore.model.dto.response.GoogleBooksMetadata;
|
||||
import com.adityachandel.booklore.model.dto.request.SetMetadataRequest;
|
||||
import com.adityachandel.booklore.service.BooksService;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.adityachandel.booklore.controller;
|
||||
|
||||
import com.adityachandel.booklore.model.dto.BookDTO;
|
||||
import com.adityachandel.booklore.model.dto.BookWithNeighborsDTO;
|
||||
import com.adityachandel.booklore.model.dto.LibraryDTO;
|
||||
import com.adityachandel.booklore.model.dto.request.CreateLibraryRequest;
|
||||
import com.adityachandel.booklore.service.BooksService;
|
||||
import com.adityachandel.booklore.service.LibraryService;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
@@ -19,6 +21,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
public class LibraryController {
|
||||
|
||||
private LibraryService libraryService;
|
||||
private BooksService booksService;
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<LibraryDTO> createLibraryNew(@RequestBody CreateLibraryRequest request) {
|
||||
@@ -46,6 +49,11 @@ public class LibraryController {
|
||||
return ResponseEntity.ok(libraryService.getLibraries(page, size));
|
||||
}
|
||||
|
||||
@GetMapping("/{libraryId}/book/{bookId}/withNeighbors")
|
||||
public ResponseEntity<BookWithNeighborsDTO> getBookWithNeighbours(@PathVariable long libraryId, @PathVariable long bookId) {
|
||||
return ResponseEntity.ok(booksService.getBookWithNeighbours(libraryId, bookId));
|
||||
}
|
||||
|
||||
@GetMapping("/{libraryId}/book/{bookId}")
|
||||
public ResponseEntity<BookDTO> getBook(@PathVariable long libraryId, @PathVariable long bookId) {
|
||||
return ResponseEntity.ok(libraryService.getBook(libraryId, bookId));
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.adityachandel.booklore.model.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
public class BookWithNeighborsDTO {
|
||||
private BookDTO currentBook;
|
||||
private Long previousBookId;
|
||||
private Long nextBookId;
|
||||
}
|
||||
@@ -27,5 +27,9 @@ public interface BookRepository extends JpaRepository<Book, Long>, JpaSpecificat
|
||||
Page<Book> findByLastReadTimeIsNotNull(Pageable pageable);
|
||||
|
||||
Page<Book> findByAddedOnIsNotNull(Pageable pageable);
|
||||
|
||||
Optional<Book> findFirstByLibraryIdAndIdLessThanOrderByIdDesc(Long libraryId, Long currentBookId);
|
||||
|
||||
Optional<Book> findFirstByLibraryIdAndIdGreaterThanOrderByIdAsc(Long libraryId, Long currentBookId);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.adityachandel.booklore.service;
|
||||
|
||||
import com.adityachandel.booklore.config.AppProperties;
|
||||
import com.adityachandel.booklore.model.dto.BookDTO;
|
||||
import com.adityachandel.booklore.model.dto.BookWithNeighborsDTO;
|
||||
import com.adityachandel.booklore.model.dto.response.GoogleBooksMetadata;
|
||||
import com.adityachandel.booklore.model.dto.BookViewerSettingDTO;
|
||||
import com.adityachandel.booklore.model.dto.request.SetMetadataRequest;
|
||||
@@ -47,6 +48,7 @@ public class BooksService {
|
||||
private final BookMetadataRepository metadataRepository;
|
||||
private final AuthorRepository authorRepository;
|
||||
private final CategoryRepository categoryRepository;
|
||||
private final LibraryRepository libraryRepository;
|
||||
|
||||
|
||||
public BookDTO getBook(long bookId) {
|
||||
@@ -210,4 +212,17 @@ public class BooksService {
|
||||
return fileName.substring(0, dotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public BookWithNeighborsDTO getBookWithNeighbours(long libraryId, long bookId) {
|
||||
libraryRepository.findById(libraryId).orElseThrow(() -> ErrorCode.LIBRARY_NOT_FOUND.createException(libraryId));
|
||||
Book book = bookRepository.findById(bookId).orElseThrow(() -> ErrorCode.BOOK_NOT_FOUND.createException(bookId));
|
||||
Book previousBook = bookRepository.findFirstByLibraryIdAndIdLessThanOrderByIdDesc(libraryId, bookId).orElse(null);
|
||||
Book nextBook = bookRepository.findFirstByLibraryIdAndIdGreaterThanOrderByIdAsc(libraryId, bookId).orElse(null);
|
||||
return BookWithNeighborsDTO.builder()
|
||||
.currentBook(BookTransformer.convertToBookDTO(book))
|
||||
.previousBookId(previousBook != null ? previousBook.getId() : null)
|
||||
.nextBookId(nextBook != null ? nextBook.getId() : null)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class PdfFileProcessor implements FileProcessor {
|
||||
}
|
||||
}
|
||||
generateCoverImage(bookFile, new File(appProperties.getPathConfig() + "/thumbs"), document);
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
log.error("Error while processing file {}", libraryFile.getFilePath(), e);
|
||||
return FileProcessResult.builder()
|
||||
.libraryFile(libraryFile)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {AppLayoutComponent} from './layout/app.layout.component';
|
||||
import {AppLayoutComponent} from './book/component/layout/app.layout.component';
|
||||
import {LibraryBrowserComponent} from './book/component/library-browser/library-browser.component';
|
||||
import {PdfViewerComponent} from './book/component/pdf-viewer/pdf-viewer.component';
|
||||
import {DashboardComponent} from './book/component/dashboard/dashboard.component';
|
||||
import {BookMetadataComponent} from './book-metadata/book-metadata.component';
|
||||
import {BookMetadataComponent} from './book/component/book-metadata/book-metadata.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -17,7 +17,7 @@ const routes: Routes = [
|
||||
path: 'library/:libraryId/books', component: LibraryBrowserComponent,
|
||||
},
|
||||
{
|
||||
path: 'book/:bookId/info', component: BookMetadataComponent,
|
||||
path: 'library/:libraryId/book/:bookId/info', component: BookMetadataComponent,
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {AppRoutingModule} from './app-routing.module';
|
||||
import {AppComponent} from './app.component';
|
||||
import {AppLayoutModule} from './layout/app.layout.module';
|
||||
import {AppLayoutModule} from './book/component/layout/app.layout.module';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {DialogService} from 'primeng/dynamicdialog';
|
||||
import {DirectoryPickerComponent} from './book/component/directory-picker/directory-picker.component';
|
||||
@@ -20,10 +20,10 @@ import {ToastModule} from 'primeng/toast';
|
||||
import {LibraryBrowserComponent} from './book/component/library-browser/library-browser.component';
|
||||
import {InfiniteScrollDirective} from 'ngx-infinite-scroll';
|
||||
import {SearchComponent} from './book/component/search/search.component';
|
||||
import { BookMetadataComponent } from './book-metadata/book-metadata.component';
|
||||
import { BooksMetadataDialogComponent } from './books-metadata-dialog/books-metadata-dialog.component';
|
||||
import { BookMetadataComponent } from './book/component/book-metadata/book-metadata.component';
|
||||
import { BooksMetadataDialogComponent } from './book/component/books-metadata-dialog/books-metadata-dialog.component';
|
||||
import {MessageService} from 'primeng/api';
|
||||
import { NotificationComponent } from './notification/notification.component';
|
||||
import { NotificationComponent } from './book/component/notification/notification.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import {Component, OnInit, OnDestroy} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {BookService} from '../book/service/book.service';
|
||||
import {Book} from '../book/model/book.model';
|
||||
import {Button} from 'primeng/button';
|
||||
import {NgForOf} from '@angular/common';
|
||||
import {BooksMetadataDialogComponent} from '../books-metadata-dialog/books-metadata-dialog.component';
|
||||
import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {TagModule} from 'primeng/tag';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-metadata',
|
||||
templateUrl: './book-metadata.component.html',
|
||||
styleUrls: ['./book-metadata.component.scss'],
|
||||
imports: [
|
||||
Button,
|
||||
NgForOf,
|
||||
TagModule
|
||||
]
|
||||
})
|
||||
export class BookMetadataComponent implements OnInit, OnDestroy {
|
||||
book: Book | null = null;
|
||||
private routeSubscription!: Subscription;
|
||||
ref: DynamicDialogRef | undefined;
|
||||
|
||||
constructor(
|
||||
private bookService: BookService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private dialogService: DialogService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.routeSubscription = this.activatedRoute.paramMap.subscribe((paramMap) => {
|
||||
const bookId = +paramMap.get('bookId')!;
|
||||
if (bookId) {
|
||||
this.loadBook(bookId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private loadBook(bookId: number): void {
|
||||
this.bookService.getBook(bookId).subscribe((book) => {
|
||||
this.book = book;
|
||||
});
|
||||
}
|
||||
|
||||
getAuthorNames(book: Book | null): string {
|
||||
if (book && book.metadata && book.metadata.authors) {
|
||||
return book.metadata.authors.map((author) => author.name).join(', ');
|
||||
}
|
||||
return 'No authors available';
|
||||
}
|
||||
|
||||
openEditDialog(id: number | undefined) {
|
||||
this.ref = this.dialogService.open(BooksMetadataDialogComponent, {
|
||||
header: 'Fetch Metadata (from Google Books)',
|
||||
modal: false,
|
||||
width: '65%',
|
||||
height: '85%',
|
||||
data: {
|
||||
bookId: id,
|
||||
bookTitle: this.book?.metadata.title,
|
||||
},
|
||||
});
|
||||
|
||||
this.ref.onClose.subscribe(() => {
|
||||
// @ts-ignore
|
||||
this.loadBook(this.book?.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
coverImageSrc(bookId: any): string {
|
||||
if (bookId === null) {
|
||||
return 'assets/placeholder.png';
|
||||
}
|
||||
return this.bookService.getBookCoverUrl(bookId);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.routeSubscription) {
|
||||
this.routeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
readBook(id: number | undefined) {
|
||||
const url = `/pdf-viewer/book/${id}`;
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,38 @@
|
||||
<div class="book-metadata">
|
||||
<div class="book-header">
|
||||
<div class="cover-container">
|
||||
<img [src]="coverImageSrc(book?.id)" class="book-cover placeholder" alt="Cover of {{ book?.metadata?.title }}"
|
||||
loading="lazy"/>
|
||||
<img [src]="coverImageSrc(book?.id)" class="book-cover placeholder" alt="Cover of {{ book?.metadata?.title }}" loading="lazy"/>
|
||||
<div>
|
||||
<div class="book-navigation">
|
||||
<p-button
|
||||
icon="pi pi-arrow-left"
|
||||
class="navigation-button"
|
||||
severity="help"
|
||||
(click)="navigateToBook(previousBookId, book?.libraryId!)"
|
||||
[rounded]="true"
|
||||
[outlined]="true"
|
||||
[disabled]="!canGoPrevious()">
|
||||
</p-button>
|
||||
<p-button
|
||||
icon="pi pi-arrow-right"
|
||||
class="navigation-button"
|
||||
severity="help"
|
||||
(click)="navigateToBook(nextBookId, book?.libraryId!)"
|
||||
[rounded]="true"
|
||||
[outlined]="true"
|
||||
[disabled]="!canGoNext()">
|
||||
</p-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metadata">
|
||||
<div class="title-row">
|
||||
<h2 class="book-title">{{ book?.metadata?.title || 'Untitled' }}</h2>
|
||||
<h1 class="book-title">
|
||||
{{ book?.metadata?.title }}<span *ngIf="book?.metadata?.subtitle">: {{ book?.metadata?.subtitle }}</span>
|
||||
</h1>
|
||||
<div class="button-group">
|
||||
<p-button [rounded]="true" [raised]="true" [outlined]="true" (onClick)="openEditDialog(book?.id)"
|
||||
icon="pi pi-pencil"></p-button>
|
||||
<p-button [rounded]="true" [raised]="true" [outlined]="true" (onClick)="readBook(book?.id)"
|
||||
icon="pi pi-eye"></p-button>
|
||||
<p-button [rounded]="true" [raised]="true" [outlined]="true" (onClick)="openEditDialog(book?.id, book?.libraryId)" icon="pi pi-pencil"></p-button>
|
||||
<p-button [rounded]="true" [raised]="true" [outlined]="true" (onClick)="readBook(book?.id)" icon="pi pi-eye"></p-button>
|
||||
<p-button [rounded]="true" [raised]="true" [outlined]="true" icon="pi pi-download"></p-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
.book-title {
|
||||
font-size: 1.65rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -86,3 +86,16 @@
|
||||
.book-description {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.book-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0.8rem 1rem 0;
|
||||
}
|
||||
|
||||
.book-subtitle {
|
||||
font-size: 1rem;
|
||||
color: var(--text-color-secondary);
|
||||
margin-top: 0.25rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {BookService} from '../../service/book.service';
|
||||
import {Book} from '../../model/book.model';
|
||||
import {Button} from 'primeng/button';
|
||||
import {NgForOf, NgIf} from '@angular/common';
|
||||
import {BooksMetadataDialogComponent} from '../books-metadata-dialog/books-metadata-dialog.component';
|
||||
import {DialogService, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {TagModule} from 'primeng/tag';
|
||||
|
||||
@Component({
|
||||
selector: 'app-book-metadata',
|
||||
templateUrl: './book-metadata.component.html',
|
||||
styleUrls: ['./book-metadata.component.scss'],
|
||||
imports: [
|
||||
Button,
|
||||
NgForOf,
|
||||
TagModule,
|
||||
NgIf
|
||||
]
|
||||
})
|
||||
export class BookMetadataComponent implements OnInit, OnDestroy {
|
||||
book: Book | null = null;
|
||||
nextBookId: number | null = null;
|
||||
previousBookId: number | null = null;
|
||||
|
||||
private routeSubscription!: Subscription;
|
||||
private dialogRef: DynamicDialogRef | undefined;
|
||||
private dialogSubscription?: Subscription;
|
||||
|
||||
constructor(
|
||||
private bookService: BookService, private activatedRoute: ActivatedRoute,
|
||||
private dialogService: DialogService, private router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.routeSubscription = this.activatedRoute.paramMap.subscribe((paramMap) => {
|
||||
const bookId = +paramMap.get('bookId')!;
|
||||
const libraryId = +paramMap.get('libraryId')!;
|
||||
if (bookId && libraryId) {
|
||||
this.loadBookWithNeighbors(bookId, libraryId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private loadBookWithNeighbors(libraryId: number, bookId: number): void {
|
||||
this.bookService.getBookWithNeighbours(bookId, libraryId).subscribe((response) => {
|
||||
this.book = response.currentBook;
|
||||
this.nextBookId = response.nextBookId;
|
||||
this.previousBookId = response.previousBookId;
|
||||
});
|
||||
}
|
||||
|
||||
navigateToBook(bookId: number | null, libraryId: number | null): void {
|
||||
if (bookId && libraryId) {
|
||||
this.router.navigate(['/library', libraryId, 'book', bookId, 'info']);
|
||||
}
|
||||
}
|
||||
|
||||
canGoNext(): boolean {
|
||||
return this.nextBookId !== null;
|
||||
}
|
||||
|
||||
canGoPrevious(): boolean {
|
||||
return this.previousBookId !== null;
|
||||
}
|
||||
|
||||
getAuthorNames(book: Book | null): string {
|
||||
if (book && book.metadata && book.metadata.authors) {
|
||||
return book.metadata.authors.map((author) => author.name).join(', ');
|
||||
}
|
||||
return 'No authors available';
|
||||
}
|
||||
|
||||
openEditDialog(bookId: number | undefined, libraryId: number | undefined) {
|
||||
this.dialogRef = this.dialogService.open(BooksMetadataDialogComponent, {
|
||||
header: 'Metadata: Google Books',
|
||||
modal: false,
|
||||
width: '65%',
|
||||
height: '85%',
|
||||
data: {
|
||||
bookId: bookId,
|
||||
libraryId: libraryId,
|
||||
bookTitle: this.book?.metadata.title,
|
||||
},
|
||||
});
|
||||
|
||||
this.dialogSubscription = this.dialogRef.onClose.subscribe(() => {
|
||||
if (this.book?.id && this.book.libraryId) {
|
||||
this.loadBookWithNeighbors(this.book.id, this.book.libraryId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
coverImageSrc(bookId: number | undefined): string {
|
||||
if (bookId === null) {
|
||||
return 'assets/book-cover-metadata.png';
|
||||
}
|
||||
return this.bookService.getBookCoverUrl(bookId!);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.routeSubscription) {
|
||||
this.routeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
readBook(id: number | undefined) {
|
||||
const url = `/pdf-viewer/book/${id}`;
|
||||
window.open(url, '_blank');
|
||||
this.routeSubscription?.unsubscribe();
|
||||
this.dialogSubscription?.unsubscribe();
|
||||
this.dialogRef?.close();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,3 @@
|
||||
<div *ngIf="!isLoading && bookMetadataList.length > 0" class="search-container">
|
||||
<div class="input-group">
|
||||
<input type="text" [(ngModel)]="searchText" placeholder="Enter book title" />
|
||||
<p-button severity="success" (click)="populateTitle()">Search</p-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isLoading" class="loading">
|
||||
Loading metadata...
|
||||
</div>
|
||||
|
||||
<div *ngIf="errorMessage" class="error">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isLoading && bookMetadataList.length > 0" class="metadata-list">
|
||||
<div *ngFor="let metadata of bookMetadataList" class="book-metadata">
|
||||
<div class="metadata-header">
|
||||
@@ -21,8 +6,10 @@
|
||||
<p-button class="select-button" (click)="selectMetadata(metadata)">Select</p-button>
|
||||
</div>
|
||||
<div>
|
||||
<h3>{{ metadata.title }}</h3>
|
||||
<p><strong>Authors:</strong> {{ metadata.authors?.join(', ') || 'No authors available' }}</p>
|
||||
<h3>
|
||||
{{ metadata.title }}<span *ngIf="metadata.subtitle">: {{ metadata.subtitle }}</span>
|
||||
</h3>
|
||||
<p><strong>Authors:</strong> {{ metadata.authors.join(', ') || 'No authors available' }}</p>
|
||||
<p><strong>Publisher:</strong> {{ metadata.publisher }}</p>
|
||||
<p><strong>Published Date:</strong> {{ metadata.publishedDate }}</p>
|
||||
<p><strong>ISBN:</strong> {{ metadata.isbn10 }}</p>
|
||||
@@ -32,9 +19,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div *ngIf="!isLoading && bookMetadataList.length === 0" class="no-metadata">
|
||||
No metadata found for this book.
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {BookMetadata} from '../book/model/book.model';
|
||||
import {BookService} from '../book/service/book.service';
|
||||
import {BookMetadata} from '../../model/book.model';
|
||||
import {BookService} from '../../service/book.service';
|
||||
import {NgForOf, NgIf} from '@angular/common';
|
||||
import {FormBuilder, FormsModule} from '@angular/forms';
|
||||
import {DynamicDialogConfig, DynamicDialogRef} from 'primeng/dynamicdialog';
|
||||
@@ -24,11 +24,12 @@ export class BooksMetadataDialogComponent implements OnInit {
|
||||
errorMessage: string | null = null;
|
||||
searchText: string = '';
|
||||
bookId: number = 0;
|
||||
libraryId: number = 0;
|
||||
|
||||
constructor(private bookService: BookService, public dynamicDialogConfig: DynamicDialogConfig,
|
||||
private dynamicDialogRef: DynamicDialogRef, private router: Router) {
|
||||
constructor(private bookService: BookService, public dynamicDialogConfig: DynamicDialogConfig, private dynamicDialogRef: DynamicDialogRef, private router: Router) {
|
||||
this.searchText = dynamicDialogConfig.data.bookTitle;
|
||||
this.bookId = this.dynamicDialogConfig.data.bookId;
|
||||
this.libraryId = this.dynamicDialogConfig.data.libraryId;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -48,7 +49,7 @@ export class BooksMetadataDialogComponent implements OnInit {
|
||||
this.bookService.setBookMetadata(metadata.googleBookId, this.bookId).subscribe({
|
||||
next: () => {
|
||||
this.dynamicDialogRef.close();
|
||||
this.router.navigate(['/book', this.bookId, 'info']);
|
||||
this.router.navigate(['/library', this.libraryId, 'book', this.bookId, 'info']);
|
||||
},
|
||||
error: (error) => {
|
||||
this.errorMessage = 'Failed to save book metadata';
|
||||
@@ -14,7 +14,7 @@
|
||||
<h4>{{ book.metadata.title }}</h4>
|
||||
<p>{{ getAuthorNames(book) }}</p>
|
||||
<p-button [rounded]="true" icon="pi pi-eye" class="view-btn" (click)="openBook(book.id)"></p-button>
|
||||
<p-button [rounded]="true" icon="pi pi-info" class="read-btn" (click)="openBookInfo(book.id)"></p-button>
|
||||
<p-button [rounded]="true" icon="pi pi-info" class="read-btn" (click)="openBookInfo(book.id, book.libraryId)"></p-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -85,7 +85,7 @@ export class DashboardScrollerComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
openBookInfo(bookId: number) {
|
||||
this.router.navigate(['/book', bookId, 'info']);
|
||||
openBookInfo(bookId: number, libraryId: number) {
|
||||
this.router.navigate(['/library', libraryId, 'book', bookId, 'info']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="layout-footer">
|
||||
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Logo" height="20" class="mr-2"/>
|
||||
by
|
||||
<span class="font-medium ml-2">PrimeNG</span>
|
||||
<span class="font-medium ml-2">Aditya C.</span>
|
||||
</div>
|
||||
@@ -2,8 +2,8 @@ import {Component, computed, OnInit} from '@angular/core';
|
||||
import {AppMenuitemComponent} from './app.menuitem.component';
|
||||
import {NgForOf, NgIf} from '@angular/common';
|
||||
import {MenuModule} from 'primeng/menu';
|
||||
import {LibraryService} from '../book/service/library.service';
|
||||
import {Library} from '../book/model/library.model';
|
||||
import {LibraryService} from '../../service/library.service';
|
||||
import {Library} from '../../model/library.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-menu',
|
||||
@@ -3,11 +3,11 @@ import { MenuItem } from 'primeng/api';
|
||||
import { LayoutService } from './service/app.layout.service';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { DialogService as PrimeDialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
|
||||
import { LibraryCreatorComponent } from '../book/component/library-creator/library-creator.component';
|
||||
import { LibraryCreatorComponent } from '../library-creator/library-creator.component';
|
||||
import { TooltipModule } from 'primeng/tooltip';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { SearchComponent } from '../book/component/search/search.component';
|
||||
import { SearchComponent } from '../search/search.component';
|
||||
import { NotificationComponent } from '../notification/notification.component'; // Import the NotificationComponent
|
||||
|
||||
@Component({
|
||||
@@ -46,22 +46,22 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('bootstrap4-light-blue', 'light')">
|
||||
<img src="assets/layout/images/themes/bootstrap4-light-blue.svg" class="w-2rem h-2rem" alt="Bootstrap Light Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/bootstrap4-light-blue.svg" class="w-2rem h-2rem" alt="Bootstrap Light Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('bootstrap4-light-purple', 'light')">
|
||||
<img src="assets/layout/images/themes/bootstrap4-light-purple.svg" class="w-2rem h-2rem" alt="Bootstrap Light Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/bootstrap4-light-purple.svg" class="w-2rem h-2rem" alt="Bootstrap Light Purple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('bootstrap4-dark-blue', 'dark')">
|
||||
<img src="assets/layout/images/themes/bootstrap4-dark-blue.svg" class="w-2rem h-2rem" alt="Bootstrap Dark Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/bootstrap4-dark-blue.svg" class="w-2rem h-2rem" alt="Bootstrap Dark Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('bootstrap4-dark-purple', 'dark')">
|
||||
<img src="assets/layout/images/themes/bootstrap4-dark-purple.svg" class="w-2rem h-2rem" alt="Bootstrap Dark Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/bootstrap4-dark-purple.svg" class="w-2rem h-2rem" alt="Bootstrap Dark Purple">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,22 +70,22 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('md-light-indigo', 'light')">
|
||||
<img src="assets/layout/images/themes/md-light-indigo.svg" class="w-2rem h-2rem" alt="Material Light Indigo">
|
||||
<img src="../../../../../assets/layout/images/themes/md-light-indigo.svg" class="w-2rem h-2rem" alt="Material Light Indigo">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('md-light-deeppurple', 'light')">
|
||||
<img src="assets/layout/images/themes/md-light-deeppurple.svg" class="w-2rem h-2rem" alt="Material Light DeepPurple">
|
||||
<img src="../../../../../assets/layout/images/themes/md-light-deeppurple.svg" class="w-2rem h-2rem" alt="Material Light DeepPurple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('md-dark-indigo', 'dark')">
|
||||
<img src="assets/layout/images/themes/md-dark-indigo.svg" class="w-2rem h-2rem" alt="Material Dark Indigo">
|
||||
<img src="../../../../../assets/layout/images/themes/md-dark-indigo.svg" class="w-2rem h-2rem" alt="Material Dark Indigo">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('md-dark-deeppurple', 'dark')">
|
||||
<img src="assets/layout/images/themes/md-dark-deeppurple.svg" class="w-2rem h-2rem" alt="Material Dark DeepPurple">
|
||||
<img src="../../../../../assets/layout/images/themes/md-dark-deeppurple.svg" class="w-2rem h-2rem" alt="Material Dark DeepPurple">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,22 +94,22 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('mdc-light-indigo', 'light')">
|
||||
<img src="assets/layout/images/themes/md-light-indigo.svg" class="w-2rem h-2rem" alt="Material Light Indigo">
|
||||
<img src="../../../../../assets/layout/images/themes/md-light-indigo.svg" class="w-2rem h-2rem" alt="Material Light Indigo">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('mdc-light-deeppurple', 'light')">
|
||||
<img src="assets/layout/images/themes/md-light-deeppurple.svg" class="w-2rem h-2rem" alt="Material Light Deep Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/md-light-deeppurple.svg" class="w-2rem h-2rem" alt="Material Light Deep Purple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('mdc-dark-indigo', 'dark')">
|
||||
<img src="assets/layout/images/themes/md-dark-indigo.svg" class="w-2rem h-2rem" alt="Material Dark Indigo">
|
||||
<img src="../../../../../assets/layout/images/themes/md-dark-indigo.svg" class="w-2rem h-2rem" alt="Material Dark Indigo">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('mdc-dark-deeppurple', 'dark')">
|
||||
<img src="assets/layout/images/themes/md-dark-deeppurple.svg" class="w-2rem h-2rem" alt="Material Dark Deep Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/md-dark-deeppurple.svg" class="w-2rem h-2rem" alt="Material Dark Deep Purple">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -118,7 +118,7 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('tailwind-light', 'light')">
|
||||
<img src="assets/layout/images/themes/tailwind-light.png" class="w-2rem h-2rem" alt="Tailwind Light">
|
||||
<img src="../../../../../assets/layout/images/themes/tailwind-light.png" class="w-2rem h-2rem" alt="Tailwind Light">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,7 +127,7 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('fluent-light', 'light')">
|
||||
<img src="assets/layout/images/themes/fluent-light.png" class="w-2rem h-2rem" alt="Fluent Light">
|
||||
<img src="../../../../../assets/layout/images/themes/fluent-light.png" class="w-2rem h-2rem" alt="Fluent Light">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -136,42 +136,42 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-light-indigo', 'light')">
|
||||
<img src="assets/layout/images/themes/lara-light-indigo.png" class="w-2rem h-2rem" alt="Lara Light Indigo">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-light-indigo.png" class="w-2rem h-2rem" alt="Lara Light Indigo">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-light-blue', 'light')">
|
||||
<img src="assets/layout/images/themes/lara-light-blue.png" class="w-2rem h-2rem" alt="Lara Light Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-light-blue.png" class="w-2rem h-2rem" alt="Lara Light Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-light-purple', 'light')">
|
||||
<img src="assets/layout/images/themes/lara-light-purple.png" class="w-2rem h-2rem" alt="Lara Light Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-light-purple.png" class="w-2rem h-2rem" alt="Lara Light Purple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-light-teal', 'light')">
|
||||
<img src="assets/layout/images/themes/lara-light-teal.png" class="w-2rem h-2rem" alt="Lara Light Teal">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-light-teal.png" class="w-2rem h-2rem" alt="Lara Light Teal">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-dark-indigo', 'dark')">
|
||||
<img src="assets/layout/images/themes/lara-dark-indigo.png" class="w-2rem h-2rem" alt="Lara Dark Indigo">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-dark-indigo.png" class="w-2rem h-2rem" alt="Lara Dark Indigo">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-dark-blue', 'dark')">
|
||||
<img src="assets/layout/images/themes/lara-dark-blue.png" class="w-2rem h-2rem" alt="Lara Dark Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-dark-blue.png" class="w-2rem h-2rem" alt="Lara Dark Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-dark-purple', 'dark')">
|
||||
<img src="assets/layout/images/themes/lara-dark-purple.png" class="w-2rem h-2rem" alt="Lara Dark Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-dark-purple.png" class="w-2rem h-2rem" alt="Lara Dark Purple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('lara-dark-teal', 'dark')">
|
||||
<img src="assets/layout/images/themes/lara-dark-teal.png" class="w-2rem h-2rem" alt="Lara Dark Teal">
|
||||
<img src="../../../../../assets/layout/images/themes/lara-dark-teal.png" class="w-2rem h-2rem" alt="Lara Dark Teal">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,62 +180,62 @@
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('saga-blue', 'light')">
|
||||
<img src="assets/layout/images/themes/saga-blue.png" class="w-2rem h-2rem" alt="Saga Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/saga-blue.png" class="w-2rem h-2rem" alt="Saga Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('saga-green', 'light')">
|
||||
<img src="assets/layout/images/themes/saga-green.png" class="w-2rem h-2rem" alt="Saga Green">
|
||||
<img src="../../../../../assets/layout/images/themes/saga-green.png" class="w-2rem h-2rem" alt="Saga Green">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('saga-orange', 'light')">
|
||||
<img src="assets/layout/images/themes/saga-orange.png" class="w-2rem h-2rem" alt="Saga Orange">
|
||||
<img src="../../../../../assets/layout/images/themes/saga-orange.png" class="w-2rem h-2rem" alt="Saga Orange">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('saga-purple', 'light')">
|
||||
<img src="assets/layout/images/themes/saga-purple.png" class="w-2rem h-2rem" alt="Saga Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/saga-purple.png" class="w-2rem h-2rem" alt="Saga Purple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('vela-blue', 'dark')">
|
||||
<img src="assets/layout/images/themes/vela-blue.png" class="w-2rem h-2rem" alt="Vela Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/vela-blue.png" class="w-2rem h-2rem" alt="Vela Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('vela-green', 'dark')">
|
||||
<img src="assets/layout/images/themes/vela-green.png" class="w-2rem h-2rem" alt="Vela Green">
|
||||
<img src="../../../../../assets/layout/images/themes/vela-green.png" class="w-2rem h-2rem" alt="Vela Green">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('vela-orange', 'dark')">
|
||||
<img src="assets/layout/images/themes/vela-orange.png" class="w-2rem h-2rem" alt="Vela Orange">
|
||||
<img src="../../../../../assets/layout/images/themes/vela-orange.png" class="w-2rem h-2rem" alt="Vela Orange">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('vela-purple', 'dark')">
|
||||
<img src="assets/layout/images/themes/vela-purple.png" class="w-2rem h-2rem" alt="Vela Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/vela-purple.png" class="w-2rem h-2rem" alt="Vela Purple">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('arya-blue', 'dark')">
|
||||
<img src="assets/layout/images/themes/arya-blue.png" class="w-2rem h-2rem" alt="Arya Blue">
|
||||
<img src="../../../../../assets/layout/images/themes/arya-blue.png" class="w-2rem h-2rem" alt="Arya Blue">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('arya-green', 'dark')">
|
||||
<img src="assets/layout/images/themes/arya-green.png" class="w-2rem h-2rem" alt="Arya Green">
|
||||
<img src="../../../../../assets/layout/images/themes/arya-green.png" class="w-2rem h-2rem" alt="Arya Green">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('arya-orange', 'dark')">
|
||||
<img src="assets/layout/images/themes/arya-orange.png" class="w-2rem h-2rem" alt="Arya Orange">
|
||||
<img src="../../../../../assets/layout/images/themes/arya-orange.png" class="w-2rem h-2rem" alt="Arya Orange">
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<button class="p-link w-2rem h-2rem" (click)="changeTheme('arya-purple', 'dark')">
|
||||
<img src="assets/layout/images/themes/arya-purple.png" class="w-2rem h-2rem" alt="Arya Purple">
|
||||
<img src="../../../../../assets/layout/images/themes/arya-purple.png" class="w-2rem h-2rem" alt="Arya Purple">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -9,7 +9,7 @@
|
||||
<h4>{{ book.metadata.title }}</h4>
|
||||
<p>{{ getAuthorNames(book) }}</p>
|
||||
<p-button [rounded]="true" icon="pi pi-eye" class="view-btn" (click)="readBook(book.id)"></p-button>
|
||||
<p-button [rounded]="true" icon="pi pi-info" class="read-btn" (click)="openBookInfo(book.id)"></p-button>
|
||||
<p-button [rounded]="true" icon="pi pi-info" class="read-btn" (click)="openBookInfo(book.id, book.libraryId)"></p-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Component, OnInit, NgZone } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BookProgressService } from '../../service/book-progress-service';
|
||||
import { BookUpdateEvent } from '../../model/book-update-event.model';
|
||||
import { BookService } from '../../service/book.service';
|
||||
import { Book } from '../../model/book.model';
|
||||
import {Book, BookUpdateEvent} from '../../model/book.model';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import {InfiniteScrollDirective} from 'ngx-infinite-scroll';
|
||||
import {Button} from 'primeng/button';
|
||||
@@ -105,7 +104,7 @@ export class LibraryBrowserComponent implements OnInit {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
openBookInfo(bookId: number) {
|
||||
this.router.navigate(['/book', bookId, 'info']);
|
||||
openBookInfo(bookId: number, libraryId: number) {
|
||||
this.router.navigate(['/library', libraryId, 'book', bookId, 'info']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Component, OnInit, OnDestroy} from '@angular/core';
|
||||
import {BookProgressService} from '../book/service/book-progress-service';
|
||||
import {BookUpdateEvent} from '../book/model/book-update-event.model';
|
||||
import {BookProgressService} from '../../service/book-progress-service';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {NgClass} from '@angular/common';
|
||||
import {BookUpdateEvent} from '../../model/book.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-notification',
|
||||
@@ -12,7 +12,7 @@
|
||||
<button *ngIf="searchQuery" pButton icon="pi pi-times" (click)="clearSearch()" class="clear-btn" type="button" aria-label="Clear Search"></button>
|
||||
</span>
|
||||
|
||||
<div class="search-dropdown layout-menu" [class.show]="(books.length > 0 || (searchQuery?.length ?? 0) > 0)">
|
||||
<div class="search-dropdown layout-menu" [class.show]="(books.length > 0)">
|
||||
<ng-container *ngIf="books.length > 0; else noResults">
|
||||
<div class="search-dropdown-item" *ngFor="let book of books" (click)="onBookClick(book)">
|
||||
<img [src]="getBookCoverUrl(book.id)" alt="Book Cover" class="search-book-cover" />
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface Author {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export interface BookSetting {
|
||||
pageNumber: number;
|
||||
zoom: number | string;
|
||||
sidebar_visible: boolean;
|
||||
spread: 'off' | 'even' | 'odd';
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import {BookMetadata} from './book.model';
|
||||
|
||||
export interface BookUpdateEvent {
|
||||
libraryId: number;
|
||||
filename: string;
|
||||
book: {
|
||||
id: number;
|
||||
libraryId: number;
|
||||
fileName: string;
|
||||
addedOn: string;
|
||||
metadata: BookMetadata;
|
||||
};
|
||||
parsingStatus: string;
|
||||
}
|
||||
@@ -17,6 +17,7 @@ export interface PaginatedBooksResponse {
|
||||
export interface BookMetadata {
|
||||
thumbnail: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
authors: Author[];
|
||||
categories: Category[];
|
||||
publisher: string;
|
||||
@@ -38,4 +39,29 @@ export interface Category {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface BookWithNeighborsDTO {
|
||||
currentBook: Book;
|
||||
previousBookId: number | null;
|
||||
nextBookId: number | null;
|
||||
}
|
||||
|
||||
export interface BookUpdateEvent {
|
||||
libraryId: number;
|
||||
filename: string;
|
||||
book: {
|
||||
id: number;
|
||||
libraryId: number;
|
||||
fileName: string;
|
||||
addedOn: string;
|
||||
metadata: BookMetadata;
|
||||
};
|
||||
parsingStatus: string;
|
||||
}
|
||||
|
||||
export interface BookSetting {
|
||||
pageNumber: number;
|
||||
zoom: number | string;
|
||||
sidebar_visible: boolean;
|
||||
spread: 'off' | 'even' | 'odd';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {BookUpdateEvent} from '../model/book-update-event.model';
|
||||
import {BookUpdateEvent} from '../model/book.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {Observable} from 'rxjs';
|
||||
import {Book, BookMetadata, PaginatedBooksResponse} from '../model/book.model';
|
||||
import {Book, BookMetadata, BookSetting, BookWithNeighborsDTO, PaginatedBooksResponse} from '../model/book.model';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {BookSetting} from '../model/book-settings.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -19,6 +18,10 @@ export class BookService {
|
||||
return this.http.get<Book>(`${this.bookUrl}/${bookId}`);
|
||||
}
|
||||
|
||||
getBookWithNeighbours(libraryId: number, bookId: number): Observable<BookWithNeighborsDTO> {
|
||||
return this.http.get<BookWithNeighborsDTO>(`${this.libraryUrl}/${libraryId}/book/${bookId}/withNeighbors`);
|
||||
}
|
||||
|
||||
loadBooks(libraryId: number, page: number): Observable<PaginatedBooksResponse> {
|
||||
return this.http.get<PaginatedBooksResponse>(
|
||||
`${this.libraryUrl}/${libraryId}/book?page=${page}&size=${this.pageSize}`
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user