Removed some todos and cleaned up some of the code.
This commit is contained in:
parent
9128e41bcb
commit
09dbdaa41d
18 changed files with 65 additions and 267 deletions
|
|
@ -51,23 +51,11 @@ public class Program
|
||||||
|
|
||||||
|
|
||||||
// Check if this is the first time running and if so, rename appsettings-init.json to appsettings.json
|
// Check if this is the first time running and if so, rename appsettings-init.json to appsettings.json
|
||||||
var firstRunConfigFilePath = Path.Join(Directory.GetCurrentDirectory(), "config/appsettings-init.json");
|
HandleFirstRunConfiguration();
|
||||||
if (File.Exists(firstRunConfigFilePath) &&
|
|
||||||
!File.Exists(Path.Join(Directory.GetCurrentDirectory(), "config/appsettings.json")))
|
|
||||||
{
|
|
||||||
File.Move(firstRunConfigFilePath, Path.Join(Directory.GetCurrentDirectory(), "config/appsettings.json"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Before anything, check if JWT has been generated properly or if user still has default
|
// Before anything, check if JWT has been generated properly or if user still has default
|
||||||
if (!Configuration.CheckIfJwtTokenSet() &&
|
EnsureJwtTokenKey();
|
||||||
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != Environments.Development)
|
|
||||||
{
|
|
||||||
Log.Logger.Information("Generating JWT TokenKey for encrypting user sessions...");
|
|
||||||
var rBytes = new byte[256];
|
|
||||||
RandomNumberGenerator.Create().GetBytes(rBytes);
|
|
||||||
Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -81,6 +69,7 @@ public class Program
|
||||||
{
|
{
|
||||||
var logger = services.GetRequiredService<ILogger<Program>>();
|
var logger = services.GetRequiredService<ILogger<Program>>();
|
||||||
var context = services.GetRequiredService<DataContext>();
|
var context = services.GetRequiredService<DataContext>();
|
||||||
|
|
||||||
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
|
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
|
||||||
var isDbCreated = await context.Database.CanConnectAsync();
|
var isDbCreated = await context.Database.CanConnectAsync();
|
||||||
if (isDbCreated && pendingMigrations.Any())
|
if (isDbCreated && pendingMigrations.Any())
|
||||||
|
|
@ -168,6 +157,26 @@ public class Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EnsureJwtTokenKey()
|
||||||
|
{
|
||||||
|
if (Configuration.CheckIfJwtTokenSet() || Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development) return;
|
||||||
|
|
||||||
|
Log.Logger.Information("Generating JWT TokenKey for encrypting user sessions...");
|
||||||
|
var rBytes = new byte[256];
|
||||||
|
RandomNumberGenerator.Create().GetBytes(rBytes);
|
||||||
|
Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleFirstRunConfiguration()
|
||||||
|
{
|
||||||
|
var firstRunConfigFilePath = Path.Join(Directory.GetCurrentDirectory(), "config/appsettings-init.json");
|
||||||
|
if (File.Exists(firstRunConfigFilePath) &&
|
||||||
|
!File.Exists(Path.Join(Directory.GetCurrentDirectory(), "config/appsettings.json")))
|
||||||
|
{
|
||||||
|
File.Move(firstRunConfigFilePath, Path.Join(Directory.GetCurrentDirectory(), "config/appsettings.json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task<string> GetMigrationDirectory(DataContext context, IDirectoryService directoryService)
|
private static async Task<string> GetMigrationDirectory(DataContext context, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
string? currentVersion = null;
|
string? currentVersion = null;
|
||||||
|
|
|
||||||
|
|
@ -473,8 +473,7 @@ export class ActionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteMultipleVolumes(volumes: Array<Volume>, callback?: BooleanActionCallback) {
|
async deleteMultipleVolumes(volumes: Array<Volume>, callback?: BooleanActionCallback) {
|
||||||
// TODO: Change translation key back to "toasts.confirm-delete-multiple-volumes"
|
if (!await this.confirmService.confirm(translate('toasts.confirm-delete-multiple-volumes', {count: volumes.length}))) return;
|
||||||
if (!await this.confirmService.confirm(translate('toasts.confirm-delete-multiple-chapters', {count: volumes.length}))) return;
|
|
||||||
|
|
||||||
this.volumeService.deleteMultipleVolumes(volumes.map(v => v.id)).subscribe((success) => {
|
this.volumeService.deleteMultipleVolumes(volumes.map(v => v.id)).subscribe((success) => {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||||
import {Inject, inject, Injectable} from '@angular/core';
|
import {Inject, inject, Injectable} from '@angular/core';
|
||||||
import {environment} from 'src/environments/environment';
|
import {environment} from 'src/environments/environment';
|
||||||
import {UserReadStatistics} from '../statistics/_models/user-read-statistics';
|
import {UserReadStatistics} from '../statistics/_models/user-read-statistics';
|
||||||
import {PublicationStatusPipe} from '../_pipes/publication-status.pipe';
|
import {PublicationStatusPipe} from '../_pipes/publication-status.pipe';
|
||||||
import {asyncScheduler, finalize, map, tap} from 'rxjs';
|
import {asyncScheduler, map} from 'rxjs';
|
||||||
import {MangaFormatPipe} from '../_pipes/manga-format.pipe';
|
import {MangaFormatPipe} from '../_pipes/manga-format.pipe';
|
||||||
import {FileExtensionBreakdown} from '../statistics/_models/file-breakdown';
|
import {FileExtensionBreakdown} from '../statistics/_models/file-breakdown';
|
||||||
import {TopUserRead} from '../statistics/_models/top-reads';
|
import {TopUserRead} from '../statistics/_models/top-reads';
|
||||||
|
|
@ -14,7 +14,6 @@ import { PublicationStatus } from '../_models/metadata/publication-status';
|
||||||
import {MangaFormat} from '../_models/manga-format';
|
import {MangaFormat} from '../_models/manga-format';
|
||||||
import {TextResonse} from '../_types/text-response';
|
import {TextResonse} from '../_types/text-response';
|
||||||
import {TranslocoService} from "@jsverse/transloco";
|
import {TranslocoService} from "@jsverse/transloco";
|
||||||
import {KavitaPlusMetadataBreakdown} from "../statistics/_models/kavitaplus-metadata-breakdown";
|
|
||||||
import {throttleTime} from "rxjs/operators";
|
import {throttleTime} from "rxjs/operators";
|
||||||
import {DEBOUNCE_TIME} from "../shared/_services/download.service";
|
import {DEBOUNCE_TIME} from "../shared/_services/download.service";
|
||||||
import {download} from "../shared/_models/download";
|
import {download} from "../shared/_models/download";
|
||||||
|
|
@ -44,11 +43,14 @@ export class StatisticsService {
|
||||||
constructor(private httpClient: HttpClient, @Inject(SAVER) private save: Saver) { }
|
constructor(private httpClient: HttpClient, @Inject(SAVER) private save: Saver) { }
|
||||||
|
|
||||||
getUserStatistics(userId: number, libraryIds: Array<number> = []) {
|
getUserStatistics(userId: number, libraryIds: Array<number> = []) {
|
||||||
// TODO: Convert to httpParams object
|
const url = `${this.baseUrl}stats/user/${userId}/read`;
|
||||||
let url = 'stats/user/' + userId + '/read';
|
|
||||||
if (libraryIds.length > 0) url += '?libraryIds=' + libraryIds.join(',');
|
|
||||||
|
|
||||||
return this.httpClient.get<UserReadStatistics>(this.baseUrl + url);
|
let params = new HttpParams();
|
||||||
|
if (libraryIds.length > 0) {
|
||||||
|
params = params.set('libraryIds', libraryIds.join(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.httpClient.get<UserReadStatistics>(url, { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
getServerStatistics() {
|
getServerStatistics() {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
@if (logs$ | async; as items) {
|
|
||||||
<virtual-scroller #scroll [items]="items" [bufferAmount]="1">
|
|
||||||
<div class="grid row g-0" #container>
|
|
||||||
@for (item of scroll.viewPortItems; track item.timestamp) {
|
|
||||||
<div class="card col-auto mt-2 mb-2">
|
|
||||||
{{item.timestamp | date}} [{{item.level}}] {{item.message}}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</virtual-scroller>
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
||||||
import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
|
|
||||||
import { BehaviorSubject, take } from 'rxjs';
|
|
||||||
import { AccountService } from 'src/app/_services/account.service';
|
|
||||||
import { environment } from 'src/environments/environment';
|
|
||||||
import { VirtualScrollerModule } from '@iharbeck/ngx-virtual-scroller';
|
|
||||||
import { AsyncPipe, DatePipe } from '@angular/common';
|
|
||||||
|
|
||||||
interface LogMessage {
|
|
||||||
timestamp: string;
|
|
||||||
level: 'Information' | 'Debug' | 'Warning' | 'Error';
|
|
||||||
message: string;
|
|
||||||
exception: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-manage-logs',
|
|
||||||
templateUrl: './manage-logs.component.html',
|
|
||||||
styleUrls: ['./manage-logs.component.scss'],
|
|
||||||
standalone: true,
|
|
||||||
imports: [VirtualScrollerModule, AsyncPipe, DatePipe]
|
|
||||||
})
|
|
||||||
export class ManageLogsComponent implements OnInit, OnDestroy {
|
|
||||||
|
|
||||||
hubUrl = environment.hubUrl;
|
|
||||||
private hubConnection!: HubConnection;
|
|
||||||
|
|
||||||
logsSource = new BehaviorSubject<LogMessage[]>([]);
|
|
||||||
public logs$ = this.logsSource.asObservable();
|
|
||||||
|
|
||||||
constructor(private accountService: AccountService) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
// TODO: Come back and implement this one day
|
|
||||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
|
||||||
if (user) {
|
|
||||||
this.hubConnection = new HubConnectionBuilder()
|
|
||||||
.withUrl(this.hubUrl + 'logs', {
|
|
||||||
accessTokenFactory: () => user.token
|
|
||||||
})
|
|
||||||
.withAutomaticReconnect()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
console.log('Starting log connection');
|
|
||||||
|
|
||||||
this.hubConnection
|
|
||||||
.start()
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
|
|
||||||
this.hubConnection.on('SendLogAsObject', resp => {
|
|
||||||
const payload = resp.arguments[0] as LogMessage;
|
|
||||||
const logMessage = {timestamp: payload.timestamp, level: payload.level, message: payload.message, exception: payload.exception};
|
|
||||||
// NOTE: It might be better to just have a queue to show this
|
|
||||||
const values = this.logsSource.getValue();
|
|
||||||
values.push(logMessage);
|
|
||||||
this.logsSource.next(values);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
// unsubscribe from signalr connection
|
|
||||||
if (this.hubConnection) {
|
|
||||||
this.hubConnection.stop().catch(err => console.error(err));
|
|
||||||
console.log('Stopping log connection');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -10,6 +10,4 @@ import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||||
export class UpdateSectionComponent {
|
export class UpdateSectionComponent {
|
||||||
@Input({required: true}) items: Array<string> = [];
|
@Input({required: true}) items: Array<string> = [];
|
||||||
@Input({required: true}) title: string = '';
|
@Input({required: true}) title: string = '';
|
||||||
|
|
||||||
// TODO: Implement a read-more-list so that we by default show a configurable number
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,10 +344,6 @@ export class CardItemComponent implements OnInit {
|
||||||
this.clicked.emit(this.title);
|
this.clicked.emit(this.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
preventClick(event: any) {
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
performAction(action: ActionItem<any>) {
|
||||||
if (action.action == Action.Download) {
|
if (action.action == Action.Download) {
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@ import {
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
DestroyRef,
|
DestroyRef,
|
||||||
EventEmitter, HostListener,
|
EventEmitter,
|
||||||
|
HostListener,
|
||||||
inject,
|
inject,
|
||||||
Input, OnInit,
|
Input,
|
||||||
|
OnInit,
|
||||||
Output
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {ImageService} from "../../_services/image.service";
|
import {ImageService} from "../../_services/image.service";
|
||||||
|
|
@ -14,7 +16,7 @@ import {DownloadEvent, DownloadService} from "../../shared/_services/download.se
|
||||||
import {EVENTS, MessageHubService} from "../../_services/message-hub.service";
|
import {EVENTS, MessageHubService} from "../../_services/message-hub.service";
|
||||||
import {AccountService} from "../../_services/account.service";
|
import {AccountService} from "../../_services/account.service";
|
||||||
import {ScrollService} from "../../_services/scroll.service";
|
import {ScrollService} from "../../_services/scroll.service";
|
||||||
import {Action, ActionFactoryService, ActionItem} from "../../_services/action-factory.service";
|
import {ActionItem} from "../../_services/action-factory.service";
|
||||||
import {Chapter} from "../../_models/chapter";
|
import {Chapter} from "../../_models/chapter";
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from "rxjs";
|
||||||
import {User} from "../../_models/user";
|
import {User} from "../../_models/user";
|
||||||
|
|
@ -28,13 +30,10 @@ import {EntityTitleComponent} from "../entity-title/entity-title.component";
|
||||||
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";
|
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";
|
||||||
import {Router, RouterLink} from "@angular/router";
|
import {Router, RouterLink} from "@angular/router";
|
||||||
import {TranslocoDirective} from "@jsverse/transloco";
|
import {TranslocoDirective} from "@jsverse/transloco";
|
||||||
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
|
||||||
import {filter, map} from "rxjs/operators";
|
import {filter, map} from "rxjs/operators";
|
||||||
import {UserProgressUpdateEvent} from "../../_models/events/user-progress-update-event";
|
import {UserProgressUpdateEvent} from "../../_models/events/user-progress-update-event";
|
||||||
import {ReaderService} from "../../_services/reader.service";
|
import {ReaderService} from "../../_services/reader.service";
|
||||||
import {LibraryType} from "../../_models/library/library";
|
import {LibraryType} from "../../_models/library/library";
|
||||||
import {Device} from "../../_models/device/device";
|
|
||||||
import {ActionService} from "../../_services/action.service";
|
|
||||||
import {MangaFormat} from "../../_models/manga-format";
|
import {MangaFormat} from "../../_models/manga-format";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
@ -60,15 +59,16 @@ export class ChapterCardComponent implements OnInit {
|
||||||
public readonly imageService = inject(ImageService);
|
public readonly imageService = inject(ImageService);
|
||||||
public readonly bulkSelectionService = inject(BulkSelectionService);
|
public readonly bulkSelectionService = inject(BulkSelectionService);
|
||||||
private readonly downloadService = inject(DownloadService);
|
private readonly downloadService = inject(DownloadService);
|
||||||
private readonly actionService = inject(ActionService);
|
|
||||||
private readonly messageHub = inject(MessageHubService);
|
private readonly messageHub = inject(MessageHubService);
|
||||||
private readonly accountService = inject(AccountService);
|
private readonly accountService = inject(AccountService);
|
||||||
private readonly scrollService = inject(ScrollService);
|
private readonly scrollService = inject(ScrollService);
|
||||||
private readonly cdRef = inject(ChangeDetectorRef);
|
private readonly cdRef = inject(ChangeDetectorRef);
|
||||||
private readonly actionFactoryService = inject(ActionFactoryService);
|
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
private readonly readerService = inject(ReaderService);
|
private readonly readerService = inject(ReaderService);
|
||||||
|
|
||||||
|
protected readonly LibraryType = LibraryType;
|
||||||
|
protected readonly MangaFormat = MangaFormat;
|
||||||
|
|
||||||
@Input({required: true}) libraryId: number = 0;
|
@Input({required: true}) libraryId: number = 0;
|
||||||
@Input({required: true}) seriesId: number = 0;
|
@Input({required: true}) seriesId: number = 0;
|
||||||
@Input({required: true}) chapter!: Chapter;
|
@Input({required: true}) chapter!: Chapter;
|
||||||
|
|
@ -143,8 +143,6 @@ export class ChapterCardComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.filterSendTo();
|
|
||||||
|
|
||||||
this.accountService.currentUser$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(user => {
|
this.accountService.currentUser$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(user => {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
});
|
});
|
||||||
|
|
@ -172,30 +170,6 @@ export class ChapterCardComponent implements OnInit {
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
filterSendTo() {
|
|
||||||
if (!this.actions || this.actions.length === 0) return;
|
|
||||||
|
|
||||||
this.actions = this.actionFactoryService.filterSendToAction(this.actions, this.chapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
|
||||||
if (action.action == Action.Download) {
|
|
||||||
this.downloadService.download('chapter', this.chapter);
|
|
||||||
return; // Don't propagate the download from a card
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.action == Action.SendTo) {
|
|
||||||
const device = (action._extra!.data as Device);
|
|
||||||
this.actionService.sendToDevice([this.chapter.id], device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.chapter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick(event: any) {
|
handleClick(event: any) {
|
||||||
if (this.bulkSelectionService.hasSelections()) {
|
if (this.bulkSelectionService.hasSelections()) {
|
||||||
this.handleSelection(event);
|
this.handleSelection(event);
|
||||||
|
|
@ -209,8 +183,4 @@ export class ChapterCardComponent implements OnInit {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.readerService.readChapter(this.libraryId, this.seriesId, this.chapter, false);
|
this.readerService.readChapter(this.libraryId, this.seriesId, this.chapter, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected readonly LibraryType = LibraryType;
|
|
||||||
protected readonly MangaFormat = MangaFormat;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component, ContentChild,
|
Component,
|
||||||
DestroyRef, EventEmitter,
|
ContentChild,
|
||||||
|
DestroyRef,
|
||||||
|
EventEmitter,
|
||||||
HostListener,
|
HostListener,
|
||||||
inject,
|
inject,
|
||||||
Input, Output, TemplateRef
|
Input,
|
||||||
|
Output,
|
||||||
|
TemplateRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {Action, ActionFactoryService, ActionItem} from "../../_services/action-factory.service";
|
import {ActionItem} from "../../_services/action-factory.service";
|
||||||
import {ImageService} from "../../_services/image.service";
|
import {ImageService} from "../../_services/image.service";
|
||||||
import {BulkSelectionService} from "../bulk-selection.service";
|
import {BulkSelectionService} from "../bulk-selection.service";
|
||||||
import {LibraryService} from "../../_services/library.service";
|
|
||||||
import {DownloadService} from "../../shared/_services/download.service";
|
|
||||||
import {UtilityService} from "../../shared/_services/utility.service";
|
|
||||||
import {MessageHubService} from "../../_services/message-hub.service";
|
import {MessageHubService} from "../../_services/message-hub.service";
|
||||||
import {AccountService} from "../../_services/account.service";
|
|
||||||
import {ScrollService} from "../../_services/scroll.service";
|
import {ScrollService} from "../../_services/scroll.service";
|
||||||
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
|
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
|
||||||
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";
|
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";
|
||||||
|
|
@ -139,11 +139,6 @@ export class PersonCardComponent {
|
||||||
this.clicked.emit(this.title);
|
this.clicked.emit(this.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSelection(event?: any) {
|
handleSelection(event?: any) {
|
||||||
if (event) {
|
if (event) {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import {DownloadEvent, DownloadService} from "../../shared/_services/download.se
|
||||||
import {EVENTS, MessageHubService} from "../../_services/message-hub.service";
|
import {EVENTS, MessageHubService} from "../../_services/message-hub.service";
|
||||||
import {AccountService} from "../../_services/account.service";
|
import {AccountService} from "../../_services/account.service";
|
||||||
import {ScrollService} from "../../_services/scroll.service";
|
import {ScrollService} from "../../_services/scroll.service";
|
||||||
import {Action, ActionItem} from "../../_services/action-factory.service";
|
import {ActionItem} from "../../_services/action-factory.service";
|
||||||
import {ReaderService} from "../../_services/reader.service";
|
import {ReaderService} from "../../_services/reader.service";
|
||||||
import {Observable} from "rxjs";
|
import {Observable} from "rxjs";
|
||||||
import {User} from "../../_models/user";
|
import {User} from "../../_models/user";
|
||||||
|
|
@ -33,7 +33,6 @@ import {UserProgressUpdateEvent} from "../../_models/events/user-progress-update
|
||||||
import {Volume} from "../../_models/volume";
|
import {Volume} from "../../_models/volume";
|
||||||
import {UtilityService} from "../../shared/_services/utility.service";
|
import {UtilityService} from "../../shared/_services/utility.service";
|
||||||
import {LibraryType} from "../../_models/library/library";
|
import {LibraryType} from "../../_models/library/library";
|
||||||
import {Device} from "../../_models/device/device";
|
|
||||||
import {ActionService} from "../../_services/action.service";
|
import {ActionService} from "../../_services/action.service";
|
||||||
import {FormsModule} from "@angular/forms";
|
import {FormsModule} from "@angular/forms";
|
||||||
|
|
||||||
|
|
@ -143,8 +142,6 @@ export class VolumeCardComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.filterSendTo();
|
|
||||||
|
|
||||||
this.accountService.currentUser$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(user => {
|
this.accountService.currentUser$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(user => {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
});
|
});
|
||||||
|
|
@ -180,30 +177,6 @@ export class VolumeCardComponent implements OnInit {
|
||||||
this.cdRef.detectChanges();
|
this.cdRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
filterSendTo() {
|
|
||||||
if (!this.actions || this.actions.length === 0) return;
|
|
||||||
// TODO: See if we can handle send to for volumes
|
|
||||||
//this.actions = this.actionFactoryService.filterSendToAction(this.actions, this.volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
performAction(action: ActionItem<Volume>) {
|
|
||||||
if (action.action == Action.Download) {
|
|
||||||
this.downloadService.download('volume', this.volume);
|
|
||||||
return; // Don't propagate the download from a card
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.action == Action.SendTo) {
|
|
||||||
const device = (action._extra!.data as Device);
|
|
||||||
this.actionService.sendToDevice(this.volume.chapters.map(c => c.id), device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick(event: any) {
|
handleClick(event: any) {
|
||||||
if (this.bulkSelectionService.hasSelections()) {
|
if (this.bulkSelectionService.hasSelections()) {
|
||||||
this.handleSelection(event);
|
this.handleSelection(event);
|
||||||
|
|
|
||||||
|
|
@ -339,10 +339,6 @@ export class ChapterDetailComponent implements OnInit {
|
||||||
this.location.replaceState(newUrl)
|
this.location.replaceState(newUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
openPerson(field: FilterField, value: number) {
|
|
||||||
this.filterUtilityService.applyFilter(['all-series'], field, FilterComparison.Equal, `${value}`).subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadChapter() {
|
downloadChapter() {
|
||||||
if (this.downloadInProgress) return;
|
if (this.downloadInProgress) return;
|
||||||
this.downloadService.download('chapter', this.chapter!, (d) => {
|
this.downloadService.download('chapter', this.chapter!, (d) => {
|
||||||
|
|
@ -360,11 +356,6 @@ export class ChapterDetailComponent implements OnInit {
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
performAction(action: ActionItem<Chapter>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.chapter!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChapterActionCallback(action: ActionItem<Chapter>, chapter: Chapter) {
|
handleChapterActionCallback(action: ActionItem<Chapter>, chapter: Chapter) {
|
||||||
switch (action.action) {
|
switch (action.action) {
|
||||||
|
|
|
||||||
|
|
@ -305,12 +305,6 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.collectionTag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openEditCollectionTagModal(collectionTag: UserCollection) {
|
openEditCollectionTagModal(collectionTag: UserCollection) {
|
||||||
const modalRef = this.modalService.open(EditCollectionTagsComponent, DefaultModalOptions);
|
const modalRef = this.modalService.open(EditCollectionTagsComponent, DefaultModalOptions);
|
||||||
modalRef.componentInstance.tag = this.collectionTag;
|
modalRef.componentInstance.tag = this.collectionTag;
|
||||||
|
|
@ -321,7 +315,6 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
||||||
}
|
}
|
||||||
|
|
||||||
openSyncDetailDrawer() {
|
openSyncDetailDrawer() {
|
||||||
|
|
||||||
const ref = this.offcanvasService.open(SmartCollectionDrawerComponent, {position: 'end', panelClass: ''});
|
const ref = this.offcanvasService.open(SmartCollectionDrawerComponent, {position: 'end', panelClass: ''});
|
||||||
ref.componentInstance.collection = this.collectionTag;
|
ref.componentInstance.collection = this.collectionTag;
|
||||||
ref.componentInstance.series = this.series;
|
ref.componentInstance.series = this.series;
|
||||||
|
|
|
||||||
|
|
@ -297,8 +297,6 @@ export class LibraryDetailComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
performAction(action: ActionItem<any>) {
|
||||||
if (typeof action.callback === 'function') {
|
if (typeof action.callback === 'function') {
|
||||||
action.callback(action, undefined);
|
action.callback(action, undefined);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import {
|
||||||
SideNavCompanionBarComponent
|
SideNavCompanionBarComponent
|
||||||
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
|
} from "../sidenav/_components/side-nav-companion-bar/side-nav-companion-bar.component";
|
||||||
import {ReadMoreComponent} from "../shared/read-more/read-more.component";
|
import {ReadMoreComponent} from "../shared/read-more/read-more.component";
|
||||||
import {TagBadgeCursor} from "../shared/tag-badge/tag-badge.component";
|
|
||||||
import {PersonRolePipe} from "../_pipes/person-role.pipe";
|
import {PersonRolePipe} from "../_pipes/person-role.pipe";
|
||||||
import {CarouselReelComponent} from "../carousel/_components/carousel-reel/carousel-reel.component";
|
import {CarouselReelComponent} from "../carousel/_components/carousel-reel/carousel-reel.component";
|
||||||
import {FilterComparison} from "../_models/metadata/v2/filter-comparison";
|
import {FilterComparison} from "../_models/metadata/v2/filter-comparison";
|
||||||
|
|
@ -89,7 +88,7 @@ export class PersonDetailComponent implements OnInit {
|
||||||
private readonly toastr = inject(ToastrService);
|
private readonly toastr = inject(ToastrService);
|
||||||
private readonly messageHubService = inject(MessageHubService)
|
private readonly messageHubService = inject(MessageHubService)
|
||||||
|
|
||||||
protected readonly TagBadgeCursor = TagBadgeCursor;
|
protected readonly FilterField = FilterField;
|
||||||
|
|
||||||
@ViewChild('scrollingBlock') scrollingBlock: ElementRef<HTMLDivElement> | undefined;
|
@ViewChild('scrollingBlock') scrollingBlock: ElementRef<HTMLDivElement> | undefined;
|
||||||
@ViewChild('companionBar') companionBar: ElementRef<HTMLDivElement> | undefined;
|
@ViewChild('companionBar') companionBar: ElementRef<HTMLDivElement> | undefined;
|
||||||
|
|
@ -278,11 +277,4 @@ export class PersonDetailComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.person);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected readonly FilterField = FilterField;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -273,11 +273,6 @@ export class ReadingListDetailComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.readingList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readChapter(item: ReadingListItem) {
|
readChapter(item: ReadingListItem) {
|
||||||
if (!this.readingList) return;
|
if (!this.readingList) return;
|
||||||
|
|
@ -387,12 +382,6 @@ export class ReadingListDetailComponent implements OnInit {
|
||||||
{queryParams: {readingListId: this.readingList.id, incognitoMode: incognitoMode}});
|
{queryParams: {readingListId: this.readingList.id, incognitoMode: incognitoMode}});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccessibilityMode() {
|
|
||||||
this.accessibilityMode = !this.accessibilityMode;
|
|
||||||
this.cdRef.markForCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toggleReorder() {
|
toggleReorder() {
|
||||||
this.formGroup.get('edit')?.setValue(!this.formGroup.get('edit')!.value);
|
this.formGroup.get('edit')?.setValue(!this.formGroup.get('edit')!.value);
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,6 @@ import {ReaderService} from 'src/app/_services/reader.service';
|
||||||
import {ReadingListService} from 'src/app/_services/reading-list.service';
|
import {ReadingListService} from 'src/app/_services/reading-list.service';
|
||||||
import {ScrollService} from 'src/app/_services/scroll.service';
|
import {ScrollService} from 'src/app/_services/scroll.service';
|
||||||
import {SeriesService} from 'src/app/_services/series.service';
|
import {SeriesService} from 'src/app/_services/series.service';
|
||||||
import {
|
|
||||||
ReviewModalCloseAction,
|
|
||||||
ReviewModalCloseEvent,
|
|
||||||
ReviewModalComponent
|
|
||||||
} from '../../../_single-module/review-modal/review-modal.component';
|
|
||||||
import {PageLayoutMode} from 'src/app/_models/page-layout-mode';
|
import {PageLayoutMode} from 'src/app/_models/page-layout-mode';
|
||||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||||
import {UserReview} from "../../../_single-module/review-card/user-review";
|
import {UserReview} from "../../../_single-module/review-card/user-review";
|
||||||
|
|
@ -73,8 +68,6 @@ import {ExternalSeriesCardComponent} from '../../../cards/external-series-card/e
|
||||||
import {SeriesCardComponent} from '../../../cards/series-card/series-card.component';
|
import {SeriesCardComponent} from '../../../cards/series-card/series-card.component';
|
||||||
import {VirtualScrollerModule} from '@iharbeck/ngx-virtual-scroller';
|
import {VirtualScrollerModule} from '@iharbeck/ngx-virtual-scroller';
|
||||||
import {BulkOperationsComponent} from '../../../cards/bulk-operations/bulk-operations.component';
|
import {BulkOperationsComponent} from '../../../cards/bulk-operations/bulk-operations.component';
|
||||||
import {ReviewCardComponent} from '../../../_single-module/review-card/review-card.component';
|
|
||||||
import {CarouselReelComponent} from '../../../carousel/_components/carousel-reel/carousel-reel.component';
|
|
||||||
import {translate, TranslocoDirective, TranslocoService} from "@jsverse/transloco";
|
import {translate, TranslocoDirective, TranslocoService} from "@jsverse/transloco";
|
||||||
import {CardActionablesComponent} from "../../../_single-module/card-actionables/card-actionables.component";
|
import {CardActionablesComponent} from "../../../_single-module/card-actionables/card-actionables.component";
|
||||||
import {PublicationStatus} from "../../../_models/metadata/publication-status";
|
import {PublicationStatus} from "../../../_models/metadata/publication-status";
|
||||||
|
|
@ -1138,13 +1131,6 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
performAction(action: ActionItem<any>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.series);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadSeries() {
|
downloadSeries() {
|
||||||
this.downloadService.download('series', this.series, (d) => {
|
this.downloadService.download('series', this.series, (d) => {
|
||||||
this.downloadInProgress = !!d;
|
this.downloadInProgress = !!d;
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ export class VolumeDetailComponent implements OnInit {
|
||||||
protected readonly TabID = TabID;
|
protected readonly TabID = TabID;
|
||||||
protected readonly FilterField = FilterField;
|
protected readonly FilterField = FilterField;
|
||||||
protected readonly Breakpoint = Breakpoint;
|
protected readonly Breakpoint = Breakpoint;
|
||||||
|
protected readonly encodeURIComponent = encodeURIComponent;
|
||||||
|
|
||||||
@ViewChild('scrollingBlock') scrollingBlock: ElementRef<HTMLDivElement> | undefined;
|
@ViewChild('scrollingBlock') scrollingBlock: ElementRef<HTMLDivElement> | undefined;
|
||||||
@ViewChild('companionBar') companionBar: ElementRef<HTMLDivElement> | undefined;
|
@ViewChild('companionBar') companionBar: ElementRef<HTMLDivElement> | undefined;
|
||||||
|
|
@ -571,16 +572,6 @@ export class VolumeDetailComponent implements OnInit {
|
||||||
this.location.replaceState(newUrl)
|
this.location.replaceState(newUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
openPerson(field: FilterField, value: number) {
|
|
||||||
this.filterUtilityService.applyFilter(['all-series'], field, FilterComparison.Equal, `${value}`).subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
performAction(action: ActionItem<Volume>) {
|
|
||||||
if (typeof action.callback === 'function') {
|
|
||||||
action.callback(action, this.volume!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleChapterActionCallback(action: ActionItem<Chapter>, chapter: Chapter) {
|
async handleChapterActionCallback(action: ActionItem<Chapter>, chapter: Chapter) {
|
||||||
switch (action.action) {
|
switch (action.action) {
|
||||||
case(Action.MarkAsRead):
|
case(Action.MarkAsRead):
|
||||||
|
|
@ -699,6 +690,4 @@ export class VolumeDetailComponent implements OnInit {
|
||||||
this.currentlyReadingChapter = undefined;
|
this.currentlyReadingChapter = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly encodeURIComponent = encodeURIComponent;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue