Enhancement: allow setting default pdf zoom (#9017)

This commit is contained in:
shamoon
2025-02-03 21:54:18 -08:00
committed by GitHub
parent 7ab779e78a
commit 2103a499eb
9 changed files with 332 additions and 244 deletions

View File

@@ -41,7 +41,7 @@
<ng-template ngbNavContent>
<div class="row">
<div class="col-xl-6 pe-xl-5">
<h4 i18n>Appearance</h4>
<h5 i18n>Appearance</h5>
<div class="row mb-3">
<div class="col-md-3 col-form-label pt-0">
<span i18n>Display language</span>
@@ -154,28 +154,7 @@
</div>
</div>
<h4 class="mt-4" i18n>Document editing</h4>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Use PDF viewer provided by the browser" i18n-hint hint="This is usually faster for displaying large PDF documents, but it might not work on some browsers." formControlName="useNativePdfViewer"></pngx-input-check>
</div>
</div>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Automatically remove inbox tag(s) on save" formControlName="documentEditingRemoveInboxTags"></pngx-input-check>
</div>
</div>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Show document thumbnail during loading" formControlName="documentEditingOverlayThumbnail"></pngx-input-check>
</div>
</div>
</div>
<div class="col-xl-6 ps-xl-5">
<h4 class="mt-4 mt-md-0" id="update-checking" i18n>Update checking</h4>
<h5 class="mt-3" id="update-checking" i18n>Update checking</h5>
<div class="row mb-3">
<div class="col d-flex flex-row align-items-start">
<pngx-input-check i18n-title title="Enable update checking" formControlName="updateCheckingEnabled"></pngx-input-check>
@@ -193,7 +172,56 @@
</div>
</div>
<h4 class="mt-4" i18n>Bulk editing</h4>
<h5 class="mt-3" i18n>Saved Views</h5>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check>
</div>
</div>
</div>
<div class="col-xl-6 ps-xl-5">
<h5 class="mt-3 mt-md-0" i18n>Document editing</h5>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Use PDF viewer provided by the browser" i18n-hint hint="This is usually faster for displaying large PDF documents, but it might not work on some browsers." formControlName="useNativePdfViewer"></pngx-input-check>
</div>
</div>
<div class="row mb-3">
<div class="col-2">
<span i18n>Default zoom:</span>
</div>
<div class="col">
<select class="form-select" formControlName="pdfViewerDefaultZoom">
<option [ngValue]="ZoomSetting.PageWidth" i18n>Fit width</option>
<option [ngValue]="ZoomSetting.PageFit" i18n>Fit page</option>
</select>
<p class="small text-muted mt-1" i18n>Only applies to the Paperless-ngx PDF viewer.</p>
</div>
</div>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Automatically remove inbox tag(s) on save" formControlName="documentEditingRemoveInboxTags"></pngx-input-check>
</div>
</div>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Show document thumbnail during loading" formControlName="documentEditingOverlayThumbnail"></pngx-input-check>
</div>
</div>
<h5 class="mt-3" i18n>Notes</h5>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Enable notes" formControlName="notesEnabled"></pngx-input-check>
</div>
</div>
<h5 class="mt-3" i18n>Bulk editing</h5>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Show confirmation dialogs" formControlName="bulkEditConfirmationDialogs"></pngx-input-check>
@@ -201,7 +229,7 @@
</div>
</div>
<h4 class="mt-4" i18n>Global search</h4>
<h5 class="mt-3" i18n>Global search</h5>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Do not include advanced search results" formControlName="searchDbOnly"></pngx-input-check>
@@ -224,19 +252,6 @@
</div>
</div>
<h4 class="mt-4" i18n>Saved Views</h4>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check>
</div>
</div>
<h4 class="mt-4" i18n>Notes</h4>
<div class="row mb-3">
<div class="col">
<pngx-input-check i18n-title title="Enable notes" formControlName="notesEnabled"></pngx-input-check>
</div>
</div>
</div>
</div>
@@ -247,7 +262,7 @@
<a ngbNavLink i18n>Permissions</a>
<ng-template ngbNavContent>
<h4 i18n>Default Permissions</h4>
<h5 i18n>Default Permissions</h5>
<div class="row mb-3">
<div class="col">
@@ -329,7 +344,7 @@
<a ngbNavLink i18n>Notifications</a>
<ng-template ngbNavContent>
<h4 i18n>Document processing</h4>
<h5 i18n>Document processing</h5>
<div class="row mb-3">
<div class="col">

View File

@@ -212,7 +212,7 @@ describe('SettingsComponent', () => {
expect(toastErrorSpy).toHaveBeenCalled()
expect(storeSpy).toHaveBeenCalled()
expect(appearanceSettingsSpy).not.toHaveBeenCalled()
expect(setSpy).toHaveBeenCalledTimes(28)
expect(setSpy).toHaveBeenCalledTimes(29)
// succeed
storeSpy.mockReturnValueOnce(of(true))

View File

@@ -63,6 +63,7 @@ import { PermissionsUserComponent } from '../../common/input/permissions/permiss
import { SelectComponent } from '../../common/input/select/select.component'
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
import { SystemStatusDialogComponent } from '../../common/system-status-dialog/system-status-dialog.component'
import { ZoomSetting } from '../../document-detail/document-detail.component'
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
enum SettingsNavIDs {
@@ -125,6 +126,7 @@ export class SettingsComponent
defaultPermsEditUsers: new FormControl(null),
defaultPermsEditGroups: new FormControl(null),
useNativePdfViewer: new FormControl(null),
pdfViewerDefaultZoom: new FormControl(null),
documentEditingRemoveInboxTags: new FormControl(null),
documentEditingOverlayThumbnail: new FormControl(null),
searchDbOnly: new FormControl(null),
@@ -154,6 +156,8 @@ export class SettingsComponent
public readonly GlobalSearchType = GlobalSearchType
public readonly ZoomSetting = ZoomSetting
get systemStatusHasErrors(): boolean {
return (
this.systemStatus.database.status === SystemStatusItemStatus.ERROR ||
@@ -276,6 +280,9 @@ export class SettingsComponent
useNativePdfViewer: this.settings.get(
SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER
),
pdfViewerDefaultZoom: this.settings.get(
SETTINGS_KEYS.PDF_VIEWER_ZOOM_SETTING
),
displayLanguage: this.settings.getLanguage(),
dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE),
dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT),
@@ -435,6 +442,10 @@ export class SettingsComponent
SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER,
this.settingsForm.value.useNativePdfViewer
)
this.settings.set(
SETTINGS_KEYS.PDF_VIEWER_ZOOM_SETTING,
this.settingsForm.value.pdfViewerDefaultZoom
)
this.settings.set(
SETTINGS_KEYS.DATE_LOCALE,
this.settingsForm.value.dateLocale

View File

@@ -9,9 +9,9 @@
}
<div class="input-group input-group-sm me-md-5 d-none d-md-flex">
<button class="btn btn-outline-secondary" (click)="decreaseZoom()" i18n>-</button>
<select class="form-select" (change)="onZoomSelect($event)">
<select class="form-select" (change)="setZoom($event.target.value)">
@for (setting of zoomSettings; track setting) {
<option [value]="setting" [selected]="previewZoomSetting === setting">
<option [value]="setting" [attr.selected]="isZoomSelected(setting) ? 'selected' : null">
{{ getZoomSettingTitle(setting) }}
</option>
}
@@ -356,9 +356,9 @@
</ng-template>
<ng-template #previewContent>
<div class="thumb-preview position-absolute pe-none" [class.fade]="previewLoaded">
<div class="thumb-preview position-absolute pe-none text-center" [class.fade]="previewLoaded">
@if (showThumbnailOverlay) {
<img [src]="thumbUrl | safeUrl" class="" width="100%" height="auto" alt="Document loading..." i18n-alt />
<img [src]="thumbUrl | safeUrl" class="mx-auto" [attr.width]="previewZoomScale === 'page-fit' ? 'auto' : '100%'" [attr.height]="previewZoomScale === 'page-fit' ? '100%' : 'auto'" alt="Document loading..." i18n-alt />
}
<div class="position-absolute top-0 start-0 m-2 p-2 d-flex align-items-center justify-content-center">
<div>

View File

@@ -85,5 +85,8 @@ textarea.rtl {
> img {
filter: blur(1px);
max-width: 100%;
object-fit: contain;
object-position: top;
}
}

View File

@@ -62,7 +62,10 @@ import { ToastService } from 'src/app/services/toast.service'
import { environment } from 'src/environments/environment'
import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'
import { CustomFieldsDropdownComponent } from '../common/custom-fields-dropdown/custom-fields-dropdown.component'
import { DocumentDetailComponent } from './document-detail.component'
import {
DocumentDetailComponent,
ZoomSetting,
} from './document-detail.component'
const doc: Document = {
id: 3,
@@ -753,7 +756,7 @@ describe('DocumentDetailComponent', () => {
it('should support zoom controls', () => {
initNormally()
component.onZoomSelect({ target: { value: '1' } } as any) // from select
component.setZoom(ZoomSetting.One) // from select
expect(component.previewZoomSetting).toEqual('1')
component.increaseZoom()
expect(component.previewZoomSetting).toEqual('1.5')
@@ -761,18 +764,18 @@ describe('DocumentDetailComponent', () => {
expect(component.previewZoomSetting).toEqual('2')
component.decreaseZoom()
expect(component.previewZoomSetting).toEqual('1.5')
component.onZoomSelect({ target: { value: '1' } } as any) // from select
component.setZoom(ZoomSetting.One) // from select
component.decreaseZoom()
expect(component.previewZoomSetting).toEqual('.75')
component.onZoomSelect({ target: { value: 'page-fit' } } as any) // from select
component.setZoom(ZoomSetting.PageFit) // from select
expect(component.previewZoomScale).toEqual('page-fit')
expect(component.previewZoomSetting).toEqual('1')
component.increaseZoom()
expect(component.previewZoomSetting).toEqual('1.5')
expect(component.previewZoomScale).toEqual('page-width')
component.onZoomSelect({ target: { value: 'page-fit' } } as any) // from select
component.setZoom(ZoomSetting.PageFit) // from select
expect(component.previewZoomScale).toEqual('page-fit')
expect(component.previewZoomSetting).toEqual('1')
component.decreaseZoom()
@@ -780,6 +783,19 @@ describe('DocumentDetailComponent', () => {
expect(component.previewZoomScale).toEqual('page-width')
})
it('should select correct zoom setting in dropdown', () => {
initNormally()
component.setZoom(ZoomSetting.PageFit)
expect(component.isZoomSelected(ZoomSetting.PageFit)).toBeTruthy()
expect(component.isZoomSelected(ZoomSetting.One)).toBeFalsy()
component.setZoom(ZoomSetting.PageWidth)
expect(component.isZoomSelected(ZoomSetting.One)).toBeTruthy()
expect(component.isZoomSelected(ZoomSetting.PageFit)).toBeFalsy()
component.setZoom(ZoomSetting.Quarter)
expect(component.isZoomSelected(ZoomSetting.Quarter)).toBeTruthy()
expect(component.isZoomSelected(ZoomSetting.PageFit)).toBeFalsy()
})
it('should support updating notes dynamically', () => {
const notes = [
{

View File

@@ -124,7 +124,7 @@ enum ContentRenderType {
TIFF = 'tiff',
}
enum ZoomSetting {
export enum ZoomSetting {
PageFit = 'page-fit',
PageWidth = 'page-width',
Quarter = '.25',
@@ -328,6 +328,7 @@ export class DocumentDetailComponent
}
ngOnInit(): void {
this.setZoom(this.settings.get(SETTINGS_KEYS.PDF_VIEWER_ZOOM_SETTING))
this.documentForm.valueChanges
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(() => {
@@ -1072,14 +1073,13 @@ export class DocumentDetailComponent
}
}
onZoomSelect(event: Event) {
const setting = (event.target as HTMLSelectElement)?.value as ZoomSetting
if (ZoomSetting.PageFit === setting) {
this.previewZoomSetting = ZoomSetting.One
setZoom(setting: ZoomSetting) {
if (ZoomSetting.PageFit === setting || ZoomSetting.PageWidth === setting) {
this.previewZoomScale = setting
this.previewZoomSetting = ZoomSetting.One
} else {
this.previewZoomScale = ZoomSetting.PageWidth
this.previewZoomSetting = setting
this.previewZoomScale = ZoomSetting.PageWidth
}
}
@@ -1089,6 +1089,14 @@ export class DocumentDetailComponent
)
}
isZoomSelected(setting: ZoomSetting): boolean {
if (this.previewZoomScale === ZoomSetting.PageFit) {
return setting === ZoomSetting.PageFit
}
return this.previewZoomSetting === setting
}
getZoomSettingTitle(setting: ZoomSetting): string {
switch (setting) {
case ZoomSetting.PageFit:

View File

@@ -33,6 +33,8 @@ export const SETTINGS_KEYS = {
DARK_MODE_THUMB_INVERTED: 'general-settings:dark-mode:thumb-inverted',
THEME_COLOR: 'general-settings:theme:color',
USE_NATIVE_PDF_VIEWER: 'general-settings:document-details:native-pdf-viewer',
PDF_VIEWER_ZOOM_SETTING:
'general-settings:document-details:pdf-viewer-zoom-setting',
DATE_LOCALE: 'general-settings:date-display:date-locale',
DATE_FORMAT: 'general-settings:date-display:date-format',
NOTIFICATIONS_CONSUMER_NEW_DOCUMENT:
@@ -269,4 +271,9 @@ export const SETTINGS: UiSetting[] = [
type: 'boolean',
default: false,
},
{
key: SETTINGS_KEYS.PDF_VIEWER_ZOOM_SETTING,
type: 'string',
default: 'page-width', // ZoomSetting from 'document-detail.component'
},
]