Width Override Fixes + Swagger (again) (#3034)

This commit is contained in:
Joe Milazzo 2024-07-01 15:02:17 -05:00 committed by GitHub
parent 2326c9f437
commit 8cc1edc38d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 118 additions and 2161 deletions

View File

@ -489,8 +489,6 @@ public class ScannerService : IScannerService
// We don't need to send SignalR event as this is a background job that user doesn't need insight into
_logger.LogInformation("[ScannerService] Scan library invoked via nightly scan job but a task is already running for {LibraryName}. Rescheduling for 4 hours", lib.Name);
await Task.Delay(TimeSpan.FromHours(4));
//BackgroundJob.Schedule(() => ScanLibraries(forceUpdate), TimeSpan.FromHours(4));
//return;
}
await ScanLibrary(lib.Id, forceUpdate, true);

View File

@ -137,7 +137,7 @@ public class Startup
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "2.0",
Version = "3.1.0",
Title = "Kavita",
Description = $"Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v{BuildInfo.Version.ToString()}",
License = new OpenApiLicense
@ -176,7 +176,7 @@ public class Startup
Url = "{protocol}://{hostpath}",
Variables = new Dictionary<string, OpenApiServerVariable>
{
{ "protocol", new OpenApiServerVariable { Default = "http", Enum = new List<string> { "http", "https" } } },
{ "protocol", new OpenApiServerVariable { Default = "http", Enum = ["http", "https"]} },
{ "hostpath", new OpenApiServerVariable { Default = "localhost:5000" } }
}
});
@ -207,7 +207,7 @@ public class Startup
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseInMemoryStorage());
//.UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted (and locking can cause high utilization)
//.UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted (and locking can cause high utilization) (NOTE: There is code to clear jobs on startup a redditor gave me)
// Add the processing server as IHostedService
services.AddHangfireServer(options =>

View File

@ -1,39 +1,49 @@
<ng-container *transloco="let t; read: 'infinite-scroller'">
<div class="fixed-top overlay" *ngIf="showDebugBar()">
<strong>Captures Scroll Events:</strong> {{!this.isScrolling && this.allImagesLoaded}}
<strong>Is Scrolling:</strong> {{isScrollingForwards() ? 'Forwards' : 'Backwards'}} {{this.isScrolling}}
<strong>All Images Loaded:</strong> {{this.allImagesLoaded}}
<strong>Prefetched</strong> {{minPageLoaded}}-{{maxPageLoaded}}
<strong>Pages:</strong> {{pageNum}} / {{totalPages - 1}}
<strong>At Top:</strong> {{atTop}}
<strong>At Bottom:</strong> {{atBottom}}
<strong>Total Height:</strong> {{getTotalHeight()}}
<strong>Total Scroll:</strong> {{getTotalScroll()}}
<strong>Scroll Top:</strong> {{getScrollTop()}}
</div>
<div *ngIf="atTop" #topSpacer class="spacer top" role="alert" (click)="loadPrevChapter.emit()">
<div style="height: 200px"></div>
<div>
<button class="btn btn-icon mx-auto">
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
</button>
<span class="mx-auto text">{{t('continuous-reading-prev-chapter')}}</span>
<button class="btn btn-icon mx-auto">
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
</button>
<span class="visually-hidden">{{t('continuous-reading-prev-chapter-alt')}}</span>
@if (showDebugBar()) {
<div class="fixed-top overlay">
<strong>Captures Scroll Events:</strong> {{!this.isScrolling && this.allImagesLoaded}}
<strong>Is Scrolling:</strong> {{isScrollingForwards() ? 'Forwards' : 'Backwards'}} {{this.isScrolling}}
<strong>All Images Loaded:</strong> {{this.allImagesLoaded}}
<strong>Prefetched</strong> {{minPageLoaded}}-{{maxPageLoaded}}
<strong>Pages:</strong> {{pageNum}} / {{totalPages - 1}}
<strong>At Top:</strong> {{atTop}}
<strong>At Bottom:</strong> {{atBottom}}
<strong>Total Height:</strong> {{getTotalHeight()}}
<strong>Total Scroll:</strong> {{getTotalScroll()}}
<strong>Scroll Top:</strong> {{getScrollTop()}}
</div>
</div>
}
@if (atTop) {
<div #topSpacer class="spacer top" role="alert" (click)="loadPrevChapter.emit()">
<div class="empty-space"></div>
<div>
<button class="btn btn-icon mx-auto">
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
</button>
<span class="mx-auto text">{{t('continuous-reading-prev-chapter')}}</span>
<button class="btn btn-icon mx-auto">
<i class="fa fa-angle-double-up animate" aria-hidden="true"></i>
</button>
<span class="visually-hidden">{{t('continuous-reading-prev-chapter-alt')}}</span>
</div>
</div>
}
<div infinite-scroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="50">
<ng-container *ngFor="let item of webtoonImages | async; let index = index;">
<img src="{{item.src}}" style="display: block; width: {{widthOverride$ | async}}"
@for(item of webtoonImages | async; let index = $index; track item.src) {
<img src="{{item.src}}" style="display: block;" [ngStyle]="{'width': widthOverride$ | async}"
[style.filter]="(darkness$ | async) ?? '' | safeStyle"
class="mx-auto {{pageNum === item.page && showDebugOutline() ? 'active': ''}} {{areImagesWiderThanWindow ? 'full-width' : ''}}"
rel="nofollow" alt="image" (load)="onImageLoad($event)" id="page-{{item.page}}" [attr.page]="item.page" ondragstart="return false;" onselectstart="return false;">
</ng-container>
rel="nofollow"
alt="image"
(load)="onImageLoad($event)"
id="page-{{item.page}}"
[attr.page]="item.page"
ondragstart="return false;"
onselectstart="return false;">
}
</div>
<div #bottomSpacer class="spacer bottom" role="alert" (click)="loadNextChapter.emit()">
@ -47,7 +57,7 @@
</button>
<span class="visually-hidden">{{t('continuous-reading-next-chapter-alt')}}</span>
</div>
<div style="height: 200px"></div>
<div class="empty-space"></div>
</div>
</ng-container>

View File

@ -21,8 +21,12 @@
.text {
z-index: 101;
}
.empty-space {
height: 200px;
}
}

View File

@ -1,4 +1,4 @@
import { DOCUMENT, NgIf, NgFor, AsyncPipe } from '@angular/common';
import {DOCUMENT, AsyncPipe, NgStyle} from '@angular/common';
import {
AfterViewInit,
ChangeDetectionStrategy,
@ -16,7 +16,7 @@ import {
Renderer2,
SimpleChanges, ViewChild
} from '@angular/core';
import {BehaviorSubject, filter, fromEvent, map, Observable, of, ReplaySubject} from 'rxjs';
import {BehaviorSubject, fromEvent, map, Observable, of, ReplaySubject} from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { ScrollService } from 'src/app/_services/scroll.service';
import { ReaderService } from '../../../_services/reader.service';
@ -62,7 +62,7 @@ const enum DEBUG_MODES {
styleUrls: ['./infinite-scroller.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [NgIf, NgFor, AsyncPipe, TranslocoDirective, InfiniteScrollModule, SafeStylePipe]
imports: [AsyncPipe, TranslocoDirective, InfiniteScrollModule, SafeStylePipe, NgStyle]
})
export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {

View File

@ -19,6 +19,7 @@ import {
BehaviorSubject,
debounceTime,
distinctUntilChanged,
filter,
forkJoin,
fromEvent,
map,
@ -399,7 +400,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
*/
debugMode: boolean = false;
/**
* Width override label for maunal width control
* Width override label for manual width control
*/
widthOverrideLabel$ : Observable<string> = new Observable<string>();
@ -554,55 +555,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {});
//only enable the width override slider under certain conditions
// width mode selected
// splitting is set to fit to screen, otherwise disable
// when disable set the value to 0
// to use the default of the current single page reader
this.generalSettingsForm.get('pageSplitOption')?.valueChanges.pipe(
tap(val => {
const fitting = this.generalSettingsForm.get('fittingOption')?.value;
const widthOverrideControl = this.generalSettingsForm.get('widthSlider')!;
if (PageSplitOption.FitSplit == val && FITTING_OPTION.WIDTH == fitting) {
widthOverrideControl?.enable();
} else {
widthOverrideControl?.setValue(0);
widthOverrideControl?.disable();
}
}),
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {});
//only enable the width override slider under certain conditions
// width mode selected
// splitting is set to fit to screen, otherwise disable
// when disable set the value to 0
// to use the default of the current single page reader
this.generalSettingsForm.get('fittingOption')?.valueChanges.pipe(
tap(val => {
const splitting = this.generalSettingsForm.get('pageSplitOption')?.value;
const widthOverrideControl = this.generalSettingsForm.get('widthSlider')!;
if (PageSplitOption.FitSplit == splitting && FITTING_OPTION.WIDTH == val){
widthOverrideControl?.enable();
} else {
widthOverrideControl?.setValue(0);
widthOverrideControl?.disable();
}
}),
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {});
//sets the default override to 0, fixing the none% bug
this.generalSettingsForm.get('widthSlider')!.setValue(0);
//send the current width override value to the label
this.widthOverrideLabel$ = this.readerSettings$?.pipe(
map(values => (parseInt(values.widthSlider) <= 0) ? '' : values.widthSlider + '%'),
takeUntilDestroyed(this.destroyRef)
);
this.setupWidthOverrideTriggers();
this.generalSettingsForm.get('layoutMode')?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(val => {
@ -746,6 +699,68 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
}
}
/**
* Width override is only valid under the following conditions:
* Image Scaling is Width
* Reader Mode is Webtoon
*
* In all other cases, the form will be disabled and set to 0 which indicates default/off state.
*/
setupWidthOverrideTriggers() {
const widthOverrideControl = this.generalSettingsForm.get('widthSlider')!;
const enableWidthOverride = () => {
widthOverrideControl.enable();
};
const disableWidthOverride = () => {
widthOverrideControl.setValue(0);
widthOverrideControl.disable();
};
const handleControlChanges = () => {
const fitting = this.generalSettingsForm.get('fittingOption')?.value;
const splitting = this.generalSettingsForm.get('pageSplitOption')?.value;
if ((PageSplitOption.FitSplit == splitting && FITTING_OPTION.WIDTH == fitting) || this.readerMode === ReaderMode.Webtoon) {
enableWidthOverride();
} else {
disableWidthOverride();
}
};
// Reader mode changes
this.readerModeSubject.asObservable()
.pipe(
filter(v => v === ReaderMode.Webtoon),
tap(enableWidthOverride),
takeUntilDestroyed(this.destroyRef)
)
.subscribe();
// Page split option changes
this.generalSettingsForm.get('pageSplitOption')?.valueChanges.pipe(
distinctUntilChanged(),
tap(handleControlChanges),
takeUntilDestroyed(this.destroyRef)
).subscribe();
// Fitting option changes
this.generalSettingsForm.get('fittingOption')?.valueChanges.pipe(
tap(handleControlChanges),
takeUntilDestroyed(this.destroyRef)
).subscribe();
// Set the default override to 0
widthOverrideControl.setValue(0);
//send the current width override value to the label
this.widthOverrideLabel$ = this.readerSettings$?.pipe(
map(values => (parseInt(values.widthSlider) <= 0) ? '' : values.widthSlider + '%'),
takeUntilDestroyed(this.destroyRef)
);
}
createReaderSettingsUpdate() {
return {
pageSplit: parseInt(this.generalSettingsForm.get('pageSplitOption')?.value, 10),

File diff suppressed because it is too large Load Diff