Former-commit-id: 72b46bbefe8dbf65ea8861d5ede19492fea041d8
This commit is contained in:
troyeguo
2021-11-29 12:46:05 +08:00
parent e62102beb5
commit e86ccdb0fe
21 changed files with 215 additions and 77 deletions

View File

@@ -130,6 +130,13 @@ app.on("ready", () => {
ipcMain.on("user-data", (event, arg) => {
event.returnValue = dirPath;
});
ipcMain.on("hide-reader", (event, arg) => {
if (!readerWindow.isDestroyed()) {
if (readerWindow.isFocused()) {
readerWindow.minimize();
}
}
});
ipcMain.on("switch-moyu", (event, arg) => {
let id;
if (store.get("isPreventSleep") === "yes") {

View File

File diff suppressed because one or more lines are too long

View File

@@ -325,5 +325,6 @@
"Purple": "紫色",
"Remember window's size from last read": "记忆阅读器窗口大小",
"Letter Spacing": "字间距",
"Survey": "用户调查"
"Survey": "用户调查",
"Sliding Animation": "翻页动画"
}

View File

@@ -328,5 +328,6 @@
"When opening books in the file manager with Koodo, the opened books won't be added to the library": "When opening books in the file manager with Koodo, the opened books won't be added to the library",
"Hide menu button": "Hide menu button",
"Manage": "Manage",
"Sliding Animation": "Sliding Animation",
"Please turn off open books in the main window": "Please turn off open books in the main window"
}

View File

@@ -41,7 +41,7 @@ class ActionDialog extends React.Component<ActionDialogProps> {
style={{
left: this.props.left,
top: this.props.top,
maxHeight: "37px",
maxHeight: "45px",
paddingTop: "3px",
}}
>

View File

@@ -34,10 +34,9 @@
}
.cover-footer {
width: 100%;
text-align: left;
text-align: center;
font-size: 13px;
opacity: 0.3;
position: absolute;
bottom: 6px;
margin-left: 13px;
}

View File

@@ -112,7 +112,6 @@ class ImageViewer extends React.Component<ImageViewerProps, ImageViewerStates> {
handleZoomIn = () => {
let image: any = document.querySelector(".image");
if (image.style.width === "200vw" || image.style.height === "200vh") return;
console.log(image.style);
this.setState({ zoomIndex: this.state.zoomIndex + 1 }, () => {
if (this.state.imageRatio === "horizontal") {
image.style.width = `${60 + this.state.zoomIndex * 10}vw`;
@@ -124,7 +123,6 @@ class ImageViewer extends React.Component<ImageViewerProps, ImageViewerStates> {
handleZoomOut = () => {
let image: any = document.querySelector(".image");
if (image.style.width === "10vw" || image.style.height === "10vh") return;
console.log(image.style.height);
this.setState({ zoomIndex: this.state.zoomIndex - 1 }, () => {
if (this.state.imageRatio === "horizontal") {
image.style.width = `${60 + this.state.zoomIndex * 10}vw`;

View File

@@ -6,6 +6,7 @@ import PopupTrans from "../popupTrans";
import { PopupMenuProps, PopupMenuStates } from "./interface";
import StorageUtil from "../../../utils/storageUtil";
let colors = ["#fac106", "#ebe702", "#0be603", "#0493e6"];
let lines = ["#FF0000", "#000080", "#0000FF", "#2EFF2E"];
declare var window: any;
@@ -132,18 +133,26 @@ class PopupMenu extends React.Component<PopupMenuProps, PopupMenuStates> {
var pageIndex = selected.page;
if (!iWin.PDFViewerApplication.pdfViewer) return;
var page = iWin.PDFViewerApplication.pdfViewer.getPageView(pageIndex);
if (page && page.textLayer && page.textLayer.textLayerDiv) {
var pageElement = page.textLayer.textLayerDiv;
if (page && page.div && page.textLayer && page.textLayer.textLayerDiv) {
var pageElement =
colorCode.indexOf("color") > -1
? page.textLayer.textLayerDiv
: page.div;
var viewport = page.viewport;
selected.coords.forEach((rect) => {
var bounds = viewport.convertToViewportRectangle(rect);
var el = iWin.document.createElement("div");
el.setAttribute(
"style",
"position: absolute;" +
"background-color: " +
colors[colorCode.split("-")[1]] +
(colorCode.indexOf("color") > -1
? "background-color: "
: "border-bottom: ") +
(colorCode.indexOf("color") > -1
? colors[colorCode.split("-")[1]]
: `2px solid ${lines[colorCode.split("-")[1]]}`) +
"; left:" +
Math.min(bounds[0], bounds[2]) +
"px; top:" +
@@ -153,7 +162,7 @@ class PopupMenu extends React.Component<PopupMenuProps, PopupMenuStates> {
Math.abs(bounds[0] - bounds[2]) +
"px; height:" +
Math.abs(bounds[1] - bounds[3]) +
"px; z-index: 10;"
"px; z-index:0;"
);
el.setAttribute("key", noteKey);
el.addEventListener("click", (event: any) => {

View File

@@ -37,7 +37,6 @@ class PopupOption extends React.Component<PopupOptionProps> {
if (!iframe) return;
let doc = iframe.contentDocument;
if (!doc) return;
console.log(getSelection());
copy(getSelection());
this.props.handleOpenMenu(false);
doc.getSelection()?.empty();

View File

@@ -15,6 +15,7 @@ class SettingSwitch extends React.Component<
this.state = {
isBold: StorageUtil.getReaderConfig("isBold") === "yes",
isIndent: StorageUtil.getReaderConfig("isIndent") === "yes",
isSliding: StorageUtil.getReaderConfig("isSliding") === "yes",
isUnderline: StorageUtil.getReaderConfig("isUnderline") === "yes",
isShadow: StorageUtil.getReaderConfig("isShadow") === "yes",
isItalic: StorageUtil.getReaderConfig("isItalic") === "yes",
@@ -44,6 +45,7 @@ class SettingSwitch extends React.Component<
stateName,
this.state[stateName] ? "yes" : "no"
);
toast(this.props.t("Change Successfully"));
setTimeout(() => {
this.props.renderFunc();
}, 500);
@@ -82,6 +84,9 @@ class SettingSwitch extends React.Component<
case "isIndent":
this._handleChange("isIndent");
break;
case "isSliding":
this._handleChange("isSliding");
break;
case "isItalic":
this._handleChange("isItalic");
break;

View File

@@ -14,6 +14,7 @@ export interface SettingSwitchState {
isHideFooter: boolean;
isBold: boolean;
isIndent: boolean;
isSliding: boolean;
isShadow: boolean;
isUnderline: boolean;
isItalic: boolean;

View File

@@ -8,36 +8,31 @@ export const settingList = [
{
isElectron: false,
title: "Prevent accidental trigger",
desc:
"Reader menu will not be triggered by hovering but clicking on the area",
desc: "Reader menu will not be triggered by hovering but clicking on the area",
propName: "isPreventTrigger",
},
{
isElectron: true,
title: "Import books as link",
desc:
"The imported books will not be copied to library, only linked to the original book path",
desc: "The imported books will not be copied to library, only linked to the original book path",
propName: "isImportPath",
},
{
isElectron: true,
title: "Merge reader into Word",
desc:
"Get rid of window frame, make reader hide into Word or any text editor, and can't be detected. You need to set up the reader's position, size and style first.",
desc: "Get rid of window frame, make reader hide into Word or any text editor, and can't be detected. You need to set up the reader's position, size and style first.",
propName: "isMergeWord",
},
{
isElectron: false,
title: "Auto open last-read book",
desc:
"The book that you read from last time will be open automatically when launching",
desc: "The book that you read from last time will be open automatically when launching",
propName: "isOpenBook",
},
{
isElectron: true,
title: "Auto open book in fullscreen",
desc:
"Reader window will be maximized to fit the screen when opening a book",
desc: "Reader window will be maximized to fit the screen when opening a book",
propName: "isAutoFullscreen",
},
{
@@ -55,15 +50,13 @@ export const settingList = [
{
isElectron: true,
title: "Open book without adding it to library",
desc:
"When opening books in the file manager with Koodo, the opened books won't be added to the library",
desc: "When opening books in the file manager with Koodo, the opened books won't be added to the library",
propName: "isPreventAdd",
},
{
isElectron: false,
title: "Open books in the main window",
desc:
"Book won't be opened in a seperate window but directly opened in the main window",
desc: "Book won't be opened in a seperate window but directly opened in the main window",
propName: "isOpenInMain",
},
{
@@ -98,6 +91,10 @@ export const searchList = [
{ label: "Yahoo", value: "yahoo" },
];
export const readerSettingList = [
{
title: "Sliding Animation",
propName: "isSliding",
},
{
title: "Text Indent",
propName: "isIndent",

View File

@@ -149,7 +149,6 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
pageHeight: rendition.getPageSize().height,
});
if (this.props.currentBook.format.startsWith("CB")) {
console.log(this.props.htmlBook.chapters);
this.setState({
chapter:
this.props.htmlBook.chapters[parseInt(bookLocation.count || "0")]
@@ -203,7 +202,8 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
entries.map((item: any) => item.name),
unrar,
this.state.readerMode,
"cbr"
"cbr",
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0],
@@ -221,7 +221,8 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
Object.keys(contents.files).sort(),
zip,
this.state.readerMode,
"cbz"
"cbz",
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0],
@@ -240,7 +241,8 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
extractedFiles.map((item: any) => item.name),
extractedFiles,
this.state.readerMode,
"cbt"
"cbt",
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0],
@@ -257,14 +259,22 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
);
};
handleMobi = async (result: ArrayBuffer) => {
let rendition = new MobiRender(result, this.state.readerMode);
let rendition = new MobiRender(
result,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);
this.handleRest(rendition);
};
handleAzw3 = async (result: ArrayBuffer) => {
let rendition = new Azw3Render(result, this.state.readerMode);
let rendition = new Azw3Render(
result,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);
@@ -295,7 +305,8 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
let rendition = new TxtRender(
result,
this.state.readerMode,
this.props.currentBook.charset || charset || "utf8"
this.props.currentBook.charset || charset || "utf8",
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
@@ -307,7 +318,11 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
var reader = new FileReader();
reader.onload = async (evt) => {
let docStr = window.marked(evt.target?.result as any);
let rendition = new StrRender(docStr, this.state.readerMode);
let rendition = new StrRender(
docStr,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);
@@ -326,7 +341,11 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
);
rtfToHTML.fromString(text, async (err: any, html: any) => {
let rendition = new StrRender(html, this.state.readerMode);
let rendition = new StrRender(
html,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);
@@ -337,7 +356,11 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
window.mammoth
.convertToHtml({ arrayBuffer: result })
.then(async (res: any) => {
let rendition = new StrRender(res.value, this.state.readerMode);
let rendition = new StrRender(
res.value,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);
@@ -355,7 +378,11 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
);
let bookObj = xmlBookToObj(Buffer.from(result));
bookObj += xmlBookTagFilter(fb2Str);
let rendition = new StrRender(bookObj, this.state.readerMode);
let rendition = new StrRender(
bookObj,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);
@@ -368,7 +395,11 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
var reader = new FileReader();
reader.onload = async (evt) => {
const html = evt.target?.result as any;
let rendition = new StrRender(html, this.state.readerMode);
let rendition = new StrRender(
html,
this.state.readerMode,
StorageUtil.getReaderConfig("isSliding") === "yes" ? true : false
);
await rendition.renderTo(
document.getElementsByClassName("html-viewer-page")[0]
);

View File

@@ -130,7 +130,7 @@ class CardList extends React.Component<CardListProps, CardListStates> {
{this.handleBookName(item.bookKey)}
</div>
<div className="card-list-item-chapter card-list-item-title">
<Trans>{item.chapter}</Trans>
{item.chapter}
</div>
</div>
<div

View File

@@ -41,7 +41,8 @@ class OperationPanel extends React.Component<
nextProps.currentEpub.rendition.location &&
this.props.currentEpub.rendition
) {
const currentLocation = this.props.currentEpub.rendition.currentLocation();
const currentLocation =
this.props.currentEpub.rendition.currentLocation();
if (!currentLocation.start) {
return;
}
@@ -62,6 +63,51 @@ class OperationPanel extends React.Component<
// let nextPercentage = section.start.percentage;
}
}
componentDidMount() {
const exitHandler = () => {
if (
document.webkitIsFullScreen ||
document.mozFullScreen ||
document.msFullscreenElement !== null
) {
this.setState({ isFullScreen: !this.state.isFullScreen });
StorageUtil.setReaderConfig(
"isFullScreen",
this.state.isFullScreen ? "no" : "yes"
);
}
};
if (document.addEventListener) {
document.addEventListener(
"fullscreenchange",
() => {
exitHandler();
},
false
);
document.addEventListener(
"mozfullscreenchange",
() => {
exitHandler();
},
false
);
document.addEventListener(
"MSFullscreenChange",
() => {
exitHandler();
},
false
);
document.addEventListener(
"webkitfullscreenchange",
() => {
exitHandler();
},
false
);
}
}
// 点击切换全屏按钮触发
handleScreen() {
!this.state.isFullScreen
@@ -89,8 +135,8 @@ class OperationPanel extends React.Component<
de.msRequestFullscreen();
}
this.setState({ isFullScreen: true });
StorageUtil.setReaderConfig("isFullScreen", "yes");
// this.setState({ isFullScreen: true });
// StorageUtil.setReaderConfig("isFullScreen", "yes");
}
// 退出全屏模式
handleExitFullScreen() {
@@ -107,8 +153,8 @@ class OperationPanel extends React.Component<
document.webkitExitFullscreen();
}
this.setState({ isFullScreen: false });
StorageUtil.setReaderConfig("isFullScreen", "no");
// this.setState({ isFullScreen: false });
// StorageUtil.setReaderConfig("isFullScreen", "no");
}
handleAddBookmark() {
let bookKey = this.props.currentBook.key;

View File

@@ -21,7 +21,6 @@ class EpubReader extends React.Component<EpubReaderProps, EpubReaderState> {
componentWillMount() {
if (StorageUtil.getReaderConfig("isMergeWord") === "yes") {
console.log(document.querySelector("body"));
document
.querySelector("body")
?.setAttribute("style", "background-color: rgba(0,0,0,0)");
@@ -30,15 +29,10 @@ class EpubReader extends React.Component<EpubReaderProps, EpubReaderState> {
let key = url[url.length - 1].split("?")[0];
localforage.getItem("books").then((result: any) => {
let book;
//兼容在主窗口打开
if (this.props.currentBook.key) {
book = this.props.currentBook;
} else {
book =
result[_.findIndex(result, { key })] ||
JSON.parse(localStorage.getItem("tempBook") || "{}");
}
let book =
result[_.findIndex(result, { key })] ||
JSON.parse(localStorage.getItem("tempBook") || "{}");
BookUtil.fetchBook(key, false, book.path).then((result) => {
if (!result) {
toast.error(this.props.t("Book not exsits"));

View File

@@ -38,7 +38,6 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
}
componentDidMount() {
if (StorageUtil.getReaderConfig("isMergeWord") === "yes") {
console.log(document.querySelector("body"));
document
.querySelector("body")
?.setAttribute("style", "background-color: rgba(0,0,0,0)");

View File

@@ -2,6 +2,7 @@ import StorageUtil from "../storageUtil";
import { isElectron } from "react-device-detect";
import localforage from "localforage";
import BookModel from "../../model/Book";
import toast from "react-hot-toast";
class BookUtil {
static addBook(key: string, buffer: ArrayBuffer) {
@@ -60,6 +61,37 @@ class BookUtil {
return localforage.removeItem(key);
}
}
static isBookExist(key: string, bookPath: string = "") {
return new Promise<boolean>((resolve, reject) => {
if (isElectron) {
var fs = window.require("fs");
var path = window.require("path");
let _bookPath = path.join(
localStorage.getItem("storageLocation")
? localStorage.getItem("storageLocation")
: window
.require("electron")
.ipcRenderer.sendSync("storage-location", "ping"),
`book`,
key
);
if ((bookPath && fs.existsSync(bookPath)) || fs.existsSync(_bookPath)) {
resolve(true);
} else {
resolve(false);
}
} else {
localforage.getItem(key).then((result) => {
if (result) {
resolve(true);
} else {
resolve(false);
}
});
}
});
}
static fetchBook(
key: string,
isArrayBuffer: boolean = false,
@@ -103,6 +135,10 @@ class BookUtil {
}
}
static async RedirectBook(book: BookModel) {
if (!(await this.isBookExist(book.key, book.path))) {
toast.error("Book not exist");
return;
}
let ref =
book.description === "readonly" || book.description === "pdf"
? book.format.toLowerCase()

View File

@@ -43,6 +43,10 @@ const arrowKeys = (rendition: any, keyCode: number) => {
}
if (keyCode === 123) {
if (isElectron) {
StorageUtil.setReaderConfig(
"isMergeWord",
StorageUtil.getReaderConfig("isMergeWord") === "yes" ? "no" : "yes"
);
window.require("electron").ipcRenderer.sendSync("switch-moyu", "ping");
}
lock = true;
@@ -51,6 +55,16 @@ const arrowKeys = (rendition: any, keyCode: number) => {
}, 100);
return false;
}
if (keyCode === 9) {
if (isElectron) {
window.require("electron").ipcRenderer.sendSync("hide-reader", "ping");
}
lock = true;
setTimeout(function () {
lock = false;
}, 100);
return false;
}
};
const mouseChrome = (rendition: any, wheelDelta: number) => {
@@ -180,15 +194,17 @@ export const HtmlMouseEvent = (
key: string,
readerMode: string
) => {
let iframe = document.getElementsByTagName("iframe")[0];
if (!iframe) return;
let doc = iframe.contentDocument;
if (!doc) {
return;
}
// navigate with mousewheel
window.addEventListener("keydown", (event) => {
arrowKeys(rendition, event.keyCode);
rendition.on("rendered", () => {
let iframe = document.getElementsByTagName("iframe")[0];
if (!iframe) return;
let doc = iframe.contentDocument;
if (!doc) {
return;
}
// navigate with mousewheel
window.addEventListener("keydown", (event) => {
arrowKeys(rendition, event.keyCode);
});
bindEvent(rendition, doc, key, readerMode);
});
bindEvent(rendition, doc, key, readerMode);
};

View File

@@ -3,14 +3,14 @@ import _ from "underscore";
class RecordLocation {
static recordCfi(bookKey: string, cfi: string, percentage: number) {
let json = localStorage.getItem("recordLocation");
let obj = JSON.parse(json!) || {};
let obj = JSON.parse(json || "{}");
obj[bookKey] = { cfi: cfi, percentage: percentage };
localStorage.setItem("recordLocation", JSON.stringify(obj));
}
static getCfi(bookKey: string) {
let json = localStorage.getItem("recordLocation");
let obj = JSON.parse(json!) || {};
let obj = JSON.parse(json || "{}");
return obj[bookKey] || {};
}
static recordScrollHeight(
@@ -20,35 +20,36 @@ class RecordLocation {
count: string
) {
let json = localStorage.getItem("recordLocation");
let obj = JSON.parse(json!) || {};
let obj = JSON.parse(json || "{}");
obj[bookKey] = { text, chapterTitle, count };
localStorage.setItem("recordLocation", JSON.stringify(obj));
}
static getScrollHeight(bookKey: string) {
let json = localStorage.getItem("recordLocation");
let obj = JSON.parse(json!) || {};
let obj = JSON.parse(json || "{}");
return obj[bookKey] || {};
}
static getPDFlocation(fingerprint: string) {
let json = localStorage.getItem("pdfjs.history");
let arr = JSON.parse(json!).files || [];
console.log(json);
let arr = JSON.parse(json || "{}").files || [];
return arr[_.findLastIndex(arr, { fingerprint })] || {};
}
static recordPDFlocation(fingerprint: string, obj: object) {
let json = localStorage.getItem("pdfjs.history");
let _obj = JSON.parse(json!) || [];
let _obj = JSON.parse(json || "{}");
_obj.files[_.findLastIndex(_obj.files, { fingerprint })] = obj;
localStorage.setItem("pdfjs.history", JSON.stringify(_obj));
}
static getAllCfi() {
let json = localStorage.getItem("recordLocation");
let obj = JSON.parse(json!) || {};
let obj = JSON.parse(json || "{}");
return obj;
}
static clear(bookKey: string) {
let json = localStorage.getItem("recordLocation");
let obj = JSON.parse(json!) || {};
let obj = JSON.parse(json || "{}");
delete obj[bookKey];
localStorage.setItem("recordLocation", JSON.stringify(obj));
}

View File

@@ -4,11 +4,9 @@ class styleUtil {
// 为 iframe 添加默认的样式
static addDefaultCss() {
let doc = window.frames[0].document;
console.log(doc, "doc");
if (!doc) return;
let css = this.getDefaultCss();
let background = document.querySelector(".viewer");
console.log(background, "background");
if (!background) return;
background.setAttribute(
"style",