mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
PDF Polish (#2837)
Co-authored-by: William Brockhus <pickeringw@gmail.com>
This commit is contained in:
parent
6ed634f5d1
commit
752fda0e93
@ -37,6 +37,9 @@ namespace API.Controllers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AccountController : BaseApiController
|
public class AccountController : BaseApiController
|
||||||
{
|
{
|
||||||
|
// Hardcoded to avoid localization multiple enumeration: https://github.com/Kareadita/Kavita/issues/2829
|
||||||
|
private const string BadCredentialsMessage = "Your credentials are not correct";
|
||||||
|
|
||||||
private readonly UserManager<AppUser> _userManager;
|
private readonly UserManager<AppUser> _userManager;
|
||||||
private readonly SignInManager<AppUser> _signInManager;
|
private readonly SignInManager<AppUser> _signInManager;
|
||||||
private readonly ITokenService _tokenService;
|
private readonly ITokenService _tokenService;
|
||||||
@ -204,7 +207,7 @@ public class AccountController : BaseApiController
|
|||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Attempted login by {UserName} failed due to unable to find account", loginDto.Username);
|
_logger.LogWarning("Attempted login by {UserName} failed due to unable to find account", loginDto.Username);
|
||||||
return Unauthorized(await _localizationService.Get("en", "bad-credentials"));
|
return Unauthorized(BadCredentialsMessage);
|
||||||
}
|
}
|
||||||
var roles = await _userManager.GetRolesAsync(user);
|
var roles = await _userManager.GetRolesAsync(user);
|
||||||
if (!roles.Contains(PolicyConstants.LoginRole)) return Unauthorized(await _localizationService.Translate(user.Id, "disabled-account"));
|
if (!roles.Contains(PolicyConstants.LoginRole)) return Unauthorized(await _localizationService.Translate(user.Id, "disabled-account"));
|
||||||
@ -225,10 +228,10 @@ public class AccountController : BaseApiController
|
|||||||
|
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
var errorStr = await _localizationService.Translate(user.Id,
|
string errorStr = result.IsNotAllowed
|
||||||
result.IsNotAllowed ? "confirm-email" : "bad-credentials");
|
? await _localizationService.Translate(user.Id, "confirm-email")
|
||||||
_logger.LogWarning("{UserName} failed to log in at {Time}: {Issue}", user.UserName, user.LastActive,
|
: BadCredentialsMessage;
|
||||||
errorStr);
|
_logger.LogWarning("{UserName} failed to log in at {Time}: {Issue}", user.UserName, user.LastActive, errorStr);
|
||||||
return Unauthorized(errorStr);
|
return Unauthorized(errorStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,7 +861,7 @@ public class AccountController : BaseApiController
|
|||||||
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
return BadRequest(await _localizationService.Get("en", "bad-credentials"));
|
return BadRequest(BadCredentialsMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -868,7 +871,7 @@ public class AccountController : BaseApiController
|
|||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Unable to reset password, your email token is not correct: {@Dto}", dto);
|
_logger.LogInformation("Unable to reset password, your email token is not correct: {@Dto}", dto);
|
||||||
return BadRequest(await _localizationService.Translate(user.Id, "bad-credentials"));
|
return BadRequest(BadCredentialsMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
var errors = await _accountService.ChangeUserPassword(user, dto.Password);
|
var errors = await _accountService.ChangeUserPassword(user, dto.Password);
|
||||||
@ -948,12 +951,12 @@ public class AccountController : BaseApiController
|
|||||||
public async Task<ActionResult<UserDto>> ConfirmMigrationEmail(ConfirmMigrationEmailDto dto)
|
public async Task<ActionResult<UserDto>> ConfirmMigrationEmail(ConfirmMigrationEmailDto dto)
|
||||||
{
|
{
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
||||||
if (user == null) return BadRequest(await _localizationService.Get("en", "bad-credentials"));
|
if (user == null) return BadRequest(BadCredentialsMessage);
|
||||||
|
|
||||||
if (!await ConfirmEmailToken(dto.Token, user))
|
if (!await ConfirmEmailToken(dto.Token, user))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("confirm-migration-email email token is invalid");
|
_logger.LogInformation("confirm-migration-email email token is invalid");
|
||||||
return BadRequest(await _localizationService.Translate(user.Id, "bad-credentials"));
|
return BadRequest(BadCredentialsMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _unitOfWork.CommitAsync();
|
await _unitOfWork.CommitAsync();
|
||||||
|
@ -119,7 +119,6 @@ public class UsersController : BaseApiController
|
|||||||
existingPreferences.ShareReviews = preferencesDto.ShareReviews;
|
existingPreferences.ShareReviews = preferencesDto.ShareReviews;
|
||||||
|
|
||||||
existingPreferences.PdfTheme = preferencesDto.PdfTheme;
|
existingPreferences.PdfTheme = preferencesDto.PdfTheme;
|
||||||
existingPreferences.PdfLayoutMode = preferencesDto.PdfLayoutMode;
|
|
||||||
existingPreferences.PdfScrollMode = preferencesDto.PdfScrollMode;
|
existingPreferences.PdfScrollMode = preferencesDto.PdfScrollMode;
|
||||||
existingPreferences.PdfSpreadMode = preferencesDto.PdfSpreadMode;
|
existingPreferences.PdfSpreadMode = preferencesDto.PdfSpreadMode;
|
||||||
|
|
||||||
|
@ -118,7 +118,8 @@ public class AppUserPreferences
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// PDF Reader: Layout Mode of the reader
|
/// PDF Reader: Layout Mode of the reader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PdfLayoutMode PdfLayoutMode { get; set; } = PdfLayoutMode.Multiple;
|
/// Book mode is too buggy to include
|
||||||
|
//public PdfLayoutMode PdfLayoutMode { get; set; } = PdfLayoutMode.Multiple;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PDF Reader: Spread Mode of the reader
|
/// PDF Reader: Spread Mode of the reader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"confirm-email": "You must confirm your email first",
|
"confirm-email": "You must confirm your email first",
|
||||||
"bad-credentials": "Your credentials are not correct",
|
|
||||||
"locked-out": "You've been locked out from too many authorization attempts. Please wait 10 minutes.",
|
"locked-out": "You've been locked out from too many authorization attempts. Please wait 10 minutes.",
|
||||||
"disabled-account": "Your account is disabled. Contact the server admin.",
|
"disabled-account": "Your account is disabled. Contact the server admin.",
|
||||||
"register-user": "Something went wrong when registering user",
|
"register-user": "Something went wrong when registering user",
|
||||||
|
@ -41,7 +41,6 @@ export interface Preferences {
|
|||||||
// PDF Reader
|
// PDF Reader
|
||||||
pdfTheme: PdfTheme;
|
pdfTheme: PdfTheme;
|
||||||
pdfScrollMode: PdfScrollMode;
|
pdfScrollMode: PdfScrollMode;
|
||||||
pdfLayoutMode: PdfLayoutMode;
|
|
||||||
pdfSpreadMode: PdfSpreadMode;
|
pdfSpreadMode: PdfSpreadMode;
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
|
@ -142,7 +142,7 @@ export class AccountService {
|
|||||||
|
|
||||||
login(model: {username: string, password: string, apiKey?: string}) {
|
login(model: {username: string, password: string, apiKey?: string}) {
|
||||||
return this.httpClient.post<User>(this.baseUrl + 'account/login', model).pipe(
|
return this.httpClient.post<User>(this.baseUrl + 'account/login', model).pipe(
|
||||||
map((response: User) => {
|
tap((response: User) => {
|
||||||
const user = response;
|
const user = response;
|
||||||
if (user) {
|
if (user) {
|
||||||
this.setCurrentUser(user);
|
this.setCurrentUser(user);
|
||||||
@ -176,6 +176,8 @@ export class AccountService {
|
|||||||
this.stopRefreshTokenTimer();
|
this.stopRefreshTokenTimer();
|
||||||
|
|
||||||
if (this.currentUser) {
|
if (this.currentUser) {
|
||||||
|
// BUG: StopHubConnection has a promise in it, this needs to be async
|
||||||
|
// But that really messes everything up
|
||||||
this.messageHub.stopHubConnection();
|
this.messageHub.stopHubConnection();
|
||||||
this.messageHub.createHubConnection(this.currentUser);
|
this.messageHub.createHubConnection(this.currentUser);
|
||||||
this.hasValidLicense().subscribe();
|
this.hasValidLicense().subscribe();
|
||||||
|
@ -17,12 +17,18 @@
|
|||||||
>{{t('renew')}}</a>
|
>{{t('renew')}}</a>
|
||||||
}
|
}
|
||||||
<button class="btn btn-secondary btn-sm me-1" style="width: 58px" (click)="validateLicense()">
|
<button class="btn btn-secondary btn-sm me-1" style="width: 58px" (click)="validateLicense()">
|
||||||
<span *ngIf="!isChecking">{{t('check')}}</span>
|
@if (isChecking) {
|
||||||
<app-loading [loading]="isChecking" size="spinner-border-sm"></app-loading>
|
<app-loading [loading]="isChecking" size="spinner-border-sm"></app-loading>
|
||||||
|
} @else {
|
||||||
|
<span>{{t('check')}}</span>
|
||||||
|
}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary btn-sm" style="width: 62px" (click)="toggleViewMode()">
|
<button class="btn btn-secondary btn-sm" style="width: 62px" (click)="toggleViewMode()">
|
||||||
<span *ngIf="!isViewMode">{{t('cancel')}}</span>
|
@if (isViewMode) {
|
||||||
<span *ngIf="isViewMode">{{t('edit')}}</span>
|
<span>{{t('edit')}}</span>
|
||||||
|
} @else {
|
||||||
|
<span>{{t('cancel')}}</span>
|
||||||
|
}
|
||||||
</button>
|
</button>
|
||||||
} @else {
|
} @else {
|
||||||
<a class="btn btn-secondary btn-sm me-1" [href]="buyLink" target="_blank" rel="noreferrer nofollow">{{t('buy')}}</a>
|
<a class="btn btn-secondary btn-sm me-1" [href]="buyLink" target="_blank" rel="noreferrer nofollow">{{t('buy')}}</a>
|
||||||
@ -35,24 +41,29 @@
|
|||||||
@if (isViewMode) {
|
@if (isViewMode) {
|
||||||
<div class="container-fluid row">
|
<div class="container-fluid row">
|
||||||
<span class="col-12">
|
<span class="col-12">
|
||||||
<ng-container *ngIf="hasLicense; else noToken">
|
@if (hasLicense) {
|
||||||
<span class="me-1">*********</span>
|
<span class="me-1">*********</span>
|
||||||
<ng-container *ngIf="!isChecking; else checking">
|
@if (isChecking) {
|
||||||
<i *ngIf="hasValidLicense" [ngbTooltip]="t('license-valid')" class="fa-solid fa-check-circle successful-validation ms-1">
|
<div class="spinner-border spinner-border-sm text-primary" role="status">
|
||||||
|
<span class="visually-hidden">{{t('loading')}}</span>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
@if (hasValidLicense) {
|
||||||
|
<i [ngbTooltip]="t('license-valid')" class="fa-solid fa-check-circle successful-validation ms-1">
|
||||||
<span class="visually-hidden">{{t('license-valid')}}</span>
|
<span class="visually-hidden">{{t('license-valid')}}</span>
|
||||||
</i>
|
</i>
|
||||||
<i class="error fa-solid fa-exclamation-circle ms-1" [ngbTooltip]="t('license-not-valid')" *ngIf="!hasValidLicense">
|
}
|
||||||
<span class="visually-hidden">{{t('license-not-valid')}}</span>
|
|
||||||
</i>
|
|
||||||
</ng-container>
|
|
||||||
<ng-template #checking>
|
|
||||||
<div class="spinner-border spinner-border-sm text-primary" role="status">
|
|
||||||
<span class="visually-hidden">{{t('loading')}}</span>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
</ng-container>
|
@if (!hasValidLicense) {
|
||||||
<ng-template #noToken>{{t('no-license-key')}}</ng-template>
|
<i class="error fa-solid fa-exclamation-circle ms-1" [ngbTooltip]="t('license-not-valid')">
|
||||||
|
<span class="visually-hidden">{{t('license-not-valid')}}</span>
|
||||||
|
</i>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
{{t('no-license-key')}}
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -74,11 +85,13 @@
|
|||||||
<i class="fa fa-circle-info ms-1" aria-hidden="true" [ngbTooltip]="t('activate-discordId-tooltip')"></i>
|
<i class="fa fa-circle-info ms-1" aria-hidden="true" [ngbTooltip]="t('activate-discordId-tooltip')"></i>
|
||||||
<a class="ms-1" href="https://wiki.kavitareader.com/en/kavita-plus#discord-id" target="_blank" rel="noopener noreferrer">Help</a>
|
<a class="ms-1" href="https://wiki.kavitareader.com/en/kavita-plus#discord-id" target="_blank" rel="noopener noreferrer">Help</a>
|
||||||
<input id="discordId" type="text" class="form-control" formControlName="discordId" autocomplete="off" [class.is-invalid]="formGroup.get('discordId')?.invalid && formGroup.get('discordId')?.touched"/>
|
<input id="discordId" type="text" class="form-control" formControlName="discordId" autocomplete="off" [class.is-invalid]="formGroup.get('discordId')?.invalid && formGroup.get('discordId')?.touched"/>
|
||||||
<div id="inviteForm-validations" class="invalid-feedback" *ngIf="formGroup.dirty || formGroup.touched">
|
@if (formGroup.dirty || formGroup.touched) {
|
||||||
<div *ngIf="formGroup.get('discordId')?.errors?.pattern">
|
<div id="inviteForm-validations" class="invalid-feedback">
|
||||||
{{t('discord-validation')}}
|
<div *ngIf="formGroup.get('discordId')?.errors?.pattern">
|
||||||
|
{{t('discord-validation')}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
|
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
|
||||||
@ -93,7 +106,10 @@
|
|||||||
</button>
|
</button>
|
||||||
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="license-key-header"
|
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="license-key-header"
|
||||||
[disabled]="!formGroup.get('email')?.value || !formGroup.get('licenseKey')?.value" (click)="saveForm()">
|
[disabled]="!formGroup.get('email')?.value || !formGroup.get('licenseKey')?.value" (click)="saveForm()">
|
||||||
<span *ngIf="!isSaving">{{t('activate-save')}}</span>
|
@if (!isSaving) {
|
||||||
|
<span>{{t('activate-save')}}</span>
|
||||||
|
}
|
||||||
|
|
||||||
<app-loading [loading]="isSaving" size="spinner-border-sm"></app-loading>
|
<app-loading [loading]="isSaving" size="spinner-border-sm"></app-loading>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,7 @@ import {catchError} from "rxjs";
|
|||||||
styleUrls: ['./license.component.scss'],
|
styleUrls: ['./license.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [NgIf, NgbTooltip, LoadingComponent, NgbCollapse, ReactiveFormsModule, TranslocoDirective]
|
imports: [NgbTooltip, LoadingComponent, NgbCollapse, ReactiveFormsModule, TranslocoDirective]
|
||||||
})
|
})
|
||||||
export class LicenseComponent implements OnInit {
|
export class LicenseComponent implements OnInit {
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export class LicenseComponent implements OnInit {
|
|||||||
|
|
||||||
hasValidLicense: boolean = false;
|
hasValidLicense: boolean = false;
|
||||||
hasLicense: boolean = false;
|
hasLicense: boolean = false;
|
||||||
isChecking: boolean = false;
|
isChecking: boolean = true;
|
||||||
isSaving: boolean = false;
|
isSaving: boolean = false;
|
||||||
|
|
||||||
buyLink = environment.buyLink;
|
buyLink = environment.buyLink;
|
||||||
@ -53,8 +53,11 @@ export class LicenseComponent implements OnInit {
|
|||||||
this.hasLicense = res;
|
this.hasLicense = res;
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
});
|
});
|
||||||
|
this.isChecking = true;
|
||||||
|
this.cdRef.markForCheck();
|
||||||
this.accountService.hasValidLicense().subscribe(res => {
|
this.accountService.hasValidLicense().subscribe(res => {
|
||||||
this.hasValidLicense = res;
|
this.hasValidLicense = res;
|
||||||
|
this.isChecking = false;
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,12 @@
|
|||||||
(pdfLoaded)="updateLoading(false)"
|
(pdfLoaded)="updateLoading(false)"
|
||||||
(progress)="updateLoadProgress($event)"
|
(progress)="updateLoadProgress($event)"
|
||||||
(zoomChange)="calcScrollbarNeeded()"
|
(zoomChange)="calcScrollbarNeeded()"
|
||||||
|
(handToolChange)="updateHandTool($event)"
|
||||||
>
|
>
|
||||||
|
|
||||||
</ngx-extended-pdf-viewer>
|
</ngx-extended-pdf-viewer>
|
||||||
|
|
||||||
@if (scrollMode === ScrollModeType.page) {
|
@if (scrollMode === ScrollModeType.page && !isLoading) {
|
||||||
<div class="left" (click)="prevPage()"></div>
|
<div class="left" (click)="prevPage()"></div>
|
||||||
<div class="{{scrollbarNeeded ? 'right-with-scrollbar' : 'right'}}" (click)="nextPage()"></div>
|
<div class="{{scrollbarNeeded ? 'right-with-scrollbar' : 'right'}}" (click)="nextPage()"></div>
|
||||||
}
|
}
|
||||||
@ -85,13 +86,13 @@
|
|||||||
<pdf-select-tool></pdf-select-tool>
|
<pdf-select-tool></pdf-select-tool>
|
||||||
<pdf-presentation-mode></pdf-presentation-mode>
|
<pdf-presentation-mode></pdf-presentation-mode>
|
||||||
|
|
||||||
|
<!-- The book mode is messy, not ready for prime time -->
|
||||||
@if (utilityService.getActiveBreakpoint() > Breakpoint.Mobile) {
|
<!-- @if (utilityService.getActiveBreakpoint() > Breakpoint.Mobile) {-->
|
||||||
<button (click)="toggleBookPageMode()" class="btn-icon toolbarButton" [ngbTooltip]="pageLayoutMode | pdfLayoutMode" [disabled]="scrollMode === ScrollModeType.page">
|
<!-- <button (click)="toggleBookPageMode()" class="btn-icon toolbarButton" [ngbTooltip]="pageLayoutMode | pdfLayoutMode" [disabled]="scrollMode === ScrollModeType.page">-->
|
||||||
<i class="toolbar-icon fa-solid {{this.pageLayoutMode !== 'book' ? 'fa-book' : 'fa-book-open'}}" [ngStyle]="{color: fontColor}" aria-hidden="true"></i>
|
<!-- <i class="toolbar-icon fa-solid {{this.pageLayoutMode !== 'book' ? 'fa-book' : 'fa-book-open'}}" [ngStyle]="{color: fontColor}" aria-hidden="true"></i>-->
|
||||||
<span class="visually-hidden">{{this.pageLayoutMode | pdfLayoutMode}}</span>
|
<!-- <span class="visually-hidden">{{this.pageLayoutMode | pdfLayoutMode}}</span>-->
|
||||||
</button>
|
<!-- </button>-->
|
||||||
}
|
<!-- }-->
|
||||||
|
|
||||||
|
|
||||||
<!-- scroll mode should be disabled when book mode is used -->
|
<!-- scroll mode should be disabled when book mode is used -->
|
||||||
|
@ -34,8 +34,11 @@ $pagination-opacity: 0;
|
|||||||
//$pagination-color: red;
|
//$pagination-color: red;
|
||||||
//$pagination-opacity: 0.7;
|
//$pagination-opacity: 0.7;
|
||||||
$action-bar-height: 36px;
|
$action-bar-height: 36px;
|
||||||
|
$loading-bar-height: 24px;
|
||||||
|
|
||||||
// Tap to Paginate
|
// Tap to Paginate
|
||||||
|
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
|
@ -34,6 +34,7 @@ import {SpreadType} from "ngx-extended-pdf-viewer/lib/options/spread-type";
|
|||||||
import {PdfLayoutModePipe} from "../../_pipe/pdf-layout-mode.pipe";
|
import {PdfLayoutModePipe} from "../../_pipe/pdf-layout-mode.pipe";
|
||||||
import {PdfScrollModePipe} from "../../_pipe/pdf-scroll-mode.pipe";
|
import {PdfScrollModePipe} from "../../_pipe/pdf-scroll-mode.pipe";
|
||||||
import {PdfSpreadModePipe} from "../../_pipe/pdf-spread-mode.pipe";
|
import {PdfSpreadModePipe} from "../../_pipe/pdf-spread-mode.pipe";
|
||||||
|
import {HandtoolChanged} from "ngx-extended-pdf-viewer/lib/events/handtool-changed";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pdf-reader',
|
selector: 'app-pdf-reader',
|
||||||
@ -236,7 +237,7 @@ export class PdfReaderComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|
||||||
this.pageLayoutMode = this.convertPdfLayoutMode(this.user.preferences.pdfLayoutMode || PdfLayoutMode.Multiple);
|
this.pageLayoutMode = this.convertPdfLayoutMode(PdfLayoutMode.Multiple);
|
||||||
this.scrollMode = this.convertPdfScrollMode(this.user.preferences.pdfScrollMode || PdfScrollMode.Vertical);
|
this.scrollMode = this.convertPdfScrollMode(this.user.preferences.pdfScrollMode || PdfScrollMode.Vertical);
|
||||||
this.spreadMode = this.convertPdfSpreadMode(this.user.preferences.pdfSpreadMode || PdfSpreadMode.None);
|
this.spreadMode = this.convertPdfSpreadMode(this.user.preferences.pdfSpreadMode || PdfSpreadMode.None);
|
||||||
this.theme = this.convertPdfTheme(this.user.preferences.pdfTheme || PdfTheme.Dark);
|
this.theme = this.convertPdfTheme(this.user.preferences.pdfTheme || PdfTheme.Dark);
|
||||||
@ -350,6 +351,10 @@ export class PdfReaderComponent implements OnInit, OnDestroy {
|
|||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateHandTool(event: any) {
|
||||||
|
console.log('event.tool', event);
|
||||||
|
}
|
||||||
|
|
||||||
prevPage() {
|
prevPage() {
|
||||||
this.currentPage--;
|
this.currentPage--;
|
||||||
if (this.currentPage < 0) this.currentPage = 0;
|
if (this.currentPage < 0) this.currentPage = 0;
|
||||||
|
@ -542,45 +542,6 @@
|
|||||||
<div ngbAccordionBody>
|
<div ngbAccordionBody>
|
||||||
<ng-template>
|
<ng-template>
|
||||||
|
|
||||||
<div class="row g-0">
|
|
||||||
<div class="col-md-6 col-sm-12 pe-2 mb-3">
|
|
||||||
<label for="settings-pdf-layout-mode" class="form-label">{{t('pdf-layout-mode-label')}}</label><i
|
|
||||||
class="fa fa-info-circle ms-1" aria-hidden="true" placement="right"
|
|
||||||
[ngbTooltip]="pdfLayoutModeTooltip" role="button" tabindex="0"></i>
|
|
||||||
<ng-template #pdfLayoutModeTooltip>{{t('pdf-layout-mode-tooltip')}}
|
|
||||||
</ng-template>
|
|
||||||
<span class="visually-hidden" id="settings-pdf-layout-mode-help">
|
|
||||||
<ng-container [ngTemplateOutlet]="pdfLayoutModeTooltip"></ng-container>
|
|
||||||
</span>
|
|
||||||
<select id="settings-pdf-layout-mode" class="form-select"
|
|
||||||
aria-describedby="settings-pdf-layout-mode-help"
|
|
||||||
formControlName="pdfLayoutMode">
|
|
||||||
<option *ngFor="let opt of pdfLayoutModesTranslated" [value]="opt.value">
|
|
||||||
{{opt.text | titlecase}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-6 col-sm-12 pe-2 mb-3">
|
|
||||||
<label for="settings-pdf-scroll-mode" class="form-label">{{t('pdf-scroll-mode-label')}}</label><i
|
|
||||||
class="fa fa-info-circle ms-1" aria-hidden="true" placement="right"
|
|
||||||
[ngbTooltip]="pdfScrollModeTooltip" role="button" tabindex="0"></i>
|
|
||||||
<ng-template #pdfScrollModeTooltip>{{t('pdf-scroll-mode-tooltip')}}
|
|
||||||
</ng-template>
|
|
||||||
<span class="visually-hidden" id="settings-pdf-scroll-mode-help">
|
|
||||||
<ng-container [ngTemplateOutlet]="pdfScrollModeTooltip"></ng-container>
|
|
||||||
</span>
|
|
||||||
<select id="settings-pdf-scroll-mode" class="form-select"
|
|
||||||
aria-describedby="settings-pdf-scroll-mode-help"
|
|
||||||
formControlName="pdfScrollMode">
|
|
||||||
<option *ngFor="let opt of pdfScrollModesTranslated" [value]="opt.value">
|
|
||||||
{{opt.text | titlecase}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
<div class="col-md-6 col-sm-12 pe-2 mb-3">
|
<div class="col-md-6 col-sm-12 pe-2 mb-3">
|
||||||
<label for="settings-pdf-spread-mode" class="form-label">{{t('pdf-spread-mode-label')}}</label><i
|
<label for="settings-pdf-spread-mode" class="form-label">{{t('pdf-spread-mode-label')}}</label><i
|
||||||
@ -612,6 +573,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-0">
|
||||||
|
<div class="col-md-6 col-sm-12 pe-2 mb-3">
|
||||||
|
<label for="settings-pdf-scroll-mode" class="form-label">{{t('pdf-scroll-mode-label')}}</label><i
|
||||||
|
class="fa fa-info-circle ms-1" aria-hidden="true" placement="right"
|
||||||
|
[ngbTooltip]="pdfScrollModeTooltip" role="button" tabindex="0"></i>
|
||||||
|
<ng-template #pdfScrollModeTooltip>{{t('pdf-scroll-mode-tooltip')}}
|
||||||
|
</ng-template>
|
||||||
|
<span class="visually-hidden" id="settings-pdf-scroll-mode-help">
|
||||||
|
<ng-container [ngTemplateOutlet]="pdfScrollModeTooltip"></ng-container>
|
||||||
|
</span>
|
||||||
|
<select id="settings-pdf-scroll-mode" class="form-select"
|
||||||
|
aria-describedby="settings-pdf-scroll-mode-help"
|
||||||
|
formControlName="pdfScrollMode">
|
||||||
|
<option *ngFor="let opt of pdfScrollModesTranslated" [value]="opt.value">
|
||||||
|
{{opt.text | titlecase}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
|
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
|
||||||
<button type="button" class="flex-fill btn btn-secondary me-2" (click)="resetForm()"
|
<button type="button" class="flex-fill btn btn-secondary me-2" (click)="resetForm()"
|
||||||
|
@ -136,7 +136,7 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
pageLayoutModesTranslated = pageLayoutModes.map(this.translatePrefOptions);
|
pageLayoutModesTranslated = pageLayoutModes.map(this.translatePrefOptions);
|
||||||
bookWritingStylesTranslated = bookWritingStyles.map(this.translatePrefOptions);
|
bookWritingStylesTranslated = bookWritingStyles.map(this.translatePrefOptions);
|
||||||
pdfLayoutModesTranslated = pdfLayoutModes.map(this.translatePrefOptions);
|
// pdfLayoutModesTranslated = pdfLayoutModes.map(this.translatePrefOptions);
|
||||||
pdfScrollModesTranslated = pdfScrollModes.map(this.translatePrefOptions);
|
pdfScrollModesTranslated = pdfScrollModes.map(this.translatePrefOptions);
|
||||||
pdfSpreadModesTranslated = pdfSpreadModes.map(this.translatePrefOptions);
|
pdfSpreadModesTranslated = pdfSpreadModes.map(this.translatePrefOptions);
|
||||||
pdfThemesTranslated = pdfThemes.map(this.translatePrefOptions);
|
pdfThemesTranslated = pdfThemes.map(this.translatePrefOptions);
|
||||||
@ -253,7 +253,6 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.settingsForm.addControl('pdfTheme', new FormControl(this.user?.preferences.pdfTheme || PdfTheme.Dark, []));
|
this.settingsForm.addControl('pdfTheme', new FormControl(this.user?.preferences.pdfTheme || PdfTheme.Dark, []));
|
||||||
this.settingsForm.addControl('pdfScrollMode', new FormControl(this.user?.preferences.pdfScrollMode || PdfScrollMode.Vertical, []));
|
this.settingsForm.addControl('pdfScrollMode', new FormControl(this.user?.preferences.pdfScrollMode || PdfScrollMode.Vertical, []));
|
||||||
this.settingsForm.addControl('pdfLayoutMode', new FormControl(this.user?.preferences.pdfLayoutMode || PdfLayoutMode.Multiple, []));
|
|
||||||
this.settingsForm.addControl('pdfSpreadMode', new FormControl(this.user?.preferences.pdfSpreadMode || PdfSpreadMode.None, []));
|
this.settingsForm.addControl('pdfSpreadMode', new FormControl(this.user?.preferences.pdfSpreadMode || PdfSpreadMode.None, []));
|
||||||
|
|
||||||
this.settingsForm.addControl('theme', new FormControl(this.user.preferences.theme, []));
|
this.settingsForm.addControl('theme', new FormControl(this.user.preferences.theme, []));
|
||||||
@ -318,7 +317,6 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.settingsForm.get('pdfTheme')?.setValue(this.user.preferences.pdfTheme);
|
this.settingsForm.get('pdfTheme')?.setValue(this.user.preferences.pdfTheme);
|
||||||
this.settingsForm.get('pdfScrollMode')?.setValue(this.user.preferences.pdfScrollMode);
|
this.settingsForm.get('pdfScrollMode')?.setValue(this.user.preferences.pdfScrollMode);
|
||||||
this.settingsForm.get('pdfLayoutMode')?.setValue(this.user.preferences.pdfLayoutMode);
|
|
||||||
this.settingsForm.get('pdfSpreadMode')?.setValue(this.user.preferences.pdfSpreadMode);
|
this.settingsForm.get('pdfSpreadMode')?.setValue(this.user.preferences.pdfSpreadMode);
|
||||||
|
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
@ -359,7 +357,6 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
|
|||||||
locale: modelSettings.locale,
|
locale: modelSettings.locale,
|
||||||
pdfTheme: parseInt(modelSettings.pdfTheme, 10),
|
pdfTheme: parseInt(modelSettings.pdfTheme, 10),
|
||||||
pdfScrollMode: parseInt(modelSettings.pdfScrollMode, 10),
|
pdfScrollMode: parseInt(modelSettings.pdfScrollMode, 10),
|
||||||
pdfLayoutMode: parseInt(modelSettings.pdfLayoutMode, 10),
|
|
||||||
pdfSpreadMode: parseInt(modelSettings.pdfSpreadMode, 10),
|
pdfSpreadMode: parseInt(modelSettings.pdfSpreadMode, 10),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,8 +160,6 @@
|
|||||||
"margin-book-tooltip": "How much spacing on each side of the screen. This will override to 0 on mobile devices regardless of this setting.",
|
"margin-book-tooltip": "How much spacing on each side of the screen. This will override to 0 on mobile devices regardless of this setting.",
|
||||||
|
|
||||||
"pdf-reader-settings-title": "PDF Reader",
|
"pdf-reader-settings-title": "PDF Reader",
|
||||||
"pdf-layout-mode-label": "Layout Mode",
|
|
||||||
"pdf-layout-mode-tooltip": "How the reader lays the pdf out. Default is pages stacked with scrolling and Book emulates a physical book",
|
|
||||||
"pdf-scroll-mode-label": "Scroll Mode",
|
"pdf-scroll-mode-label": "Scroll Mode",
|
||||||
"pdf-scroll-mode-tooltip": "How you scroll through pages. Vertical/Horizontal and Tap to Paginate (no scroll)",
|
"pdf-scroll-mode-tooltip": "How you scroll through pages. Vertical/Horizontal and Tap to Paginate (no scroll)",
|
||||||
"pdf-spread-mode-label": "Spread Mode",
|
"pdf-spread-mode-label": "Spread Mode",
|
||||||
@ -516,7 +514,7 @@
|
|||||||
"book": "Book",
|
"book": "Book",
|
||||||
"comic": "Comic",
|
"comic": "Comic",
|
||||||
"manga": "Manga",
|
"manga": "Manga",
|
||||||
"comicVine": "ComicVine",
|
"comicVine": "Comic Vine",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"lightNovel": "Light Novel"
|
"lightNovel": "Light Novel"
|
||||||
},
|
},
|
||||||
@ -1612,7 +1610,7 @@
|
|||||||
"validate-cbl-step": "Validate CBL",
|
"validate-cbl-step": "Validate CBL",
|
||||||
"dry-run-step": "Dry Run",
|
"dry-run-step": "Dry Run",
|
||||||
"final-import-step": "Final Step",
|
"final-import-step": "Final Step",
|
||||||
"comicvine-parsing-label": "Use ComicVine Series matching"
|
"comicvine-parsing-label": "Use Comic Vine Series matching"
|
||||||
},
|
},
|
||||||
|
|
||||||
"pdf-reader": {
|
"pdf-reader": {
|
||||||
|
11
openapi.json
11
openapi.json
@ -7,7 +7,7 @@
|
|||||||
"name": "GPL-3.0",
|
"name": "GPL-3.0",
|
||||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||||
},
|
},
|
||||||
"version": "0.7.14.12"
|
"version": "0.7.14.13"
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
@ -13619,15 +13619,6 @@
|
|||||||
"description": "PDF Reader: Scroll mode of the reader",
|
"description": "PDF Reader: Scroll mode of the reader",
|
||||||
"format": "int32"
|
"format": "int32"
|
||||||
},
|
},
|
||||||
"pdfLayoutMode": {
|
|
||||||
"enum": [
|
|
||||||
0,
|
|
||||||
2
|
|
||||||
],
|
|
||||||
"type": "integer",
|
|
||||||
"description": "PDF Reader: Layout Mode of the reader",
|
|
||||||
"format": "int32"
|
|
||||||
},
|
|
||||||
"pdfSpreadMode": {
|
"pdfSpreadMode": {
|
||||||
"enum": [
|
"enum": [
|
||||||
0,
|
0,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user