Added some key mappings to navigate pages (#95)

* Added some key mappings to navigate pages

* use keyboard event codes

* unused files removed

* use a reference to current page

* fix some bugs with Virtuoso

* add keymapping for space to navigate to next page

* commit my changes

* fix functions not regenerating

* fix partial scroll back to start of page issue

Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
This commit is contained in:
Manchewable 2021-05-24 12:16:05 -07:00 committed by GitHub
parent 16b34f874d
commit 23466cf853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 33 deletions

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* /*
* Copyright (C) Contributors to the Suwayomi project * Copyright (C) Contributors to the Suwayomi project
* *
@ -8,7 +7,6 @@
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import Page from '../Page'; import Page from '../Page';
const useStyles = makeStyles({ const useStyles = makeStyles({
@ -24,13 +22,12 @@ const useStyles = makeStyles({
export default function PagedReader(props: IReaderProps) { export default function PagedReader(props: IReaderProps) {
const { const {
pages, settings, setCurPage, curPage, manga, chapter, nextChapter, pages, settings, setCurPage, curPage, nextChapter,
} = props; } = props;
const classes = useStyles(); const classes = useStyles();
const history = useHistory();
const pageRef = useRef<HTMLDivElement>(null); const selfRef = useRef<HTMLDivElement>(null);
function nextPage() { function nextPage() {
if (curPage < pages.length - 1) { if (curPage < pages.length - 1) {
@ -45,7 +42,11 @@ export default function PagedReader(props: IReaderProps) {
} }
function keyboardControl(e:KeyboardEvent) { function keyboardControl(e:KeyboardEvent) {
switch (e.key) { switch (e.code) {
case 'Space':
e.preventDefault();
nextPage();
break;
case 'ArrowRight': case 'ArrowRight':
nextPage(); nextPage();
break; break;
@ -66,17 +67,17 @@ export default function PagedReader(props: IReaderProps) {
} }
useEffect(() => { useEffect(() => {
document.addEventListener('keyup', keyboardControl, false); document.addEventListener('keydown', keyboardControl);
pageRef.current?.addEventListener('click', clickControl); selfRef.current?.addEventListener('click', clickControl);
return () => { return () => {
document.removeEventListener('keyup', keyboardControl); document.removeEventListener('keydown', keyboardControl);
pageRef.current?.removeEventListener('click', clickControl); selfRef.current?.removeEventListener('click', clickControl);
}; };
}, [curPage, pageRef]); }, [selfRef, curPage]);
return ( return (
<div ref={pageRef} className={classes.reader}> <div ref={selfRef} className={classes.reader}>
<Page <Page
key={curPage} key={curPage}
index={curPage} index={curPage}

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* /*
* Copyright (C) Contributors to the Suwayomi project * Copyright (C) Contributors to the Suwayomi project
* *
@ -7,8 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import Page from '../Page'; import Page from '../Page';
const useStyles = makeStyles({ const useStyles = makeStyles({
@ -23,42 +21,91 @@ const useStyles = makeStyles({
export default function VerticalReader(props: IReaderProps) { export default function VerticalReader(props: IReaderProps) {
const { const {
pages, settings, setCurPage, curPage, manga, chapter, nextChapter, pages, settings, setCurPage, curPage, chapter, nextChapter,
} = props; } = props;
const classes = useStyles(); const classes = useStyles();
const history = useHistory();
const [initialScroll, setInitialScroll] = useState(-1); const selfRef = useRef<HTMLDivElement>(null);
const initialPageRef = useRef<HTMLDivElement>(null); const pagesRef = useRef<HTMLDivElement[]>([]);
function nextPage() {
if (curPage < pages.length - 1) {
pagesRef.current[curPage + 1]?.scrollIntoView();
setCurPage((page) => page + 1);
} else if (settings.loadNextonEnding) {
nextChapter();
}
}
function prevPage() {
if (curPage > 0) {
const rect = pagesRef.current[curPage].getBoundingClientRect();
if (rect.y < 0 && rect.y + rect.height > 0) {
pagesRef.current[curPage]?.scrollIntoView();
} else {
pagesRef.current[curPage - 1]?.scrollIntoView();
setCurPage(curPage - 1);
}
}
}
function keyboardControl(e:KeyboardEvent) {
switch (e.code) {
case 'Space':
e.preventDefault();
nextPage();
break;
case 'ArrowRight':
nextPage();
break;
case 'ArrowLeft':
prevPage();
break;
default:
break;
}
}
function clickControl(e:MouseEvent) {
if (e.clientX > window.innerWidth / 2) {
nextPage();
} else {
prevPage();
}
}
const handleLoadNextonEnding = () => { const handleLoadNextonEnding = () => {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
nextChapter(); nextChapter();
} }
}; };
useEffect(() => { useEffect(() => {
if (settings.loadNextonEnding) { window.addEventListener('scroll', handleLoadNextonEnding); } if (settings.loadNextonEnding) { window.addEventListener('scroll', handleLoadNextonEnding); }
document.addEventListener('keydown', keyboardControl, false);
selfRef.current?.addEventListener('click', clickControl);
return () => { return () => {
window.removeEventListener('scroll', handleLoadNextonEnding); document.removeEventListener('scroll', handleLoadNextonEnding);
document.removeEventListener('keydown', keyboardControl);
selfRef.current?.removeEventListener('click', clickControl);
}; };
}, []); }, [selfRef, curPage]);
useEffect(() => { useEffect(() => {
if ((chapter as IChapter).lastPageRead > -1) { // scroll last read page into view
setInitialScroll((chapter as IChapter).lastPageRead); let initialPage = (chapter as IChapter).lastPageRead;
if (initialPage > pages.length - 1) {
initialPage = pages.length - 1;
}
if (initialPage > -1) {
pagesRef.current[initialPage].scrollIntoView();
} }
}, []); }, []);
useEffect(() => {
if (initialScroll > -1) {
initialPageRef.current?.scrollIntoView();
}
}, [initialScroll, initialPageRef.current]);
return ( return (
<div className={classes.reader}> <div ref={selfRef} className={classes.reader}>
{ {
pages.map((page) => ( pages.map((page) => (
<Page <Page
@ -67,7 +114,7 @@ export default function VerticalReader(props: IReaderProps) {
src={page.src} src={page.src}
setCurPage={setCurPage} setCurPage={setCurPage}
settings={settings} settings={settings}
ref={page.index === initialScroll ? initialPageRef : null} ref={(e:HTMLDivElement) => { pagesRef.current[page.index] = e; }}
/> />
)) ))
} }

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* /*
* Copyright (C) Contributors to the Suwayomi project * Copyright (C) Contributors to the Suwayomi project
* *
@ -11,7 +10,6 @@ import { makeStyles } from '@material-ui/core/styles';
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom'; import { useHistory, useParams } from 'react-router-dom';
import HorizontalPager from '../components/reader/pager/HorizontalPager'; import HorizontalPager from '../components/reader/pager/HorizontalPager';
import Page from '../components/reader/Page';
import PageNumber from '../components/reader/PageNumber'; import PageNumber from '../components/reader/PageNumber';
import WebtoonPager from '../components/reader/pager/PagedPager'; import WebtoonPager from '../components/reader/pager/PagedPager';
import VerticalPager from '../components/reader/pager/VerticalPager'; import VerticalPager from '../components/reader/pager/VerticalPager';
@ -72,6 +70,7 @@ export default function Reader() {
const [chapter, setChapter] = useState<IChapter | IPartialChpter>(initialChapter()); const [chapter, setChapter] = useState<IChapter | IPartialChpter>(initialChapter());
const [curPage, setCurPage] = useState<number>(0); const [curPage, setCurPage] = useState<number>(0);
const { setOverride, setTitle } = useContext(NavbarContext); const { setOverride, setTitle } = useContext(NavbarContext);
useEffect(() => { useEffect(() => {
// make sure settings has all the keys // make sure settings has all the keys
const settingsClone = cloneObject(settings) as any; const settingsClone = cloneObject(settings) as any;