mirror of
https://github.com/koodo-reader/koodo-reader.git
synced 2026-06-20 05:40:18 -04:00
fix bug
Former-commit-id: 180a61da604f847884b08890d2df33122625691c
This commit is contained in:
8
main.js
8
main.js
@@ -1,6 +1,7 @@
|
||||
const { app, BrowserWindow, nativeImage } = require("electron");
|
||||
const { app, BrowserWindow, Menu, remote, ipcMain } = require("electron");
|
||||
const { ebtMain } = require("electron-baidu-tongji");
|
||||
const path = require("path");
|
||||
const isDev = require("electron-is-dev");
|
||||
let mainWin;
|
||||
let readerWindow;
|
||||
const singleInstance = app.requestSingleInstanceLock();
|
||||
@@ -38,9 +39,8 @@ app.on("ready", () => {
|
||||
};
|
||||
|
||||
mainWin = new BrowserWindow(option);
|
||||
const isDev = require("electron-is-dev");
|
||||
|
||||
if (!isDev) {
|
||||
const { Menu } = require("electron");
|
||||
Menu.setApplicationMenu(null);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ app.on("ready", () => {
|
||||
: `file://${path.join(__dirname, "./build/index.html")}`;
|
||||
|
||||
mainWin.loadURL(urlLocation);
|
||||
const { remote, ipcMain } = require("electron");
|
||||
|
||||
ebtMain(ipcMain, isDev);
|
||||
mainWin.on("close", () => {
|
||||
mainWin = null;
|
||||
|
||||
371
src/containers/_epubReader/component.tsx
Normal file
371
src/containers/_epubReader/component.tsx
Normal file
@@ -0,0 +1,371 @@
|
||||
import React from "react";
|
||||
import EpubViewer from "../epubViewer";
|
||||
import Background from "../background";
|
||||
import SettingPanel from "../panels/settingPanel";
|
||||
import NavigationPanel from "../panels/navigationPanel";
|
||||
import OperationPanel from "../panels/operationPanel";
|
||||
import MessageBox from "../messageBox";
|
||||
import ProgressPanel from "../panels/progressPanel";
|
||||
import { ReaderProps, ReaderState } from "./interface";
|
||||
import { MouseEvent } from "../../utils/mouseEvent";
|
||||
import OtherUtil from "../../utils/otherUtil";
|
||||
import ReadingTime from "../../utils/readUtils/readingTime";
|
||||
|
||||
class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
messageTimer!: NodeJS.Timeout;
|
||||
tickTimer!: NodeJS.Timeout;
|
||||
rendition: any;
|
||||
|
||||
constructor(props: ReaderProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpenRightPanel:
|
||||
OtherUtil.getReaderConfig("isSettingLocked") === "yes" ? true : false,
|
||||
isOpenTopPanel: false,
|
||||
isOpenBottomPanel: false,
|
||||
isOpenLeftPanel:
|
||||
OtherUtil.getReaderConfig("isNavLocked") === "yes" ? true : false,
|
||||
isMessage: false,
|
||||
rendition: null,
|
||||
scale: OtherUtil.getReaderConfig("scale") || 1,
|
||||
margin: parseInt(OtherUtil.getReaderConfig("margin")) || 30,
|
||||
time: ReadingTime.getTime(this.props.currentBook.key),
|
||||
isTouch: OtherUtil.getReaderConfig("isTouch") === "yes",
|
||||
readerMode: OtherUtil.getReaderConfig("readerMode") || "double",
|
||||
};
|
||||
}
|
||||
componentWillMount() {
|
||||
this.props.handleFetchBookmarks();
|
||||
this.props.handleFetchPercentage(this.props.currentBook);
|
||||
this.props.handleFetchNotes();
|
||||
this.props.handleFetchBooks();
|
||||
this.props.handleFetchChapters(this.props.currentEpub);
|
||||
}
|
||||
UNSAFE_componentWillReceiveProps(nextProps: ReaderProps) {
|
||||
this.setState({
|
||||
isMessage: nextProps.isMessage,
|
||||
});
|
||||
|
||||
//控制消息提示两秒之后消失
|
||||
if (nextProps.isMessage) {
|
||||
this.messageTimer = global.setTimeout(() => {
|
||||
this.props.handleMessageBox(false);
|
||||
this.setState({ isMessage: false });
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.handleRenderBook();
|
||||
this.props.handleRenderFunc(this.handleRenderBook);
|
||||
window.addEventListener("resize", () => {
|
||||
this.handleRenderBook();
|
||||
});
|
||||
this.tickTimer = global.setInterval(() => {
|
||||
let time = this.state.time;
|
||||
time += 1;
|
||||
let page = document.querySelector("#page-area");
|
||||
//解决快速翻页过程中图书消失的bug
|
||||
let renderedBook = document.querySelector(".epub-view");
|
||||
if (
|
||||
renderedBook &&
|
||||
!renderedBook.innerHTML &&
|
||||
this.state.readerMode !== "continuous"
|
||||
) {
|
||||
this.handleRenderBook();
|
||||
}
|
||||
let ele = page!.getElementsByClassName("epub-container")[0];
|
||||
if (page!.getElementsByClassName("epub-container").length > 1 && ele) {
|
||||
ele.parentNode?.removeChild(ele);
|
||||
}
|
||||
this.setState({ time });
|
||||
this.handleRecord();
|
||||
}, 1000);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.tickTimer);
|
||||
}
|
||||
handleRenderBook = () => {
|
||||
let page = document.querySelector("#page-area");
|
||||
let epub = this.props.currentEpub;
|
||||
if (page!.innerHTML) {
|
||||
page!.innerHTML = "";
|
||||
}
|
||||
|
||||
this.setState({ rendition: null }, () => {
|
||||
(window as any).rangy.init(); // 初始化
|
||||
this.rendition = epub.renderTo(page, {
|
||||
manager:
|
||||
this.state.readerMode === "continuous" ? "continuous" : "default",
|
||||
flow: this.state.readerMode === "continuous" ? "scrolled" : "auto",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
snap: true,
|
||||
spread:
|
||||
OtherUtil.getReaderConfig("readerMode") === "single" ? "none" : "",
|
||||
});
|
||||
this.setState({ rendition: this.rendition });
|
||||
this.state.readerMode !== "continuous" && MouseEvent(this.rendition); // 绑定事件
|
||||
});
|
||||
};
|
||||
handleRecord() {
|
||||
OtherUtil.setReaderConfig("isFullScreen", "no");
|
||||
|
||||
OtherUtil.setReaderConfig("windowWidth", document.body.clientWidth + "");
|
||||
OtherUtil.setReaderConfig("windowHeight", document.body.clientHeight + "");
|
||||
OtherUtil.setReaderConfig("windowX", window.screenX + "");
|
||||
OtherUtil.setReaderConfig("windowY", window.screenY + "");
|
||||
}
|
||||
//进入阅读器
|
||||
handleEnterReader = (position: string) => {
|
||||
//控制上下左右的菜单的显示
|
||||
switch (position) {
|
||||
case "right":
|
||||
this.setState({
|
||||
isOpenRightPanel: this.state.isOpenRightPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
case "left":
|
||||
this.setState({
|
||||
isOpenLeftPanel: this.state.isOpenLeftPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
case "top":
|
||||
this.setState({
|
||||
isOpenTopPanel: this.state.isOpenTopPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
case "bottom":
|
||||
this.setState({
|
||||
isOpenBottomPanel: this.state.isOpenBottomPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
//退出阅读器
|
||||
handleLeaveReader = (position: string) => {
|
||||
//控制上下左右的菜单的显示
|
||||
switch (position) {
|
||||
case "right":
|
||||
if (OtherUtil.getReaderConfig("isSettingLocked") === "yes") {
|
||||
break;
|
||||
} else {
|
||||
this.setState({ isOpenRightPanel: false });
|
||||
break;
|
||||
}
|
||||
|
||||
case "left":
|
||||
if (OtherUtil.getReaderConfig("isNavLocked") === "yes") {
|
||||
break;
|
||||
} else {
|
||||
this.setState({ isOpenLeftPanel: false });
|
||||
break;
|
||||
}
|
||||
case "top":
|
||||
this.setState({ isOpenTopPanel: false });
|
||||
break;
|
||||
case "bottom":
|
||||
this.setState({ isOpenBottomPanel: false });
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
nextPage = () => {
|
||||
this.state.rendition.next();
|
||||
};
|
||||
prevPage = () => {
|
||||
this.state.rendition.prev();
|
||||
};
|
||||
render() {
|
||||
const renditionProps = {
|
||||
rendition: this.state.rendition,
|
||||
handleLeaveReader: this.handleLeaveReader,
|
||||
handleEnterReader: this.handleEnterReader,
|
||||
isShow:
|
||||
this.state.isOpenLeftPanel ||
|
||||
this.state.isOpenTopPanel ||
|
||||
this.state.isOpenBottomPanel ||
|
||||
this.state.isOpenRightPanel,
|
||||
};
|
||||
return (
|
||||
<div className="viewer">
|
||||
{OtherUtil.getReaderConfig("isHidePageButton") !== "yes" && (
|
||||
<>
|
||||
<div
|
||||
className="previous-chapter-single-container"
|
||||
onClick={() => {
|
||||
this.prevPage();
|
||||
}}
|
||||
>
|
||||
<span className="icon-dropdown previous-chapter-single"></span>
|
||||
</div>
|
||||
<div
|
||||
className="next-chapter-single-container"
|
||||
onClick={() => {
|
||||
this.nextPage();
|
||||
}}
|
||||
>
|
||||
<span className="icon-dropdown next-chapter-single"></span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
className="reader-setting-icon-container"
|
||||
onClick={() => {
|
||||
this.handleEnterReader("left");
|
||||
this.handleEnterReader("right");
|
||||
this.handleEnterReader("bottom");
|
||||
this.handleEnterReader("top");
|
||||
}}
|
||||
>
|
||||
<span className="icon-grid reader-setting-icon"></span>
|
||||
</div>
|
||||
{this.state.isMessage ? <MessageBox /> : null}
|
||||
<div
|
||||
className="left-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenLeftPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("left");
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleEnterReader("left");
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
className="right-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenRightPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("right");
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleEnterReader("right");
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
className="top-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenTopPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("top");
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleEnterReader("top");
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
className="bottom-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenBottomPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("bottom");
|
||||
}}
|
||||
onClick={() => {
|
||||
this.handleEnterReader("bottom");
|
||||
}}
|
||||
></div>
|
||||
|
||||
{this.state.rendition && this.props.currentEpub.rendition && (
|
||||
<EpubViewer {...renditionProps} />
|
||||
)}
|
||||
<div
|
||||
className="setting-panel-container"
|
||||
onMouseLeave={(event) => {
|
||||
this.handleLeaveReader("right");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenRightPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateX(309px)",
|
||||
}
|
||||
}
|
||||
>
|
||||
<SettingPanel />
|
||||
</div>
|
||||
<div
|
||||
className="navigation-panel-container"
|
||||
onMouseLeave={(event) => {
|
||||
this.handleLeaveReader("left");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenLeftPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateX(-309px)",
|
||||
}
|
||||
}
|
||||
>
|
||||
<NavigationPanel {...{ time: this.state.time }} />
|
||||
</div>
|
||||
<div
|
||||
className="progress-panel-container"
|
||||
onMouseLeave={(event) => {
|
||||
this.handleLeaveReader("bottom");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenBottomPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateY(110px)",
|
||||
}
|
||||
}
|
||||
>
|
||||
<ProgressPanel {...{ time: this.state.time }} />
|
||||
</div>
|
||||
<div
|
||||
className="operation-panel-container"
|
||||
onMouseLeave={(event) => {
|
||||
this.handleLeaveReader("top");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenTopPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateY(-110px)",
|
||||
}
|
||||
}
|
||||
>
|
||||
<OperationPanel {...{ time: this.state.time }} />
|
||||
</div>
|
||||
<div
|
||||
className="view-area-page"
|
||||
id="page-area"
|
||||
style={
|
||||
document.body.clientWidth < 570
|
||||
? { left: 0, right: 0 }
|
||||
: this.state.readerMode === "continuous"
|
||||
? {
|
||||
left: `calc(50vw - ${270 * parseFloat(this.state.scale)}px)`,
|
||||
right: `calc(50vw - ${270 * parseFloat(this.state.scale)}px)`,
|
||||
top: "75px",
|
||||
bottom: "75px",
|
||||
}
|
||||
: this.state.readerMode === "single"
|
||||
? {
|
||||
left: `calc(50vw - ${270 * parseFloat(this.state.scale)}px)`,
|
||||
right: `calc(50vw - ${270 * parseFloat(this.state.scale)}px)`,
|
||||
}
|
||||
: this.state.readerMode === "double"
|
||||
? {
|
||||
left: this.state.margin - 40 + "px",
|
||||
right: this.state.margin - 40 + "px",
|
||||
}
|
||||
: {}
|
||||
}
|
||||
></div>
|
||||
|
||||
<Background {...{ time: this.state.time }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Reader;
|
||||
220
src/containers/_epubReader/index.css
Normal file
220
src/containers/_epubReader/index.css
Normal file
@@ -0,0 +1,220 @@
|
||||
.viewer {
|
||||
height: 100%;
|
||||
}
|
||||
.view-area {
|
||||
height: 100%;
|
||||
touch-action: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@keyframes fade-right {
|
||||
0% {
|
||||
transform: translateX(200px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-left {
|
||||
0% {
|
||||
transform: translateX(-200px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
z-index: -10;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@keyframes fade-down {
|
||||
0% {
|
||||
transform: translateY(-60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-up {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.left-panel {
|
||||
width: 50px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: calc(50vh - 100px);
|
||||
background-color: pink;
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
}
|
||||
.right-panel {
|
||||
width: 50px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: calc(50vh - 100px);
|
||||
background-color: pink;
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
}
|
||||
.top-panel {
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
right: calc(50vw - 100px);
|
||||
top: 0px;
|
||||
background-color: pink;
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
}
|
||||
.bottom-panel {
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
right: calc(50vw - 100px);
|
||||
top: calc(100vh - 50px);
|
||||
background-color: pink;
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
}
|
||||
.operation-panel-container {
|
||||
width: 412px;
|
||||
height: 60px;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: calc(50vw - 206px);
|
||||
z-index: 15;
|
||||
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
.progress-panel-container {
|
||||
width: 412px;
|
||||
height: 60px;
|
||||
position: absolute;
|
||||
top: calc(100vh - 60px);
|
||||
left: calc(50vw - 206px);
|
||||
z-index: 15;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
.setting-panel-container {
|
||||
width: 299px;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
transition: transform 0.5s ease;
|
||||
z-index: 15;
|
||||
}
|
||||
.navigation-panel-container {
|
||||
width: 299px;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
transition: transform 0.5s ease;
|
||||
z-index: 15;
|
||||
}
|
||||
.view-area-page {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 25px;
|
||||
bottom: 20px;
|
||||
/* width: calc(100% - 100px);
|
||||
height: calc(100% - 100px); */
|
||||
z-index: 0;
|
||||
user-select: text;
|
||||
}
|
||||
.previous-chapter-single-container {
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
font-size: 30px;
|
||||
transform: rotate(90deg);
|
||||
cursor: pointer;
|
||||
opacity: 0.2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 5;
|
||||
}
|
||||
.next-chapter-single-container {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
transform: rotate(-90deg);
|
||||
cursor: pointer;
|
||||
opacity: 0.2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 5;
|
||||
}
|
||||
.next-chapter-single-container:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.previous-chapter-single-container:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.previous-chapter-single {
|
||||
height: 20px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.next-chapter-single {
|
||||
font-size: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.reader-setting-icon {
|
||||
margin: 8px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.reader-setting-icon-container {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 20px;
|
||||
font-size: 22px;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
transition: 0.1s;
|
||||
line-height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: 0, 2s;
|
||||
}
|
||||
.reader-setting-icon-container:hover {
|
||||
border-radius: 50%;
|
||||
}
|
||||
32
src/containers/_epubReader/index.tsx
Normal file
32
src/containers/_epubReader/index.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
handleFetchNotes,
|
||||
handleFetchBookmarks,
|
||||
handleFetchChapters,
|
||||
handleFetchPercentage,
|
||||
handleMessageBox,
|
||||
handleFetchBooks,
|
||||
handleRenderFunc,
|
||||
} from "../../store/actions";
|
||||
|
||||
import "./index.css";
|
||||
import { connect } from "react-redux";
|
||||
import { stateType } from "../../store";
|
||||
import Reader from "./component";
|
||||
|
||||
const mapStateToProps = (state: stateType) => {
|
||||
return {
|
||||
currentEpub: state.book.currentEpub,
|
||||
currentBook: state.book.currentBook,
|
||||
isMessage: state.manager.isMessage,
|
||||
};
|
||||
};
|
||||
const actionCreator = {
|
||||
handleFetchNotes,
|
||||
handleFetchBookmarks,
|
||||
handleFetchChapters,
|
||||
handleMessageBox,
|
||||
handleFetchPercentage,
|
||||
handleFetchBooks,
|
||||
handleRenderFunc,
|
||||
};
|
||||
export default connect(mapStateToProps, actionCreator)(Reader);
|
||||
27
src/containers/_epubReader/interface.tsx
Normal file
27
src/containers/_epubReader/interface.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import BookModel from "../../model/Book";
|
||||
export interface ReaderProps {
|
||||
currentEpub: any;
|
||||
currentBook: BookModel;
|
||||
isMessage: boolean;
|
||||
handleFetchNotes: () => void;
|
||||
handleFetchBooks: () => void;
|
||||
handleRenderFunc: (renderFunc: () => void) => void;
|
||||
handleFetchBookmarks: () => void;
|
||||
handleMessageBox: (isShow: boolean) => void;
|
||||
handleFetchPercentage: (currentBook: BookModel) => void;
|
||||
handleFetchChapters: (currentEpub: any) => void;
|
||||
}
|
||||
|
||||
export interface ReaderState {
|
||||
isOpenRightPanel: boolean;
|
||||
isOpenTopPanel: boolean;
|
||||
isOpenBottomPanel: boolean;
|
||||
isOpenLeftPanel: boolean;
|
||||
isMessage: boolean;
|
||||
isTouch: boolean;
|
||||
readerMode: string;
|
||||
rendition: any;
|
||||
time: number;
|
||||
scale: string;
|
||||
margin: number;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import EpubViewer from "../epubViewer";
|
||||
import ViewArea from "../viewArea";
|
||||
import Background from "../background";
|
||||
import SettingPanel from "../panels/settingPanel";
|
||||
import NavigationPanel from "../panels/navigationPanel";
|
||||
@@ -12,18 +12,18 @@ import OtherUtil from "../../utils/otherUtil";
|
||||
import ReadingTime from "../../utils/readUtils/readingTime";
|
||||
|
||||
class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
messageTimer!: NodeJS.Timeout;
|
||||
tickTimer!: NodeJS.Timeout;
|
||||
messageTimer!: any;
|
||||
tickTimer!: any;
|
||||
rendition: any;
|
||||
|
||||
constructor(props: ReaderProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpenRightPanel:
|
||||
isOpenSettingPanel:
|
||||
OtherUtil.getReaderConfig("isSettingLocked") === "yes" ? true : false,
|
||||
isOpenTopPanel: false,
|
||||
isOpenBottomPanel: false,
|
||||
isOpenLeftPanel:
|
||||
isOpenOperationPanel: false,
|
||||
isOpenProgressPanel: false,
|
||||
isOpenNavPanel:
|
||||
OtherUtil.getReaderConfig("isNavLocked") === "yes" ? true : false,
|
||||
isMessage: false,
|
||||
rendition: null,
|
||||
@@ -48,7 +48,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
|
||||
//控制消息提示两秒之后消失
|
||||
if (nextProps.isMessage) {
|
||||
this.messageTimer = global.setTimeout(() => {
|
||||
this.messageTimer = setTimeout(() => {
|
||||
this.props.handleMessageBox(false);
|
||||
this.setState({ isMessage: false });
|
||||
}, 2000);
|
||||
@@ -56,87 +56,55 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
}
|
||||
componentDidMount() {
|
||||
this.handleRenderBook();
|
||||
this.props.handleRenderFunc(this.handleRenderBook);
|
||||
window.addEventListener("resize", () => {
|
||||
this.handleRenderBook();
|
||||
});
|
||||
this.tickTimer = global.setInterval(() => {
|
||||
let time = this.state.time;
|
||||
time += 1;
|
||||
let page = document.querySelector("#page-area");
|
||||
//解决快速翻页过程中图书消失的bug
|
||||
let renderedBook = document.querySelector(".epub-view");
|
||||
if (
|
||||
renderedBook &&
|
||||
!renderedBook.innerHTML &&
|
||||
this.state.readerMode !== "continuous"
|
||||
) {
|
||||
this.handleRenderBook();
|
||||
}
|
||||
let ele = page!.getElementsByClassName("epub-container")[0];
|
||||
if (page!.getElementsByClassName("epub-container").length > 1 && ele) {
|
||||
ele.parentNode?.removeChild(ele);
|
||||
}
|
||||
this.setState({ time });
|
||||
this.handleRecord();
|
||||
}, 1000);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.tickTimer);
|
||||
}
|
||||
handleRenderBook = () => {
|
||||
let page = document.querySelector("#page-area");
|
||||
let epub = this.props.currentEpub;
|
||||
if (page!.innerHTML) {
|
||||
page!.innerHTML = "";
|
||||
}
|
||||
|
||||
this.setState({ rendition: null }, () => {
|
||||
(window as any).rangy.init(); // 初始化
|
||||
this.rendition = epub.renderTo(page, {
|
||||
manager:
|
||||
this.state.readerMode === "continuous" ? "continuous" : "default",
|
||||
flow: this.state.readerMode === "continuous" ? "scrolled" : "auto",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
snap: true,
|
||||
spread:
|
||||
OtherUtil.getReaderConfig("readerMode") === "single" ? "none" : "",
|
||||
});
|
||||
this.setState({ rendition: this.rendition });
|
||||
this.state.readerMode !== "continuous" && MouseEvent(this.rendition); // 绑定事件
|
||||
(window as any).rangy.init(); // 初始化
|
||||
this.rendition = epub.renderTo(page, {
|
||||
manager:
|
||||
this.state.readerMode === "continuous" ? "continuous" : "default",
|
||||
flow: this.state.readerMode === "continuous" ? "scrolled" : "auto",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
snap: true,
|
||||
spread:
|
||||
OtherUtil.getReaderConfig("readerMode") === "single" ? "none" : "",
|
||||
});
|
||||
this.setState({ rendition: this.rendition });
|
||||
this.state.readerMode !== "continuous" && MouseEvent(this.rendition); // 绑定事件
|
||||
this.tickTimer = setInterval(() => {
|
||||
let time = this.state.time;
|
||||
time += 1;
|
||||
this.setState({ time });
|
||||
}, 1000);
|
||||
};
|
||||
handleRecord() {
|
||||
OtherUtil.setReaderConfig("isFullScreen", "no");
|
||||
|
||||
OtherUtil.setReaderConfig("windowWidth", document.body.clientWidth + "");
|
||||
OtherUtil.setReaderConfig("windowHeight", document.body.clientHeight + "");
|
||||
OtherUtil.setReaderConfig("windowX", window.screenX + "");
|
||||
OtherUtil.setReaderConfig("windowY", window.screenY + "");
|
||||
}
|
||||
//进入阅读器
|
||||
handleEnterReader = (position: string) => {
|
||||
//控制上下左右的菜单的显示
|
||||
switch (position) {
|
||||
case "right":
|
||||
this.setState({
|
||||
isOpenRightPanel: this.state.isOpenRightPanel ? false : true,
|
||||
isOpenSettingPanel: this.state.isOpenSettingPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
case "left":
|
||||
this.setState({
|
||||
isOpenLeftPanel: this.state.isOpenLeftPanel ? false : true,
|
||||
isOpenNavPanel: this.state.isOpenNavPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
case "top":
|
||||
this.setState({
|
||||
isOpenTopPanel: this.state.isOpenTopPanel ? false : true,
|
||||
isOpenOperationPanel: this.state.isOpenOperationPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
case "bottom":
|
||||
this.setState({
|
||||
isOpenBottomPanel: this.state.isOpenBottomPanel ? false : true,
|
||||
isOpenProgressPanel: this.state.isOpenProgressPanel ? false : true,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
@@ -151,7 +119,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
if (OtherUtil.getReaderConfig("isSettingLocked") === "yes") {
|
||||
break;
|
||||
} else {
|
||||
this.setState({ isOpenRightPanel: false });
|
||||
this.setState({ isOpenSettingPanel: false });
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -159,14 +127,14 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
if (OtherUtil.getReaderConfig("isNavLocked") === "yes") {
|
||||
break;
|
||||
} else {
|
||||
this.setState({ isOpenLeftPanel: false });
|
||||
this.setState({ isOpenNavPanel: false });
|
||||
break;
|
||||
}
|
||||
case "top":
|
||||
this.setState({ isOpenTopPanel: false });
|
||||
this.setState({ isOpenOperationPanel: false });
|
||||
break;
|
||||
case "bottom":
|
||||
this.setState({ isOpenBottomPanel: false });
|
||||
this.setState({ isOpenProgressPanel: false });
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -184,33 +152,38 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
handleLeaveReader: this.handleLeaveReader,
|
||||
handleEnterReader: this.handleEnterReader,
|
||||
isShow:
|
||||
this.state.isOpenLeftPanel ||
|
||||
this.state.isOpenTopPanel ||
|
||||
this.state.isOpenBottomPanel ||
|
||||
this.state.isOpenRightPanel,
|
||||
this.state.isOpenNavPanel ||
|
||||
this.state.isOpenOperationPanel ||
|
||||
this.state.isOpenProgressPanel ||
|
||||
this.state.isOpenSettingPanel,
|
||||
};
|
||||
return (
|
||||
<div className="viewer">
|
||||
{OtherUtil.getReaderConfig("isHidePageButton") !== "yes" && (
|
||||
<>
|
||||
<div
|
||||
className="previous-chapter-single-container"
|
||||
onClick={() => {
|
||||
this.prevPage();
|
||||
}}
|
||||
>
|
||||
<span className="icon-dropdown previous-chapter-single"></span>
|
||||
</div>
|
||||
<div
|
||||
className="next-chapter-single-container"
|
||||
onClick={() => {
|
||||
this.nextPage();
|
||||
}}
|
||||
>
|
||||
<span className="icon-dropdown next-chapter-single"></span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
className="viewer"
|
||||
style={{
|
||||
filter: `brightness(${
|
||||
OtherUtil.getReaderConfig("brightness") || 1
|
||||
}) invert(${
|
||||
OtherUtil.getReaderConfig("isInvert") === "yes" ? 1 : 0
|
||||
})`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="previous-chapter-single-container"
|
||||
onClick={() => {
|
||||
this.prevPage();
|
||||
}}
|
||||
>
|
||||
<span className="icon-dropdown previous-chapter-single"></span>
|
||||
</div>
|
||||
<div
|
||||
className="next-chapter-single-container"
|
||||
onClick={() => {
|
||||
this.nextPage();
|
||||
}}
|
||||
>
|
||||
<span className="icon-dropdown next-chapter-single"></span>
|
||||
</div>
|
||||
<div
|
||||
className="reader-setting-icon-container"
|
||||
onClick={() => {
|
||||
@@ -226,7 +199,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
<div
|
||||
className="left-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenLeftPanel) {
|
||||
if (this.state.isTouch || this.state.isOpenNavPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("left");
|
||||
@@ -238,7 +211,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
<div
|
||||
className="right-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenRightPanel) {
|
||||
if (this.state.isTouch || this.state.isOpenSettingPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("right");
|
||||
@@ -250,7 +223,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
<div
|
||||
className="top-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenTopPanel) {
|
||||
if (this.state.isTouch || this.state.isOpenOperationPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("top");
|
||||
@@ -262,7 +235,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
<div
|
||||
className="bottom-panel"
|
||||
onMouseEnter={() => {
|
||||
if (this.state.isTouch || this.state.isOpenBottomPanel) {
|
||||
if (this.state.isTouch || this.state.isOpenProgressPanel) {
|
||||
return;
|
||||
}
|
||||
this.handleEnterReader("bottom");
|
||||
@@ -273,7 +246,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
></div>
|
||||
|
||||
{this.state.rendition && this.props.currentEpub.rendition && (
|
||||
<EpubViewer {...renditionProps} />
|
||||
<ViewArea {...renditionProps} />
|
||||
)}
|
||||
<div
|
||||
className="setting-panel-container"
|
||||
@@ -281,7 +254,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
this.handleLeaveReader("right");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenRightPanel
|
||||
this.state.isOpenSettingPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateX(309px)",
|
||||
@@ -296,7 +269,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
this.handleLeaveReader("left");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenLeftPanel
|
||||
this.state.isOpenNavPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateX(-309px)",
|
||||
@@ -311,7 +284,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
this.handleLeaveReader("bottom");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenBottomPanel
|
||||
this.state.isOpenProgressPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateY(110px)",
|
||||
@@ -326,7 +299,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
this.handleLeaveReader("top");
|
||||
}}
|
||||
style={
|
||||
this.state.isOpenTopPanel
|
||||
this.state.isOpenOperationPanel
|
||||
? {}
|
||||
: {
|
||||
transform: "translateY(-110px)",
|
||||
@@ -335,6 +308,7 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
|
||||
>
|
||||
<OperationPanel {...{ time: this.state.time }} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="view-area-page"
|
||||
id="page-area"
|
||||
|
||||
@@ -2,13 +2,13 @@ import {
|
||||
handleFetchNotes,
|
||||
handleFetchBookmarks,
|
||||
handleFetchChapters,
|
||||
handleFetchPercentage,
|
||||
} from "../../store/actions/reader";
|
||||
import { handleFetchPercentage } from "../../store/actions/progressPanel";
|
||||
import {
|
||||
handleMessageBox,
|
||||
handleFetchBooks,
|
||||
handleRenderFunc,
|
||||
} from "../../store/actions";
|
||||
|
||||
import "./index.css";
|
||||
} from "../../store/actions/manager";
|
||||
import "./epubViewer.css";
|
||||
import { connect } from "react-redux";
|
||||
import { stateType } from "../../store";
|
||||
import Reader from "./component";
|
||||
@@ -27,6 +27,5 @@ const actionCreator = {
|
||||
handleMessageBox,
|
||||
handleFetchPercentage,
|
||||
handleFetchBooks,
|
||||
handleRenderFunc,
|
||||
};
|
||||
export default connect(mapStateToProps, actionCreator)(Reader);
|
||||
|
||||
@@ -5,7 +5,6 @@ export interface ReaderProps {
|
||||
isMessage: boolean;
|
||||
handleFetchNotes: () => void;
|
||||
handleFetchBooks: () => void;
|
||||
handleRenderFunc: (renderFunc: () => void) => void;
|
||||
handleFetchBookmarks: () => void;
|
||||
handleMessageBox: (isShow: boolean) => void;
|
||||
handleFetchPercentage: (currentBook: BookModel) => void;
|
||||
@@ -13,10 +12,10 @@ export interface ReaderProps {
|
||||
}
|
||||
|
||||
export interface ReaderState {
|
||||
isOpenRightPanel: boolean;
|
||||
isOpenTopPanel: boolean;
|
||||
isOpenBottomPanel: boolean;
|
||||
isOpenLeftPanel: boolean;
|
||||
isOpenSettingPanel: boolean;
|
||||
isOpenOperationPanel: boolean;
|
||||
isOpenProgressPanel: boolean;
|
||||
isOpenNavPanel: boolean;
|
||||
isMessage: boolean;
|
||||
isTouch: boolean;
|
||||
readerMode: string;
|
||||
|
||||
124
src/containers/viewArea/component.tsx
Normal file
124
src/containers/viewArea/component.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
//阅读器图书内容区域
|
||||
import React from "react";
|
||||
import PopupMenu from "../../components/popups/popupMenu";
|
||||
import { ViewAreaProps, ViewAreaStates } from "./interface";
|
||||
import RecordLocation from "../../utils/readUtils/recordLocation";
|
||||
import BookmarkModel from "../../model/Bookmark";
|
||||
import StyleUtil from "../../utils/readUtils/styleUtil";
|
||||
import ImageViewer from "../../components/imageViewer";
|
||||
import Lottie from "react-lottie";
|
||||
import animationSiri from "../../assets/lotties/siri.json";
|
||||
|
||||
const siriOptions = {
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
animationData: animationSiri,
|
||||
rendererSettings: {
|
||||
preserveAspectRatio: "xMidYMid slice",
|
||||
},
|
||||
};
|
||||
declare var window: any;
|
||||
|
||||
class EpubViewer extends React.Component<ViewAreaProps, ViewAreaStates> {
|
||||
isFirst: boolean;
|
||||
constructor(props: ViewAreaProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
cfiRange: null,
|
||||
contents: null,
|
||||
rect: null,
|
||||
loading: true,
|
||||
};
|
||||
this.isFirst = true;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let epub = this.props.currentEpub;
|
||||
window.rangy.init(); // 初始化
|
||||
this.props.rendition.on("locationChanged", () => {
|
||||
this.props.handleReadingEpub(epub);
|
||||
this.props.handleOpenMenu(false);
|
||||
const currentLocation = this.props.rendition.currentLocation();
|
||||
if (!currentLocation.start) {
|
||||
return;
|
||||
}
|
||||
const cfi = currentLocation.start.cfi;
|
||||
this.props.handleShowBookmark(
|
||||
this.props.bookmarks &&
|
||||
this.props.bookmarks.filter(
|
||||
(item: BookmarkModel) => item.cfi === cfi
|
||||
)[0]
|
||||
? true
|
||||
: false
|
||||
);
|
||||
|
||||
if (!this.isFirst && this.props.locations) {
|
||||
let percentage = this.props.locations.percentageFromCfi(cfi);
|
||||
RecordLocation.recordCfi(this.props.currentBook.key, cfi, percentage);
|
||||
this.props.handlePercentage(percentage);
|
||||
} else if (!this.isFirst) {
|
||||
//如果过暂时没有解析出locations,就直接记录cfi
|
||||
RecordLocation.recordCfi(
|
||||
this.props.currentBook.key,
|
||||
cfi,
|
||||
RecordLocation.getCfi(this.props.currentBook.key).percentage
|
||||
);
|
||||
}
|
||||
this.isFirst = false;
|
||||
});
|
||||
this.props.rendition.on("rendered", () => {
|
||||
this.setState({ loading: false });
|
||||
let iframe = document.getElementsByTagName("iframe")[0];
|
||||
if (!iframe) return;
|
||||
let doc = iframe.contentDocument;
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
StyleUtil.addDefaultCss();
|
||||
this.props.rendition.themes.default(StyleUtil.getCustomCss(false));
|
||||
});
|
||||
this.props.rendition.on("selected", (cfiRange: any, contents: any) => {
|
||||
var range = contents.range(cfiRange);
|
||||
var rect = range.getBoundingClientRect();
|
||||
this.setState({ cfiRange, contents, rect });
|
||||
});
|
||||
this.props.rendition.themes.default(StyleUtil.getCustomCss(false));
|
||||
this.props.rendition.display(
|
||||
RecordLocation.getCfi(this.props.currentBook.key) === null
|
||||
? null
|
||||
: RecordLocation.getCfi(this.props.currentBook.key).cfi
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const popupMenuProps = {
|
||||
rendition: this.props.rendition,
|
||||
cfiRange: this.state.cfiRange,
|
||||
contents: this.state.contents,
|
||||
rect: this.state.rect,
|
||||
};
|
||||
return (
|
||||
<div className="view-area">
|
||||
<ImageViewer
|
||||
{...{
|
||||
isShow: this.props.isShow,
|
||||
rendition: this.props.rendition,
|
||||
handleEnterReader: this.props.handleEnterReader,
|
||||
handleLeaveReader: this.props.handleLeaveReader,
|
||||
}}
|
||||
/>
|
||||
<PopupMenu {...popupMenuProps} />
|
||||
{this.state.loading ? (
|
||||
<div className="spinner">
|
||||
<Lottie options={siriOptions} height={100} width={300} />
|
||||
</div>
|
||||
) : null}
|
||||
<>
|
||||
{this.props.isShowBookmark ? <div className="bookmark"></div> : null}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EpubViewer;
|
||||
35
src/containers/viewArea/index.css
Normal file
35
src/containers/viewArea/index.css
Normal file
@@ -0,0 +1,35 @@
|
||||
.popup-menu-container {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
z-index: 20;
|
||||
animation: popup 0.075s ease-in-out 0s 1;
|
||||
}
|
||||
.bookmark {
|
||||
height: 40px;
|
||||
width: 20px;
|
||||
padding: 0px;
|
||||
-webkit-transform: rotate(0deg) skew(0deg);
|
||||
transform: rotate(0deg) skew(0deg);
|
||||
border-left: 10px solid red;
|
||||
border-right: 10px solid red;
|
||||
border-bottom: 10px solid transparent;
|
||||
position: fixed;
|
||||
top: 5px;
|
||||
right: 70px;
|
||||
z-index: 15;
|
||||
}
|
||||
.bookmark,
|
||||
.bookmark:before,
|
||||
.bookmark:after {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
.spinner {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -150px;
|
||||
margin-top: -50px;
|
||||
}
|
||||
29
src/containers/viewArea/index.tsx
Normal file
29
src/containers/viewArea/index.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { connect } from "react-redux";
|
||||
import { stateType } from "../../store";
|
||||
import ViewArea from "./component";
|
||||
import {
|
||||
handlePercentage,
|
||||
handleOpenMenu,
|
||||
handleShowBookmark,
|
||||
handleReadingEpub,
|
||||
} from "../../store/actions";
|
||||
import "./index.css";
|
||||
|
||||
const mapStateToProps = (state: stateType) => {
|
||||
return {
|
||||
chapters: state.reader.chapters,
|
||||
currentEpub: state.book.currentEpub,
|
||||
currentBook: state.book.currentBook,
|
||||
locations: state.progressPanel.locations,
|
||||
bookmarks: state.reader.bookmarks,
|
||||
isShowBookmark: state.viewArea.isShowBookmark,
|
||||
};
|
||||
};
|
||||
const actionCreator = {
|
||||
handlePercentage,
|
||||
handleOpenMenu,
|
||||
handleShowBookmark,
|
||||
handleReadingEpub,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actionCreator)(ViewArea);
|
||||
26
src/containers/viewArea/interface.tsx
Normal file
26
src/containers/viewArea/interface.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import BookModel from "../../model/Book";
|
||||
import BookmarkModel from "../../model/Bookmark";
|
||||
|
||||
export interface ViewAreaProps {
|
||||
rendition: any;
|
||||
currentBook: BookModel;
|
||||
currentEpub: any;
|
||||
bookmarks: BookmarkModel[];
|
||||
locations: any;
|
||||
isShowBookmark: boolean;
|
||||
chapters: any[];
|
||||
isShow: boolean;
|
||||
handleLeaveReader: (position: string) => void;
|
||||
handleEnterReader: (position: string) => void;
|
||||
handlePercentage: (percentage: number) => void;
|
||||
handleOpenMenu: (isOpenMenu: boolean) => void;
|
||||
handleShowBookmark: (isShowBookmark: boolean) => void;
|
||||
handleReadingEpub: (epub: object) => void;
|
||||
}
|
||||
export interface ViewAreaStates {
|
||||
loading: boolean;
|
||||
cfiRange: any;
|
||||
contents: any;
|
||||
// rendition: any;
|
||||
rect: any;
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import React from "react";
|
||||
import RecentBooks from "../../utils/readUtils/recordRecent";
|
||||
import { EpubReaderProps, EpubReaderState } from "./interface";
|
||||
import localforage from "localforage";
|
||||
import Reader from "../../containers/epubReader";
|
||||
import Reader from "../../containers/_epubReader";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import _ from "underscore";
|
||||
import BookUtil from "../../utils/fileUtils/bookUtil";
|
||||
|
||||
Reference in New Issue
Block a user