Reader Fixes and Enhancements (#880)

* Don't show an exception when bookmarking doesn't have anything to change.

* Cleaned up the bookmark code a bit.

* Implemented fullscreen mode in the web reader. Refactored User Settings to move Password and 3rd Party Clients to a tab rather than accordion. Removed color filters for web reader.

* Implemented fullscreen mode into book reader

* Added some code for toggling fullscreen which re-renders the screen to ensure the fitting works optimially

* Fixed an issue where moving from FitToScreen -> Split (L/R) wouldn't render the screen correctly due to canvas not being reset.

* Fixed bad optimization and scaling when drawing fit to screen

* Removed left/right highlights on page direction change in favor for icons. Double arrow will dictate the page change.

* Reduced overlay auto close time to 3 seconds

* Updated the paginging direction overlay to use icons and colors. Added a blur effect on menus

* Removed debug flags
This commit is contained in:
Joseph Milazzo 2022-01-02 18:10:37 -07:00 committed by GitHub
parent ca5c67020e
commit 720c52f494
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 1620 additions and 166 deletions

View file

@ -2,7 +2,7 @@
<h2>User Dashboard</h2>
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs nav-pills">
<li *ngFor="let tab of tabs" [ngbNavItem]="tab">
<a ngbNavLink routerLink="." [fragment]="tab.fragment">{{ tab.title | titlecase }}</a>
<a ngbNavLink routerLink="." [fragment]="tab.fragment">{{ tab.title | sentenceCase }}</a>
<ng-template ngbNavContent>
<ng-container *ngIf="tab.fragment === ''">
<p>
@ -48,7 +48,7 @@
</ng-template>
<ng-template ngbPanelContent>
<form [formGroup]="settingsForm" *ngIf="user !== undefined">
<h3 id="manga-header">Manga</h3>
<h3 id="manga-header">Image Reader</h3>
<div class="form-group">
<label for="settings-reading-direction">Reading Direction</label>&nbsp;<i class="fa fa-info-circle" aria-hidden="true" placement="right" [ngbTooltip]="readingDirectionTooltip" role="button" tabindex="0"></i>
<ng-template #readingDirectionTooltip>Direction to click to move to next page. Right to Left means you click on left side of screen to move to next page.</ng-template>
@ -95,7 +95,7 @@
</div>
</div>
<hr>
<h3>Books</h3>
<h3>Book Reader</h3>
<div class="form-group">
<label id="dark-mode-label">Dark Mode</label>
<div class="form-group">
@ -166,53 +166,8 @@
</ng-template>
</ngb-panel>
<ngb-panel id="password-panel" title="Password">
<ng-template ngbPanelHeader>
<div class="d-flex align-items-center justify-content-between">
<button ngbPanelToggle class="btn container-fluid text-left pl-0 accordion-header">Password</button>
<span class="pull-right"><i class="fa fa-angle-{{acc.isExpanded('password-panel') ? 'down' : 'up'}}" aria-hidden="true"></i></span>
</div>
</ng-template>
<ng-template ngbPanelContent>
<ng-container *ngIf="isAuthenticationEnabled || isAdmin; else authDisabled">
<p>Change your Password</p>
<div class="alert alert-danger" role="alert" *ngIf="resetPasswordErrors.length > 0">
<div *ngFor="let error of resetPasswordErrors">{{error}}</div>
</div>
<form [formGroup]="passwordChangeForm">
<div class="form-group">
<label for="new-password">New Password</label>
<input class="form-control" type="password" id="new-password" formControlName="password" required>
<div id="password-validations" class="invalid-feedback" *ngIf="passwordChangeForm.dirty || passwordChangeForm.touched">
<div *ngIf="password?.errors?.required">
This field is required
</div>
</div>
</div>
<div class="form-group">
<label for="confirm-password">Confirm Password</label>
<input class="form-control" type="password" id="confirm-password" formControlName="confirmPassword" aria-describedby="password-validations" required>
<div id="password-validations" class="invalid-feedback" *ngIf="passwordChangeForm.dirty || passwordChangeForm.touched">
<div *ngIf="!passwordsMatch">
Passwords must match
</div>
<div *ngIf="confirmPassword?.errors?.required">
This field is required
</div>
</div>
</div>
<div class="float-right mb-3">
<button type="button" class="btn btn-secondary mr-2" aria-describedby="password-panel" (click)="resetPasswordForm()">Reset</button>
<button type="submit" class="btn btn-primary" aria-describedby="password-panel" (click)="savePasswordForm()" [disabled]="!passwordChangeForm.valid || !(passwordChangeForm.dirty || passwordChangeForm.touched)">Save</button>
</div>
</form>
</ng-container>
<ng-template #authDisabled>
<p class="text-warning">Authentication is disabled on this server. A password is not required to authenticate.</p>
</ng-template>
</ng-template>
</ngb-panel>
<!--
<ngb-panel id="api-panel" title="3rd Party Clients">
<ng-template ngbPanelHeader>
<div class="d-flex align-items-center justify-content-between">
@ -226,12 +181,56 @@
<app-api-key tooltipText="The API key is like a password. Keep it secret, Keep it safe."></app-api-key>
<app-api-key title="OPDS URL" [showRefresh]="false" [transform]="makeUrl"></app-api-key>
</ng-template>
</ngb-panel>
</ngb-panel> -->
</ngb-accordion>
</ng-container>
<ng-container *ngIf="tab.fragment === 'bookmarks'">
<app-series-bookmarks></app-series-bookmarks>
</ng-container>
<ng-container *ngIf="tab.fragment === 'password'">
<ng-container *ngIf="isAuthenticationEnabled || isAdmin; else authDisabled">
<p>Change your Password</p>
<div class="alert alert-danger" role="alert" *ngIf="resetPasswordErrors.length > 0">
<div *ngFor="let error of resetPasswordErrors">{{error}}</div>
</div>
<form [formGroup]="passwordChangeForm">
<div class="form-group">
<label for="new-password">New Password</label>
<input class="form-control" type="password" id="new-password" formControlName="password" required>
<div id="password-validations" class="invalid-feedback" *ngIf="passwordChangeForm.dirty || passwordChangeForm.touched">
<div *ngIf="password?.errors?.required">
This field is required
</div>
</div>
</div>
<div class="form-group">
<label for="confirm-password">Confirm Password</label>
<input class="form-control" type="password" id="confirm-password" formControlName="confirmPassword" aria-describedby="password-validations" required>
<div id="password-validations" class="invalid-feedback" *ngIf="passwordChangeForm.dirty || passwordChangeForm.touched">
<div *ngIf="!passwordsMatch">
Passwords must match
</div>
<div *ngIf="confirmPassword?.errors?.required">
This field is required
</div>
</div>
</div>
<div class="float-right mb-3">
<button type="button" class="btn btn-secondary mr-2" aria-describedby="password-panel" (click)="resetPasswordForm()">Reset</button>
<button type="submit" class="btn btn-primary" aria-describedby="password-panel" (click)="savePasswordForm()" [disabled]="!passwordChangeForm.valid || !(passwordChangeForm.dirty || passwordChangeForm.touched)">Save</button>
</div>
</form>
</ng-container>
<ng-template #authDisabled>
<p class="text-warning">Authentication is disabled on this server. A password is not required to authenticate.</p>
</ng-template>
</ng-container>
<ng-container *ngIf="tab.fragment === 'clients'">
<p>All 3rd Party clients will either use the API key or the Connection Url below. These are like passwords, keep it private.</p>
<p class="alert alert-warning" role="alert" *ngIf="!opdsEnabled">OPDS is not enabled on this server.</p>
<app-api-key tooltipText="The API key is like a password. Keep it secret, Keep it safe."></app-api-key>
<app-api-key title="OPDS URL" [showRefresh]="false" [transform]="makeUrl"></app-api-key>
</ng-container>
</ng-template>
</li>
</ul>

View file

@ -55,6 +55,8 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
tabs: Array<{title: string, fragment: string}> = [
{title: 'Preferences', fragment: ''},
{title: 'Bookmarks', fragment: 'bookmarks'},
{title: 'Password', fragment: 'password'},
{title: '3rd Party Clients', fragment: 'clients'},
];
active = this.tabs[0];
opdsEnabled: boolean = false;

View file

@ -7,6 +7,7 @@ import { ReactiveFormsModule } from '@angular/forms';
import { NgxSliderModule } from '@angular-slider/ngx-slider';
import { UserSettingsRoutingModule } from './user-settings-routing.module';
import { ApiKeyComponent } from './api-key/api-key.component';
import { SharedModule } from '../shared/shared.module';
@ -24,6 +25,7 @@ import { ApiKeyComponent } from './api-key/api-key.component';
NgbTooltipModule,
NgxSliderModule,
UserSettingsRoutingModule,
SharedModule // SentenceCase pipe
]
})
export class UserSettingsModule { }