diff --git a/main.ts b/main.ts index 9f284dec..8a8dfd86 100644 --- a/main.ts +++ b/main.ts @@ -9,28 +9,21 @@ const { const isDev = require("electron-is-dev"); const path = require("path"); const fontList = require("font-list"); -// ipcMain.on("is-fonts-ready", (event, arg) => { -// console.log(arg, "arg"); -// }); ipcMain.on("fonts-ready", (event, arg) => { - console.log(arg); // prints "ping" fontList .getFonts() .then((fonts) => { event.returnValue = fonts; - // event.reply("fonts-ready", "pong"); }) .catch((err) => { - console.log("epub"); + console.log(err); }); }); let mainWindow; app.on("ready", () => { - // console.log("before message box"); - mainWindow = new BrowserWindow({ width: 1030, height: 660, diff --git a/src/assets/locales/cn/translation.json b/src/assets/locales/cn/translation.json index 748980ae..a3137fdf 100644 --- a/src/assets/locales/cn/translation.json +++ b/src/assets/locales/cn/translation.json @@ -16,6 +16,7 @@ "Downloading": "下载中,请稍候", "Uploading": "上传中,请稍候", "Loading": "加载中", + "Current Font Size": "当前大小", "Import from Local": "从本地导入", "Backup and Restore": "备份和恢复", "Search My Library": "搜索我的书库", @@ -41,6 +42,7 @@ "Ultra Large": "超大", "Reading Option": "阅读选项", "Current Progress": "当前进度", + "Current Chapter": "当前章节", "Exit": "退出阅读", "Empty Shelf Title": "书架名为空", "Enter Fullscreen": "进入全屏", @@ -76,8 +78,8 @@ "Backup Successfully": "备份成功", "Restore Successfully": "恢复成功", "Try refresh or restart": "退出阅读后生效", - "Turn On scroll mode": "开启滚动模式", - "Turn Off scroll mode": "关闭滚动模式", + "Turn on scroll mode": "开启滚动模式", + "Turn off scroll mode": "关闭滚动模式", "Search the book": "全书搜索", "Wrong bookmark": "书签出问题了", "Last Step": "上一步", diff --git a/src/assets/locales/en/translation.json b/src/assets/locales/en/translation.json index 1f128833..8713281c 100644 --- a/src/assets/locales/en/translation.json +++ b/src/assets/locales/en/translation.json @@ -85,6 +85,8 @@ "Search the book": "Search the book", "Turn on scroll mode": "Turn on scroll mode", "Loading": "Loading", + "Current Font Size": "Current Font Size", + "Current Chapter": "Current Chapter", "Turn off scroll mode": "Turn off scroll mode", "Wrong bookmark": "Wrong bookmark", "Last Step": "Last Step", diff --git a/src/assets/locales/tw/translation.json b/src/assets/locales/tw/translation.json index da75d0f3..7e704d36 100644 --- a/src/assets/locales/tw/translation.json +++ b/src/assets/locales/tw/translation.json @@ -97,6 +97,8 @@ "Turn on scroll mode": "開啟滾動模式", "Turn off scroll mode": "關閉滾動模式", "Less": "收起", + "Current Font Size": "當前大小", + "Current Chapter": "當前章節", "Loading": "加載中", "Pick Up Color": "選擇顏色", "Highlight Successfully": "高亮成功", diff --git a/src/components/book/component.tsx b/src/components/book/component.tsx index 2defc782..1d64dca6 100644 --- a/src/components/book/component.tsx +++ b/src/components/book/component.tsx @@ -41,7 +41,6 @@ class Book extends React.Component { handleMoreAction = (event: any) => { const e = event || window.event; let x = e.clientX; - console.log(e.clientX, document.body.clientWidth); if (x > document.body.clientWidth - 100) { x = x - 80; } diff --git a/src/components/bookmarkList/bookmarkList.css b/src/components/bookmarkList/bookmarkList.css index 949063cb..c38ad3ee 100644 --- a/src/components/bookmarkList/bookmarkList.css +++ b/src/components/bookmarkList/bookmarkList.css @@ -10,13 +10,20 @@ .book-bookmark-digest { margin: 15px 5px 10px; width: 236px; - max-height: 183px; + max-height: 186px; font-size: 14px; line-height: 14px; color: rgba(75, 75, 75, 1); opacity: 1; - overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 4; + white-space: normal; + word-break: keep-all; + overflow: hidden; + position: relative; } .book-bookmark-index { float: left; @@ -42,7 +49,8 @@ margin-left: 12px; /* margin-top: 8px; */ position: relative; - bottom: 10px; + bottom: 15px; + left: 10px; font-size: 14px; color: rgba(161, 161, 161, 1); opacity: 1; @@ -63,5 +71,6 @@ margin: 0px 12px 0px; cursor: pointer; position: relative; - bottom: 15px; + bottom: 5px; + left: 10px; } diff --git a/src/components/bookmarkList/component.tsx b/src/components/bookmarkList/component.tsx index 428baabb..3d8ca0ff 100644 --- a/src/components/bookmarkList/component.tsx +++ b/src/components/bookmarkList/component.tsx @@ -31,6 +31,7 @@ class BookmarkList extends React.Component< .filter((item) => { return item.bookKey === this.props.currentBook.key; }) + .reverse() .map((item, index) => { const bookmarkProps = { itemKey: item.key, @@ -48,7 +49,9 @@ class BookmarkList extends React.Component< }} >

{item.label}

- {item.chapter} + + {item.chapter} + {this.state.deleteIndex === index ? ( ) : null} diff --git a/src/components/cardList/cardList.css b/src/components/cardList/cardList.css index 551bd0de..900daa07 100644 --- a/src/components/cardList/cardList.css +++ b/src/components/cardList/cardList.css @@ -126,6 +126,7 @@ } .card-list-item-title { float: left; + /* width: 100px; */ } .card-list-container-box { margin-top: 35px; diff --git a/src/components/cardList/component.tsx b/src/components/cardList/component.tsx index b9f718c1..bedc466a 100644 --- a/src/components/cardList/component.tsx +++ b/src/components/cardList/component.tsx @@ -40,7 +40,6 @@ class CardList extends React.Component { break; } } - console.log(cfi, "cfi"); this.props.handleReadingBook(book!); this.props.handleReadingEpub(epub); this.props.handleReadingState(true); @@ -116,7 +115,9 @@ class CardList extends React.Component {
{this.handleBookName(item.bookKey)}
-
》{item.chapter}
+
+ 》{item.chapter} +
{ diff --git a/src/components/contentList/component.tsx b/src/components/contentList/component.tsx index 78e1e21e..fa7dd46e 100644 --- a/src/components/contentList/component.tsx +++ b/src/components/contentList/component.tsx @@ -8,14 +8,10 @@ class ContentList extends React.Component { this.state = { chapters: [] }; this.handleJump = this.handleJump.bind(this); } + componentWillMount() { - console.log( - this.props.currentEpub.navigation, - "this.props.currentEpub.navigation" - ); this.props.currentEpub.loaded.navigation .then((chapters: any) => { - console.log(chapters.toc, "chapters"); this.setState({ chapters: chapters.toc }); }) .catch(() => { @@ -46,25 +42,11 @@ class ContentList extends React.Component { ); }); }; - // return ( - //
  • - // - // {item.label} - // - // {item.subitems.length > 0 ? ( - //
      {renderSubContentList(item.subitems)}
    - // ) : null} - //
  • - // ); return (
      - {renderContentList(this.state.chapters)} + {this.state.chapters && renderContentList(this.state.chapters)}
    ); diff --git a/src/components/contentList/index.tsx b/src/components/contentList/index.tsx index 3b1da169..7ce99119 100644 --- a/src/components/contentList/index.tsx +++ b/src/components/contentList/index.tsx @@ -3,7 +3,10 @@ import { connect } from "react-redux"; import { stateType } from "../../redux/store"; import ContentList from "./component"; const mapStateToProps = (state: stateType) => { - return { currentEpub: state.book.currentEpub }; + return { + currentEpub: state.book.currentEpub, + chapters: state.reader.chapters, + }; }; const actionCreator = {}; export default connect(mapStateToProps, actionCreator)(ContentList); diff --git a/src/components/contentList/interface.tsx b/src/components/contentList/interface.tsx index 9bcdf2f8..3236eb0f 100644 --- a/src/components/contentList/interface.tsx +++ b/src/components/contentList/interface.tsx @@ -1,5 +1,6 @@ export interface ContentListProps { currentEpub: any; + chapters: any; } export interface ContentListState { chapters: any; diff --git a/src/components/fontSizeList/component.tsx b/src/components/fontSizeList/component.tsx index 78b56a05..fd1c5321 100644 --- a/src/components/fontSizeList/component.tsx +++ b/src/components/fontSizeList/component.tsx @@ -1,6 +1,5 @@ //字体大小选择页面 import React from "react"; -import { fontSizeList } from "../../utils/readerConfig"; import { Trans } from "react-i18next"; import { FontSizeListProps, FontSizeListState } from "./interface"; import "./fontSizeList.css"; @@ -13,51 +12,52 @@ class FontSizeList extends React.Component< constructor(props: FontSizeListProps) { super(props); this.state = { - currentFontSizeIndex: fontSizeList.findIndex((item) => { - return item.value === (OtherUtil.getReaderConfig("fontSize") || "17"); - }), + fontSize: OtherUtil.getReaderConfig("fontSize") || "17", }; } - handleFontSize(value: string, index: number) { - OtherUtil.setReaderConfig("fontSize", value); - this.setState({ - currentFontSizeIndex: index, - }); + onFontChange = (event: any) => { + const fontSize = event.target.value; + OtherUtil.setReaderConfig("fontSize", fontSize); this.props.handleMessage("Try refresh or restart"); this.props.handleMessageBox(true); - } - + }; + //使进度百分比随拖动实时变化 + onFontInput = (event: any) => { + this.setState({ fontSize: event.target.value }); + }; render() { - const renderFontSizeDescription = () => { - return fontSizeList.map((item, index) => { - return ( -
  • -
    this.handleFontSize(item.value, index)} - >
    -

    - {item.size} -

    -
  • - ); - }); - }; return (
    Font Size
    A -
    -
      {renderFontSizeDescription()}
    - +
    + { + this.onFontChange(event); + }} + onChange={(event) => { + this.onFontInput(event); + }} + /> +
    A +
    + Current Font Size + {": "} + {this.state.fontSize} +
    ); } diff --git a/src/components/fontSizeList/fontSizeList.css b/src/components/fontSizeList/fontSizeList.css index db7f2725..ca0222ac 100644 --- a/src/components/fontSizeList/fontSizeList.css +++ b/src/components/fontSizeList/fontSizeList.css @@ -16,25 +16,15 @@ line-height: 27px; color: rgba(75, 75, 75, 1); } -.font-size-line { - float: left; - width: 173px; - height: 0px; - border: 2px solid rgba(112, 112, 112, 1); - opacity: 1; - border-top: none; - margin-top: 12px; - margin-left: 14px; -} + .ultra-large-size { float: right; font-size: 40px; - font-weight: 300; line-height: 68px; color: rgba(75, 75, 75, 1); position: relative; - bottom: 66px; - right: -20px; + bottom: 49px; + left: 5px; } .font-size-selector { width: 205px; @@ -42,40 +32,11 @@ display: flex; justify-content: space-between; align-items: center; - margin-left: 12px; -} - -.font-size-description { - float: left; - width: 25px; + margin-left: 0px; position: relative; - bottom: 4px; - right: 2px; - cursor: pointer; -} -.font-size-circle { - display: flex; - justify-content: center; - float: left; - margin: 0 8px; - width: 12px; - height: 12px; - background: rgba(255, 255, 255, 1); - border: 2px solid rgba(0, 0, 0, 1); - box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.16); - border-radius: 50%; - font-size: 10px; - color: rgba(75, 75, 75, 1); - text-align: center; - box-sizing: border-box; + right: 40px; } -.active-font-size { - width: 17px; - height: 17px; - margin: 0 4px; - background: black; -} .font-size-text { width: 100%; text-align: center; @@ -83,5 +44,11 @@ float: left; display: block; font-size: 12px; - color: rgba(75, 75, 75, 1); +} +.font-size-demo { + text-align: center; + color: rgba(75, 75, 75, 1); + margin-left: 19px; + position: relative; + top: 10px; } diff --git a/src/components/fontSizeList/interface.tsx b/src/components/fontSizeList/interface.tsx index b92c084b..0c5dd31d 100644 --- a/src/components/fontSizeList/interface.tsx +++ b/src/components/fontSizeList/interface.tsx @@ -3,5 +3,5 @@ export interface FontSizeListProps { handleMessage: (message: string) => void; } export interface FontSizeListState { - currentFontSizeIndex: number; + fontSize: string; } diff --git a/src/components/importLocal/component.tsx b/src/components/importLocal/component.tsx index f43b4ef4..f833df13 100644 --- a/src/components/importLocal/component.tsx +++ b/src/components/importLocal/component.tsx @@ -8,7 +8,6 @@ import { Trans } from "react-i18next"; import Dropzone from "react-dropzone"; import { ImportLocalProps, ImportLocalState } from "./interface"; import RecordRecent from "../../utils/recordRecent"; -import axios from "axios"; import Epub from "epubjs"; declare var window: any; @@ -29,7 +28,6 @@ class ImportLocal extends React.Component { } bookArr.push(book); RecordRecent.setRecent(book.key); - console.log(bookArr, "bookArr"); localforage.setItem("books", bookArr).then(() => { this.props.handleFetchBooks(); }); @@ -79,54 +77,6 @@ class ImportLocal extends React.Component { //this.handleOtherFormat(file, file.name); } }; - toBase64 = (file: any) => - new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => resolve(reader.result); - reader.onerror = (error) => reject(error); - }); - handleOtherFormat = async (file: any, name: string) => { - const option = { - apikey: "47f9a3ea69b4f01bc1c54ee2d17b4c2a", - input: "base64", - outputformat: "epub", - filename: "老人与海.txt", - file: await this.toBase64(file), - }; - const data = await axios.post("https://api.convertio.co/convert", option); - console.log(data, "data1"); - if (data.data.data.id) { - axios - .get(`https://api.convertio.co/convert/${data.data.data.id}/dl`) - .then((res) => { - fetch( - "data:" + - "application/epub+zip" + - ";base64," + - res.data.data.content - ) - .then((res: any) => res.blob()) - .then((blob: any) => { - console.log(blob, "blob"); - const file = new File([blob], "老人与海.epub", { - type: "application/epub+zip", - }); - this.doIncrementalTest(file); - }) - .catch((err) => { - console.log(err, "err"); - }); - }) - .catch((err) => { - console.log(err); - return; - }); - } else { - this.props.handleMessage("Import Failed"); - this.props.handleMessageBox(true); - } - }; handleBook = (file: any, md5: string) => { //md5重复不导入 if (this.props.books) { @@ -182,7 +132,7 @@ class ImportLocal extends React.Component { this.doIncrementalTest(item); }); }} - accept={[".epub", ".mobi", ".txt"]} + accept={[".epub"]} multiple={true} > {({ getRootProps, getInputProps }) => ( diff --git a/src/components/popupNote/component.tsx b/src/components/popupNote/component.tsx index 24455fcb..490b2e23 100644 --- a/src/components/popupNote/component.tsx +++ b/src/components/popupNote/component.tsx @@ -23,7 +23,6 @@ class PopupNote extends React.Component { item.notes = notes; } }); - console.log(this.props.notes, "notes"); localforage.setItem("notes", this.props.notes).then(() => { this.props.handleOpenMenu(false); this.props.handleMessage("Add Successfully"); @@ -35,12 +34,11 @@ class PopupNote extends React.Component { }); } else { let bookKey = this.props.currentBook.key; - let epub = this.props.currentEpub; - const currentLocation = epub.rendition.currentLocation(); + const currentLocation = this.props.currentEpub.rendition.currentLocation(); let chapterHref = currentLocation.start.href; let chapterIndex = currentLocation.start.index; let chapter = "Unknown Chapter"; - let currentChapter = this.props.chapters.filter( + let currentChapter = this.props.flattenChapters.filter( (item: any) => item.href.split("#")[0] === chapterHref )[0]; if (currentChapter) { @@ -50,7 +48,7 @@ class PopupNote extends React.Component { const cfi = RecordLocation.getCfi(this.props.currentBook.key).cfi; let iframe = document.getElementsByTagName("iframe")[0]; - if(!iframe)return; + if (!iframe) return; let doc = iframe.contentDocument; if (!doc) { return; @@ -59,11 +57,6 @@ class PopupNote extends React.Component { .getSelection(iframe) .saveCharacterRanges(doc.body)[0]; let range = JSON.stringify(charRange); - console.log( - charRange, - doc.getSelection(), - doc.getSelection()!.toString() - ); let text = doc.getSelection()?.toString(); if (!text) { return; diff --git a/src/components/popupNote/index.tsx b/src/components/popupNote/index.tsx index 4793c43d..5ee02649 100644 --- a/src/components/popupNote/index.tsx +++ b/src/components/popupNote/index.tsx @@ -11,7 +11,7 @@ const mapStateToProps = (state: stateType) => { currentBook: state.book.currentBook, notes: state.reader.notes, color: state.reader.color, - chapters: state.reader.chapters, + flattenChapters: state.reader.flattenChapters, noteKey: state.reader.noteKey, }; }; diff --git a/src/components/popupNote/interface.tsx b/src/components/popupNote/interface.tsx index fad6a54c..9db84672 100644 --- a/src/components/popupNote/interface.tsx +++ b/src/components/popupNote/interface.tsx @@ -4,7 +4,7 @@ export interface PopupNoteProps { currentEpub: any; currentBook: BookModel; notes: NoteModel[]; - chapters: any; + flattenChapters: any; color: number; noteKey: string; handleNoteKey: (key: string) => void; @@ -12,5 +12,5 @@ export interface PopupNoteProps { handleMessage: (message: string) => void; handleOpenMenu: (isOpenMenu: boolean) => void; handleMenuMode: (menu: string) => void; - handleFetchNotes:()=>void; + handleFetchNotes: () => void; } diff --git a/src/components/popupOption/component.tsx b/src/components/popupOption/component.tsx index 9b576fc4..85812631 100644 --- a/src/components/popupOption/component.tsx +++ b/src/components/popupOption/component.tsx @@ -15,7 +15,7 @@ class PopupOption extends React.Component { this.props.handleMenuMode("note"); let rect = this.props.rect; let x = rect.x % this.props.currentEpub.rendition._layout.width; - let y= rect.y % this.props.currentEpub.rendition._layout.height; + let y = rect.y % this.props.currentEpub.rendition._layout.height; let height = 200; let posX = x + rect.width / 2 - 20; //防止menu超出图书 @@ -64,12 +64,11 @@ class PopupOption extends React.Component { }; handleDigest = () => { let bookKey = this.props.currentBook.key; - let epub = this.props.currentEpub; - const currentLocation = epub.rendition.currentLocation(); + const currentLocation = this.props.currentEpub.rendition.currentLocation(); let chapterHref = currentLocation.start.href; let chapterIndex = currentLocation.start.index; let chapter = "Unknown Chapter"; - let currentChapter = this.props.chapters.filter( + let currentChapter = this.props.flattenChapters.filter( (item: any) => item.href.split("#")[0] === chapterHref )[0]; if (currentChapter) { @@ -91,7 +90,6 @@ class PopupOption extends React.Component { .getSelection(iframe) .saveCharacterRanges(doc.body)[0]; let range = JSON.stringify(charRange); - console.log(doc.getSelection(), "propscontents"); let text = doc.getSelection()?.toString(); if (!text) return; text = text.replace(/\s\s/g, ""); @@ -110,7 +108,6 @@ class PopupOption extends React.Component { percentage, color ); - console.log(digest, "digest"); let noteArr = this.props.notes; noteArr.push(digest); localforage.setItem("notes", noteArr).then(() => { diff --git a/src/components/popupOption/index.tsx b/src/components/popupOption/index.tsx index d4c1c29a..c67d65f1 100644 --- a/src/components/popupOption/index.tsx +++ b/src/components/popupOption/index.tsx @@ -19,7 +19,7 @@ const mapStateToProps = (state: stateType) => { selection: state.viewArea.selection, notes: state.reader.notes, color: state.reader.color, - chapters: state.reader.chapters, + flattenChapters: state.reader.flattenChapters, }; }; const actionCreator = { diff --git a/src/components/popupOption/interface.tsx b/src/components/popupOption/interface.tsx index 74952e88..279a6267 100644 --- a/src/components/popupOption/interface.tsx +++ b/src/components/popupOption/interface.tsx @@ -6,7 +6,7 @@ export interface PopupOptionProps { selection: string; digests: NoteModel[]; notes: NoteModel[]; - chapters: any; + flattenChapters: any; color: number; rect: DOMRect; cfiRange: string; diff --git a/src/components/searchBox/component.tsx b/src/components/searchBox/component.tsx index 1bda053e..2549f7e5 100644 --- a/src/components/searchBox/component.tsx +++ b/src/components/searchBox/component.tsx @@ -8,9 +8,7 @@ class SearchBox extends React.Component { if (this.props.isNavSearch) { let searchBox: any = document.querySelector(".header-search-box"); searchBox && searchBox.focus(); - console.log(searchBox, "searchBox"); } - console.log(this.props.isNavSearch, "this.props.isNavSearch"); } handleMouse = () => { let value = (this.refs.searchBox as any).value; @@ -48,7 +46,6 @@ class SearchBox extends React.Component { ); return item; }); - console.log(searchList, "searchListtest"); // this.$refs.searchInput.blur(); this.props.handleSearchList(searchList); }); diff --git a/src/components/singleControl/component.tsx b/src/components/singleControl/component.tsx index 1154c53d..2a03bd67 100644 --- a/src/components/singleControl/component.tsx +++ b/src/components/singleControl/component.tsx @@ -21,6 +21,9 @@ class SingleControl extends React.Component< this.props.handleSingle(mode); this.setState({ isSingle: mode === "single" }); OtherUtil.setReaderConfig("isSingle", mode); + if (mode !== "single") { + OtherUtil.setReaderConfig("isScroll", "no"); + } this.props.handleMessage("Try refresh or restart"); this.props.handleMessageBox(true); }; diff --git a/src/components/tokenDialog/component.tsx b/src/components/tokenDialog/component.tsx index d200421f..d372f76b 100644 --- a/src/components/tokenDialog/component.tsx +++ b/src/components/tokenDialog/component.tsx @@ -27,7 +27,6 @@ class TokenDialog extends Component { this.props.handleMessageBox(true); }; handleOAuth(driveName: string) { - console.log(driveName, "onedrive"); if (driveName === "onedrive") { OnedriveUtil.GetAccessToken(); } diff --git a/src/containers/actionDialog/component.tsx b/src/containers/actionDialog/component.tsx index 4c2c4b2f..91aabd56 100644 --- a/src/containers/actionDialog/component.tsx +++ b/src/containers/actionDialog/component.tsx @@ -5,7 +5,6 @@ import { ActionDialogProps } from "./interface"; class ActionDialog extends React.Component { handleDeleteBook = () => { - console.log("tests"); this.props.handleReadingBook(this.props.currentBook); this.props.handleDeleteDialog(true); this.props.handleActionDialog(false); diff --git a/src/containers/bookList/component.tsx b/src/containers/bookList/component.tsx index 37287407..abbc884b 100644 --- a/src/containers/bookList/component.tsx +++ b/src/containers/bookList/component.tsx @@ -68,7 +68,6 @@ class BookList extends React.Component { arr.forEach((item) => { items[item] && itemArr.push(items[item]); }); - console.log(items, itemArr, "filter"); return itemArr; }; renderBookList = () => { diff --git a/src/containers/bookmarkPage/bookmarkPage.css b/src/containers/bookmarkPage/bookmarkPage.css index 10ae43ac..fafc40f4 100644 --- a/src/containers/bookmarkPage/bookmarkPage.css +++ b/src/containers/bookmarkPage/bookmarkPage.css @@ -76,8 +76,7 @@ .bookmark-page-list-item-title { float: left; font-size: 14px; - height: 15px; - + height: 16px; line-height: 15px; color: rgba(75, 75, 75, 1); opacity: 1; diff --git a/src/containers/bookmarkPage/component.tsx b/src/containers/bookmarkPage/component.tsx index ed8f76e1..3ae2e915 100644 --- a/src/containers/bookmarkPage/component.tsx +++ b/src/containers/bookmarkPage/component.tsx @@ -36,7 +36,6 @@ class BookmarkPage extends React.Component< }; render() { let { bookmarks, books, covers } = this.props; - console.log(bookmarks, "bookmarks"); let bookKeyArr: string[] = []; //获取bookmarks中的图书列表 bookmarks.forEach((item) => { @@ -70,9 +69,11 @@ class BookmarkPage extends React.Component< return false; }); const renderBookmarklistItem = (item: BookModel) => { - return bookmarkObj[item.key].map((item: BookmarkModel) => ( + return bookmarkObj[item.key].reverse().map((item: BookmarkModel) => (
  • -
    {item.chapter}
    +
    + {item.chapter} +
    {Math.round(item.percentage * 100)}%
    diff --git a/src/containers/operationPanel/component.tsx b/src/containers/operationPanel/component.tsx index 4c4f8c93..95d3a1ec 100644 --- a/src/containers/operationPanel/component.tsx +++ b/src/containers/operationPanel/component.tsx @@ -65,11 +65,10 @@ class OperationPanel extends React.Component< } handleAddBookmark() { let bookKey = this.props.currentBook.key; - let epub = this.props.currentEpub; - const currentLocation = epub.rendition.currentLocation(); + const currentLocation = this.props.currentEpub.rendition.currentLocation(); let chapterHref = currentLocation.start.href; let chapter = "Unknown Chapter"; - let currentChapter = this.props.chapters.filter( + let currentChapter = this.props.flattenChapters.filter( (item: any) => item.href.split("#")[0] === chapterHref )[0]; if (currentChapter) { @@ -85,7 +84,7 @@ class OperationPanel extends React.Component< const cfiRange = `epubcfi(${cfibase}!,${cfistart},${cfiend})`; const cfi = RecordLocation.getCfi(this.props.currentBook.key).cfi; - epub.getRange(cfiRange).then((range: any) => { + this.props.currentEpub.getRange(cfiRange).then((range: any) => { let text = range.toString(); text = text.replace(/\s\s/g, ""); text = text.replace(/\r/g, ""); diff --git a/src/containers/operationPanel/index.tsx b/src/containers/operationPanel/index.tsx index a5665a86..444791b2 100644 --- a/src/containers/operationPanel/index.tsx +++ b/src/containers/operationPanel/index.tsx @@ -19,7 +19,7 @@ const mapStateToProps = (state: stateType) => { currentEpub: state.book.currentEpub, currentBook: state.book.currentBook, bookmarks: state.reader.bookmarks, - chapters: state.reader.chapters, + flattenChapters: state.reader.flattenChapters, }; }; const actionCreator = { diff --git a/src/containers/operationPanel/interface.tsx b/src/containers/operationPanel/interface.tsx index ab208d90..ecc3ced6 100644 --- a/src/containers/operationPanel/interface.tsx +++ b/src/containers/operationPanel/interface.tsx @@ -5,7 +5,7 @@ export interface OperationPanelProps { currentEpub: any; currentBook: BookModel; bookmarks: BookmarkModel[]; - chapters: any; + flattenChapters: any; handleBookmarks: (bookmarks: BookmarkModel[]) => void; handleReadingState: (isReading: boolean) => void; handleFetchBookmarks: () => void; diff --git a/src/containers/popupMenu/component.tsx b/src/containers/popupMenu/component.tsx index 71759f2e..4c4a7566 100644 --- a/src/containers/popupMenu/component.tsx +++ b/src/containers/popupMenu/component.tsx @@ -148,6 +148,7 @@ class PopupMenu extends React.Component { let highlighters: any = this.props.notes; if (!highlighters) return; const currentLocation = this.props.currentEpub.rendition.currentLocation(); + if (!currentLocation.start) return; let chapterIndex = currentLocation.start.index; let highlightersByChapter = highlighters.filter( (item: any) => item.chapterIndex === chapterIndex diff --git a/src/containers/progressPanel/component.tsx b/src/containers/progressPanel/component.tsx index be9c2f01..4b9b5276 100644 --- a/src/containers/progressPanel/component.tsx +++ b/src/containers/progressPanel/component.tsx @@ -12,12 +12,29 @@ class ProgressPanel extends React.Component< super(props); this.state = { displayPercentage: this.props.percentage ? this.props.percentage : 0, + currentChapter: "", }; } + componentWillReceiveProps(nextProps: ProgressPanelProps) { + if (nextProps.currentEpub.rendition.location) { + const currentLocation = this.props.currentEpub.rendition.currentLocation(); + if (!currentLocation.start) { + return; + } + let chapterHref = currentLocation.start.href; + let chapter = "Unknown Chapter"; + let currentChapter = this.props.flattenChapters.filter( + (item: any) => item.href.split("#")[0] === chapterHref + )[0]; + if (currentChapter) { + chapter = currentChapter.label.trim(" "); + } + this.setState({ currentChapter: chapter }); + } + } //WARNING! To be deprecated in React v17. Use componentDidMount instead. onProgressChange = (event: any) => { const percentage = event.target.value / 100; - console.log(this.props.locations, "locations"); const location = percentage ? this.props.locations.cfiFromPercentage(percentage) : 0; @@ -57,16 +74,28 @@ class ProgressPanel extends React.Component< }; render() { + if (!this.props.locations) { + return ( +
    +

    + Loading +

    +
    + ); + } return (

    - Current Progress:{" "} - {Math.round( - this.state.displayPercentage > 1 - ? 100 - : this.state.displayPercentage * 100 - )} - % + + Current Progress:{" "} + {Math.round( + this.state.displayPercentage > 1 + ? 100 + : this.state.displayPercentage * 100 + )} + {"% "} + + {this.state.currentChapter}

    { currentBook: state.book.currentBook, percentage: state.progressPanel.percentage, locations: state.progressPanel.locations, + flattenChapters: state.reader.flattenChapters, }; }; const actionCreator = {}; diff --git a/src/containers/progressPanel/interface.tsx b/src/containers/progressPanel/interface.tsx index 3f36f98e..a79352df 100644 --- a/src/containers/progressPanel/interface.tsx +++ b/src/containers/progressPanel/interface.tsx @@ -5,7 +5,9 @@ export interface ProgressPanelProps { currentBook: BookModel; percentage: number; locations: any; + flattenChapters: any; } export interface ProgressPanelState { displayPercentage: number; + currentChapter: string; } diff --git a/src/containers/progressPanel/progressPanel.css b/src/containers/progressPanel/progressPanel.css index 14d25ee1..550d4d3b 100644 --- a/src/containers/progressPanel/progressPanel.css +++ b/src/containers/progressPanel/progressPanel.css @@ -5,6 +5,8 @@ width: 100%; margin-top: 9px; text-align: center; + height: 15px; + overflow: hidden; } .progress-slide-container { width: 309px; @@ -151,3 +153,7 @@ input[type="range"]::-ms-thumb { z-index: 10; animation: fade-up 0.1s ease-in-out 0s 1; } +.input-progress { + position: absolute; + bottom: 3px; +} diff --git a/src/containers/viewArea/component.tsx b/src/containers/viewArea/component.tsx index 67c2a248..7339401e 100644 --- a/src/containers/viewArea/component.tsx +++ b/src/containers/viewArea/component.tsx @@ -51,7 +51,6 @@ class ViewArea extends React.Component { this.props.handleOpenMenu(false); const currentLocation = this.rendition.currentLocation(); const cfi = currentLocation.start.cfi; - this.props.handleShowBookmark( this.props.bookmarks && this.props.bookmarks.filter( @@ -105,6 +104,9 @@ class ViewArea extends React.Component { } showImage = (event: any) => { console.log("click"); + if (!event.target.src) { + return; + } if (this.state.isShowImage) { this.setState({ isShowImage: false }); } @@ -112,19 +114,17 @@ class ViewArea extends React.Component { const handleDirection = (direction: string) => { this.setState({ imageRatio: direction }); }; - if (event.target.src) { - var img = new Image(); - img.addEventListener("load", function () { - handleDirection( - this.naturalWidth / this.naturalHeight > 1 ? "horizontal" : "vertical" - ); - }); - img.src = event.target.src; - let image: HTMLImageElement | null = document.querySelector(".image"); - if (image) { - image.src = event.target.src; - this.setState({ isShowImage: true }); - } + var img = new Image(); + img.addEventListener("load", function () { + handleDirection( + this.naturalWidth / this.naturalHeight > 1 ? "horizontal" : "vertical" + ); + }); + img.src = event.target.src; + let image: HTMLImageElement | null = document.querySelector(".image"); + if (image) { + image.src = event.target.src; + this.setState({ isShowImage: true }); } }; hideImage = (event: any) => { diff --git a/src/containers/welcomePage/component.tsx b/src/containers/welcomePage/component.tsx index 96249759..276ac83e 100644 --- a/src/containers/welcomePage/component.tsx +++ b/src/containers/welcomePage/component.tsx @@ -28,7 +28,6 @@ class WelcomePage extends React.Component { render() { const renderWelcome = () => { return welcomeMessage.map((item, index) => { - console.log(this.state.currentIndex, index, "index"); return (
    , document.getElementById("root") ); +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.register(); diff --git a/src/pages/reader/component.tsx b/src/pages/reader/component.tsx index d34876d1..de3e9e45 100644 --- a/src/pages/reader/component.tsx +++ b/src/pages/reader/component.tsx @@ -133,6 +133,7 @@ class Reader extends React.Component { : { transition: "transform 0.6s ease", transform: "translateX(309px)", + display: "none", } } > @@ -149,6 +150,7 @@ class Reader extends React.Component { : { transform: "translateX(-309px)", transition: "transform 0.6s ease", + display: "none", } } > @@ -165,6 +167,7 @@ class Reader extends React.Component { : { transform: "translateY(90px)", transition: "transform 0.5s ease", + display: "none", } } > @@ -181,6 +184,7 @@ class Reader extends React.Component { : { transform: "translateY(-90px)", transition: "transform 0.5s ease", + display: "none", } } > diff --git a/src/redux/actions/reader.tsx b/src/redux/actions/reader.tsx index 1cc04c06..118962e0 100644 --- a/src/redux/actions/reader.tsx +++ b/src/redux/actions/reader.tsx @@ -25,6 +25,9 @@ export function handleSingle(mode: string) { export function handleChapters(chapters: any) { return { type: "HANDLE_CHAPTERS", payload: chapters }; } +export function handleFlattenChapters(flattenChapters: any) { + return { type: "HANDLE_FLATTEN_CHAPTERS", payload: flattenChapters }; +} export function handleNoteKey(key: string) { return { type: "HANDLE_NOTE_KEY", payload: key }; } @@ -48,12 +51,24 @@ export function handleFetchNotes() { }); }; } - +export function flatChapter(chapters: any) { + let newChapter: any = []; + for (let i = 0; i < chapters.length; i++) { + if (chapters[i].subitems[0]) { + newChapter.push(chapters[i]); + newChapter = newChapter.concat(flatChapter(chapters[i].subitems)); + } else { + newChapter.push(chapters[i]); + } + } + return newChapter; +} export function handleFetchChapters(epub: any) { return (dispatch: (arg0: { type: string; payload: any }) => void) => { epub.loaded.navigation .then((chapters: any) => { dispatch(handleChapters(chapters.toc)); + dispatch(handleFlattenChapters(flatChapter(chapters.toc))); }) .catch(() => { console.log("Error occurs"); diff --git a/src/redux/reducers/reader.tsx b/src/redux/reducers/reader.tsx index 157dddc9..154d70de 100644 --- a/src/redux/reducers/reader.tsx +++ b/src/redux/reducers/reader.tsx @@ -5,6 +5,7 @@ const initState = { digests: [], locations: null, chapters: null, + flattenChapters: null, color: 0, noteKey: "", originalText: "", @@ -65,6 +66,11 @@ export function reader( ...state, chapters: action.payload, }; + case "HANDLE_FLATTEN_CHAPTERS": + return { + ...state, + flattenChapters: action.payload, + }; default: return state; } diff --git a/src/redux/store.tsx b/src/redux/store.tsx index 9f6d211f..44691feb 100644 --- a/src/redux/store.tsx +++ b/src/redux/store.tsx @@ -68,6 +68,7 @@ export type stateType = { locations: any[]; color: number; chapters: any[]; + flattenChapters: any; isSingle: string; noteKey: string; originalText: string; diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts new file mode 100644 index 00000000..b09523f1 --- /dev/null +++ b/src/serviceWorker.ts @@ -0,0 +1,149 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +type Config = { + onSuccess?: (registration: ServiceWorkerRegistration) => void; + onUpdate?: (registration: ServiceWorkerRegistration) => void; +}; + +export function register(config?: Config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL( + process.env.PUBLIC_URL, + window.location.href + ); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl: string, config?: Config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl: string, config?: Config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' } + }) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready + .then(registration => { + registration.unregister(); + }) + .catch(error => { + console.error(error.message); + }); + } +} diff --git a/src/utils/addFavorite.tsx b/src/utils/addFavorite.tsx index 6e947925..22bf13de 100644 --- a/src/utils/addFavorite.tsx +++ b/src/utils/addFavorite.tsx @@ -31,7 +31,6 @@ class AddFavorite { ? JSON.parse(localStorage.getItem("favoriteBooks") || "") : []; const index = bookArr.indexOf(bookKey); - console.log(bookArr, index, "clear"); if (index > -1) { bookArr.splice(index, 1); } diff --git a/src/utils/deleteUtil.tsx b/src/utils/deleteUtil.tsx index b2779711..30f6416d 100644 --- a/src/utils/deleteUtil.tsx +++ b/src/utils/deleteUtil.tsx @@ -4,7 +4,6 @@ import BookmarkModel from "../model/Bookmark"; class DeleteUtil { static deleteBook(books: BookModel[], bookKey: string) { books = books.filter((item) => item.key !== bookKey); - console.log(books, "books"); return books; } static deleteBookmarks(bookmarks: BookmarkModel[], bookKey: string) { diff --git a/src/utils/mouseEvent.tsx b/src/utils/mouseEvent.tsx index c880b335..dda81518 100644 --- a/src/utils/mouseEvent.tsx +++ b/src/utils/mouseEvent.tsx @@ -62,8 +62,8 @@ export const MouseEvent = (rendition: any) => { return false; } }; - - rendition.on("rendered", () => { + let rebind = () => { + console.log("rebind"); let iframe = document.getElementsByTagName("iframe")[0]; if (!iframe) return; let doc = iframe.contentDocument; @@ -72,11 +72,33 @@ export const MouseEvent = (rendition: any) => { } doc.addEventListener("keydown", arrowKeys); // 箭头按键翻页 // 鼠标滚轮翻页 - window.addEventListener("keydown", arrowKeys, false); if (isFirefox) { doc.addEventListener("DOMMouseScroll", mouseFirefox, false); } else { doc.addEventListener("mousewheel", mouseChrome, false); } + }; + let bindEvent = (doc: any) => { + doc.addEventListener("keydown", arrowKeys); // 箭头按键翻页 + // 鼠标滚轮翻页 + if (isFirefox) { + doc.addEventListener("DOMMouseScroll", mouseFirefox, false); + } else { + doc.addEventListener("mousewheel", mouseChrome, false); + } + }; + rendition.on("locationChanged", () => { + let iframe = document.getElementsByTagName("iframe")[0]; + if (!iframe) return; + let doc = iframe.contentDocument; + if (!doc) { + return; + } + // 鼠标滚轮翻页 + window.addEventListener("keydown", arrowKeys); + window.addEventListener("mousewheel", rebind); + window.addEventListener("DOMMouseScroll", rebind); + window.onmousewheel = rebind; + bindEvent(doc); }); }; diff --git a/src/utils/otherUtil.tsx b/src/utils/otherUtil.tsx index c31d8e92..0a9e8962 100644 --- a/src/utils/otherUtil.tsx +++ b/src/utils/otherUtil.tsx @@ -61,7 +61,6 @@ class OtherUtil { static setSortCode(sortCode: number, orderCode: number) { let json = localStorage.getItem("sordCode") || JSON.stringify({ sort: 2, order: 2 }); - console.log(json, json, "json"); let obj = json ? JSON.parse(json) : { sort: 2, order: 2 }; obj.sort = sortCode; obj.order = orderCode; diff --git a/src/utils/readerConfig.tsx b/src/utils/readerConfig.tsx index 910b370a..aec42a67 100644 --- a/src/utils/readerConfig.tsx +++ b/src/utils/readerConfig.tsx @@ -14,7 +14,9 @@ class readerConfig { "style", `background-color:${OtherUtil.getReaderConfig("theme")}` ); - + if (!doc.head) { + return; + } if (!style) { style = doc.createElement("style"); style.id = "default-style"; @@ -38,27 +40,18 @@ export const themeList = [ { id: 3, theme: "rgba(242,219,187,0.8)" }, { id: 4, theme: "rgba(255,254,252,1)" }, ]; -export const fontSizeList = [ - { id: 1, size: "Small", value: "15" }, - { id: 2, size: "Medium", value: "17" }, - { id: 3, size: "Large", value: "20" }, - { id: 4, size: "Extra Large", value: "23" }, - { id: 5, size: "Ultra Large", value: "26" }, -]; + export const updateLog = { - date: "2020.8.23", + date: "2020.9.6", new: [ - "现在您可以给喜爱的图书添加心形标记,并且可以在我的喜爱中找到所有标记过的图书", - "添加书签之后,这一页的右上角会出现书签图标", - "图书操作的UI优化", - ], - fix: [ - "修复笔记,书摘,书签跳转位置不准确的问题", - "修复删除书签导致阅读器崩溃的问题", - "修复阅读进度为NaN的问题", - "修复笔记弹窗超出阅读器范围的问题", - "修复导入图书失败后,图书页面闪烁问题", + "现在 Koodo Reader 支持全书搜索啦", + "客户端版本支持使用本地字体", + "单页模式新增滚动阅读功能", + "新增对epub文件内置样式的支持", + "字体支持任意大小的调节", + "UI细节优化", ], + fix: ["修复图片错页显示的问题", "修复批量导入时,部分图书无法导入的问题"], }; export const dropdownList = [