Swipe Issues (#1745)

* Updated theme support to be able to customize the tile color dynamically from a theme via --tile-color. In addition, --theme-color will update apple-mobile-web-app-status-bar-style as well as the non-apple variants

* Removed --manga-reader-bg-color as it wasn't used anywhere. Fixed double pagination on swipe.

* Cleaned up some dead threshold code for swipe.

* Started refactoring tests to use an abstract test class. Stopping because I should do on the .net 7 branch to avoid large merge conflicts. Tests need to be re-designed so they can run in parallel.

* Fixed a bug in reading lists where when deleting an item, order could be miscalculated.

* Started adding new information for stat service. Refactored time spent reading to be more accurate by taking average time against how much of the chapter the user has read.

* Hooked up total time reading at server stat level. Don't show fancy graphs on mobile.

* Added new stats for v0.7

* Added a test for Clearing want to read

* Fixed a few tests that weren't resetting state between runs

* Fixed some broken unit tests

* Ensure all Series queries sort by a case invariant string.

* Added more aggressive caching of images. This will result in a min delay on pages after a cover is changed.

* Fixed a bug where if during new word count calculation, new word count is zero, restoring the old count wasn't working.

* Cleaned up some of the code for getting time estimates

* Fixed a bug where triggering swipe right wasn't working when there was no scroll

* Delete the temp folder for creating a download after a full zip is created.
This commit is contained in:
Joe Milazzo 2023-01-12 19:24:58 -06:00 committed by GitHub
parent 3d6de68089
commit 549e52b458
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 488 additions and 339 deletions

View file

@ -64,15 +64,23 @@ export class ThemeService implements OnDestroy {
getColorScheme() {
return getComputedStyle(this.document.body).getPropertyValue('--color-scheme').trim();
}
/**
* --theme-color from theme. Updates the meta tag
* @returns
*/
getThemeColor() {
return getComputedStyle(this.document.body).getPropertyValue('--theme-color').trim();
}
/**
* --theme-color from theme. Updates the meta tag
* @returns
*/
getThemeColor() {
return getComputedStyle(this.document.body).getPropertyValue('--theme-color').trim();
}
/**
* --msapplication-TileColor from theme. Updates the meta tag
* @returns
*/
getTileColor() {
return getComputedStyle(this.document.body).getPropertyValue('--title-color').trim();
}
getCssVariable(variable: string) {
return getComputedStyle(this.document.body).getPropertyValue(variable).trim();
}
@ -155,6 +163,12 @@ export class ThemeService implements OnDestroy {
const themeColor = this.getThemeColor();
if (themeColor) {
this.document.querySelector('meta[name="theme-color"]')?.setAttribute('content', themeColor);
this.document.querySelector('meta[name="apple-mobile-web-app-status-bar-style"]')?.setAttribute('content', themeColor);
}
const tileColor = this.getTileColor();
if (themeColor) {
this.document.querySelector('meta[name="msapplication-TileColor"]')?.setAttribute('content', themeColor);
}
const colorScheme = this.getColorScheme();

View file

@ -973,11 +973,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
}
triggerSwipePagination(direction: KeyDirection) {
if (this.readingDirection === ReadingDirection.LeftToRight) {
if (direction === KeyDirection.Right)
this.readingDirection === ReadingDirection.LeftToRight ? this.nextPage() : this.prevPage();
}
switch(direction) {
case KeyDirection.Down:
this.nextPage();
@ -996,8 +991,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
}
onSwipeEnd(event: SwipeEvent) {
const threshold = .12;
// Positive number means swiping right/down, negative means left
switch (this.readerMode) {
case ReaderMode.Webtoon: break;
@ -1014,6 +1007,10 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
// We just came from a swipe where pagination was required and we are now at the end of the swipe, so make the user do it once more
if (direction === KeyDirection.Right) {
this.hasHitZeroScroll = false;
if (scrollLeft === 0 && this.ReadingAreaWidth === 0) {
this.triggerSwipePagination(direction);
return;
}
if (!this.hasHitRightScroll && this.checkIfPaginationAllowed(direction)) {
this.hasHitRightScroll = true;
return;
@ -1036,7 +1033,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
return;
}
console.log('Next page triggered');
this.triggerSwipePagination(direction);
break;
}
@ -1072,32 +1068,8 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
return;
}
console.log('Next page triggered');
this.triggerSwipePagination(direction);
break;
const height = (this.readingArea?.nativeElement.scrollHeight === this.readingArea?.nativeElement.clientHeight)
? this.readingArea?.nativeElement.clientHeight : this.ReadingAreaHeight;
if (direction === KeyDirection.Down && this.readingArea?.nativeElement?.scrollTop === height && this.prevScrollTop != 0) {
this.prevScrollTop = 0;
return;
}
if (direction === KeyDirection.Up && this.readingArea?.nativeElement?.scrollTop === 0 && this.prevScrollTop != 0) {
this.prevScrollTop = 0;
return;
}
const thresholdMet = Math.abs(event.distance) >= height * threshold;
if (!thresholdMet) return;
this.triggerSwipePagination(direction);
}
}
}

View file

@ -3,7 +3,7 @@ import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
import { ScalingOption } from 'src/app/_models/preferences/scaling-option';
import { ReaderService } from 'src/app/_services/reader.service';
import { ChapterInfo } from '../_models/chapter-info';
import { DimensionMap, FileDimension } from '../_models/file-dimension';
import { DimensionMap } from '../_models/file-dimension';
import { FITTING_OPTION } from '../_models/reader-enums';
@Injectable({

View file

@ -17,16 +17,7 @@
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container>
<div class="col-auto mb-2">
<app-icon-and-title label="Total Chapters" [clickable]="false" fontClasses="fa-regular fa-file-lines" title="Total Chapters">
{{stats.chapterCount | compactNumber}} Chapters
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container>
<div class="col-auto mb-2">
<app-icon-and-title label="Total Files" [clickable]="false" fontClasses="fa-regular fa-file" title="Total Files">
@ -69,6 +60,15 @@
{{stats.totalPeople | compactNumber}} People
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>
</ng-container>
<ng-container>
<div class="col-auto mb-2">
<app-icon-and-title label="Total Read Time" [clickable]="false" fontClasses="fas fa-eye" title="Total Read Time">
{{stats.totalReadingTime | compactNumber}} Hours
</app-icon-and-title>
</div>
</ng-container>
</div>
@ -91,28 +91,33 @@
</div>
</div>
<div class="row g-0 pt-2 pb-2 ">
<app-top-readers></app-top-readers>
</div>
<div class="row g-0 pt-4 pb-2" style="height: 242px">
<div class="col-md-6 col-sm-12">
<app-file-breakdown-stats></app-file-breakdown-stats>
<ng-container *ngIf="breakpoint$ | async as bp">
<div class="row g-0 pt-2 pb-2" *ngIf="bp > Breakpoint.Mobile">
<app-top-readers></app-top-readers>
</div>
<div class="col-md-6 col-sm-12">
<app-publication-status-stats></app-publication-status-stats>
</div>
</div>
<div class="row g-0 pt-4 pb-2 " style="height: 242px">
<div class="col-md-12 col-sm-12 mt-4 pt-2">
<app-read-by-day-and [isAdmin]="true"></app-read-by-day-and>
</div>
</div>
<div class="row g-0 pt-4 pb-2 " style="height: 242px">
<div class="col-md-12 col-sm-12 mt-4 pt-2">
<app-day-breakdown></app-day-breakdown>
<div class="row g-0 pt-4 pb-2" style="height: 242px" *ngIf="bp > Breakpoint.Mobile">
<div class="col-md-6 col-sm-12">
<app-file-breakdown-stats></app-file-breakdown-stats>
</div>
<div class="col-md-6 col-sm-12">
<app-publication-status-stats></app-publication-status-stats>
</div>
</div>
</div>
<div class="row g-0 pt-4 pb-2 " style="height: 242px" *ngIf="bp > Breakpoint.Mobile">
<div class="col-md-12 col-sm-12 mt-4 pt-2">
<app-read-by-day-and [isAdmin]="true"></app-read-by-day-and>
</div>
</div>
<div class="row g-0 pt-4 pb-2 " style="height: 242px" *ngIf="bp > Breakpoint.Mobile">
<div class="col-md-12 col-sm-12 mt-4 pt-2">
<app-day-breakdown></app-day-breakdown>
</div>
</div>
</ng-container>
</div>

View file

@ -1,8 +1,9 @@
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, Component, HostListener, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { map, Observable, shareReplay, Subject, takeUntil, tap } from 'rxjs';
import { BehaviorSubject, map, Observable, of, shareReplay, Subject, takeUntil, tap } from 'rxjs';
import { FilterQueryParam } from 'src/app/shared/_services/filter-utilities.service';
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
import { Series } from 'src/app/_models/series';
import { ImageService } from 'src/app/_services/image.service';
import { MetadataService } from 'src/app/_services/metadata.service';
@ -32,13 +33,27 @@ export class ServerStatsComponent implements OnInit, OnDestroy {
this.router.navigate(['library', series.libraryId, 'series', series.id]);
}
breakpointSubject = new BehaviorSubject<Breakpoint>(1);
breakpoint$: Observable<Breakpoint> = this.breakpointSubject.asObservable();
@HostListener('window:resize', ['$event'])
@HostListener('window:orientationchange', ['$event'])
onResize() {
this.breakpointSubject.next(this.utilityService.getActiveBreakpoint());
}
get Breakpoint() { return Breakpoint; }
constructor(private statService: StatisticsService, private router: Router, private imageService: ImageService,
private metadataService: MetadataService, private modalService: NgbModal) {
private metadataService: MetadataService, private modalService: NgbModal, private utilityService: UtilityService) {
this.seriesImage = (data: PieDataItem) => {
if (data.extra) return this.imageService.getSeriesCoverImage(data.extra.id);
return '';
}
this.breakpointSubject.next(this.utilityService.getActiveBreakpoint());
this.stats$ = this.statService.getServerStatistics().pipe(takeUntil(this.onDestroy), shareReplay());
this.releaseYears$ = this.statService.getTopYears().pipe(takeUntil(this.onDestroy));
this.mostActiveUsers$ = this.stats$.pipe(

View file

@ -20,7 +20,7 @@
<ng-container >
<div class="col-auto mb-2">
<app-icon-and-title label="Time Spent Reading" [clickable]="false" fontClasses="fas fa-eye" title="Time Spent Reading">
{{timeSpentReading}} hours
{{timeSpentReading | compactNumber}} hours
</app-icon-and-title>
</div>
<div class="vr d-none d-lg-block m-2"></div>

View file

@ -12,6 +12,7 @@ export interface ServerStatistics {
totalGenres: number;
totalTags: number;
totalPeople: number;
totalReadingTime: number;
mostActiveUsers: Array<StatCount<User>>;
mostActiveLibraries: Array<StatCount<Library>>;
mostReadSeries: Array<StatCount<Series>>;

View file

@ -13,7 +13,7 @@
<meta name="msapplication-TileColor" content="#4ac694">
<meta name="msapplication-config" content="assets/icons/browserconfig.xml">
<meta name="theme-color" content="#000000">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-status-bar-style" content="#000000">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">

View file

@ -1,7 +1,6 @@
//
:root, :root .default {
--theme-color: #000000;
--color-scheme: dark;
/* Base colors */
--primary-color: #4ac694;
--primary-color-dark-shade: #3B9E76;
--primary-color-darker-shade: #338A67;
@ -11,6 +10,11 @@
--body-text-color: #efefef;
--btn-icon-filter: invert(1) grayscale(100%) brightness(200%);
--primary-color-scrollbar: rgba(74,198,148,0.75);
/* Meta and Globals */
--theme-color: #000000;
--color-scheme: dark;
--tile-color: var(--primary-color);
/* Navbar */
@ -116,7 +120,7 @@
/* List items */
--list-group-item-text-color: var(--body-text-color); /*rgba(74, 198, 148, 0.9)*/
--list-group-item-text-color: var(--body-text-color);
--list-group-item-bg-color: #343a40;
--list-group-item-border-color: rgba(239, 239, 239, 0.125);
--list-group-hover-text-color: white;
@ -176,6 +180,7 @@
--ratingstar-star-filled: var(--primary-color);
/* Global */
//--hr-color: transparent;
--hr-color: rgba(239, 239, 239, 0.125);
--accent-bg-color: rgba(1, 4, 9, 0.5);
--accent-text-color: lightgrey;
@ -207,7 +212,6 @@
--manga-reader-overlay-filter: blur(10px);
--manga-reader-overlay-bg-color: rgba(0,0,0,0.5);
--manga-reader-overlay-text-color: white;
--manga-reader-bg-color: black; // TODO: Remove this
--manga-reader-next-highlight-bg-color: rgba(65, 225, 100, 0.5);
--manga-reader-prev-highlight-bg-color: rgba(65, 105, 225, 0.5);
@ -242,7 +246,4 @@
/* List Card Item */
--card-list-item-bg-color: linear-gradient(180deg, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.15) 1%, rgba(0,0,0,0) 100%);
/* Bootstrap overrides */
--hr-color: transparent;
}