From 8dfb4361b870cc618608701c91a12c72e9164507 Mon Sep 17 00:00:00 2001 From: CD-Z Date: Mon, 29 May 2023 16:39:51 +0200 Subject: [PATCH 1/3] Export to Epub --- package-lock.json | 237 ++++++++++++++++++ package.json | 3 + src/screens/novel/NovelScreen.js | 13 +- .../novel/components/EpubIconButton.tsx | 156 ++++++++++++ .../Modal/ChooseEpubLocationModal.tsx | 151 +++++++++++ .../{ => Modal}/DownloadCustomChapterModal.js | 2 +- .../components/{ => Modal}/EditInfoModal.js | 4 +- .../{ => Modal}/JumpToChapterModal.js | 0 .../SettingsGeneralScreen.tsx | 27 ++ strings/languages/en/strings.json | 7 + strings/types/index.ts | 5 + 11 files changed, 598 insertions(+), 7 deletions(-) create mode 100644 src/screens/novel/components/EpubIconButton.tsx create mode 100644 src/screens/novel/components/Modal/ChooseEpubLocationModal.tsx rename src/screens/novel/components/{ => Modal}/DownloadCustomChapterModal.js (97%) rename src/screens/novel/components/{ => Modal}/EditInfoModal.js (97%) rename src/screens/novel/components/{ => Modal}/JumpToChapterModal.js (100%) diff --git a/package-lock.json b/package-lock.json index 933cbe477..2d649559a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "lnreader", "version": "1.1.15", "dependencies": { + "@cd-z/react-native-epub-creator": "^1.3.3", "@gorhom/bottom-sheet": "^4.4.5", "@react-native-async-storage/async-storage": "^1.18.1", "@react-native-community/clipboard": "^1.5.1", @@ -52,6 +53,7 @@ "react-native-pager-view": "^6.2.0", "react-native-paper": "^5.7.2", "react-native-reanimated": "~2.9.1", + "react-native-saf-x": "^2.2.1", "react-native-safe-area-context": "4.3.1", "react-native-screens": "~3.15.0", "react-native-shimmer-placeholder": "^2.0.9", @@ -59,6 +61,7 @@ "react-native-tts": "^4.1.0", "react-native-vector-icons": "^9.0.0", "react-native-webview": "11.23.0", + "react-native-zip-archive": "^6.0.9", "react-redux": "^7.2.6", "redux-persist": "^6.0.0", "rn-fetch-blob": "^0.12.0", @@ -1875,6 +1878,40 @@ "react": ">=16.3.0" } }, + "node_modules/@cd-z/epub-constructor": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@cd-z/epub-constructor/-/epub-constructor-1.2.0.tgz", + "integrity": "sha512-IhqBurhHHES1Z5bveRu7nPJgyvmJd1SM2xZi5sfmAG+HBCVfZu9Fpekw9I2GrAA2ZSPpvPJ9y5W3fu7lMJuLdw==", + "dependencies": { + "node-html-parser": "^4.1.4" + } + }, + "node_modules/@cd-z/react-native-epub-creator": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@cd-z/react-native-epub-creator/-/react-native-epub-creator-1.3.3.tgz", + "integrity": "sha512-VvYTHhU911WM56sCX0Gvut+gK9zlhp3rp+9FISDGq8qz5ytgS/XhU7CNrAmwOmJSVZ22ox9N+b8jpGZTl094yA==", + "dependencies": { + "@cd-z/epub-constructor": "^1.2.0", + "expo-file-system": "^15.2.2", + "react-native-saf-x": "^2.2.1", + "react-native-zip-archive": "^6.0.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/@cd-z/react-native-epub-creator/node_modules/expo-file-system": { + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.2.2.tgz", + "integrity": "sha512-LFkOLcWwlmnjkURxZ3/0ukS35OswX8iuQknLHRHeyk8mUA8fpRPPelD/a1lS+yclqfqavMJmTXVKM1Nsq5XVMA==", + "dependencies": { + "uuid": "^3.4.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/@egjs/hammerjs": { "version": "2.0.17", "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", @@ -10256,6 +10293,14 @@ "node": ">=0.10.0" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, "node_modules/hermes-engine": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz", @@ -13444,6 +13489,78 @@ "node": ">= 6.13.0" } }, + "node_modules/node-html-parser": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-4.1.5.tgz", + "integrity": "sha512-NLgqUXtftqnBqIjlRjYSaApaqE7TTxfTiH4VqKCjdUJKFOtUzRwney83EHz2qYc0XoxXAkYdmLjENCuZHvsIFg==", + "dependencies": { + "css-select": "^4.1.3", + "he": "1.2.0" + } + }, + "node_modules/node-html-parser/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/node-html-parser/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/node-html-parser/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -15031,6 +15148,15 @@ "react-native": "*" } }, + "node_modules/react-native-saf-x": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-native-saf-x/-/react-native-saf-x-2.2.1.tgz", + "integrity": "sha512-WL8EFpmjlTTVrHkIFmLzfux3ZpG+XM32VLjggEvGoz8rMq6bCFqH/SlqudHfnAUdFrWprQwypJ451xcQ5Tqwgw==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-safe-area-context": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.3.1.tgz", @@ -15194,6 +15320,15 @@ "node": ">=8" } }, + "node_modules/react-native-zip-archive": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-native-zip-archive/-/react-native-zip-archive-6.0.9.tgz", + "integrity": "sha512-IYf3yHJ7sHzj9ucO3Amx/TtsZcTgHdfj+Dar8p1e32E+wBsn7mv0PDp2X/oCLGci0nG9i2DBstrnCW74/7NLYQ==", + "peerDependencies": { + "react": ">=16.8.6", + "react-native": ">=0.60.0" + } + }, "node_modules/react-native/node_modules/@jest/types": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", @@ -19368,6 +19503,35 @@ "hoist-non-react-statics": "^3.3.0" } }, + "@cd-z/epub-constructor": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@cd-z/epub-constructor/-/epub-constructor-1.2.0.tgz", + "integrity": "sha512-IhqBurhHHES1Z5bveRu7nPJgyvmJd1SM2xZi5sfmAG+HBCVfZu9Fpekw9I2GrAA2ZSPpvPJ9y5W3fu7lMJuLdw==", + "requires": { + "node-html-parser": "^4.1.4" + } + }, + "@cd-z/react-native-epub-creator": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@cd-z/react-native-epub-creator/-/react-native-epub-creator-1.3.3.tgz", + "integrity": "sha512-VvYTHhU911WM56sCX0Gvut+gK9zlhp3rp+9FISDGq8qz5ytgS/XhU7CNrAmwOmJSVZ22ox9N+b8jpGZTl094yA==", + "requires": { + "@cd-z/epub-constructor": "^1.2.0", + "expo-file-system": "^15.2.2", + "react-native-saf-x": "^2.2.1", + "react-native-zip-archive": "^6.0.3" + }, + "dependencies": { + "expo-file-system": { + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.2.2.tgz", + "integrity": "sha512-LFkOLcWwlmnjkURxZ3/0ukS35OswX8iuQknLHRHeyk8mUA8fpRPPelD/a1lS+yclqfqavMJmTXVKM1Nsq5XVMA==", + "requires": { + "uuid": "^3.4.0" + } + } + } + }, "@egjs/hammerjs": { "version": "2.0.17", "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", @@ -25708,6 +25872,11 @@ } } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, "hermes-engine": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz", @@ -28126,6 +28295,62 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" }, + "node-html-parser": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-4.1.5.tgz", + "integrity": "sha512-NLgqUXtftqnBqIjlRjYSaApaqE7TTxfTiH4VqKCjdUJKFOtUzRwney83EHz2qYc0XoxXAkYdmLjENCuZHvsIFg==", + "requires": { + "css-select": "^4.1.3", + "he": "1.2.0" + }, + "dependencies": { + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -29350,6 +29575,12 @@ "string-hash-64": "^1.0.3" } }, + "react-native-saf-x": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-native-saf-x/-/react-native-saf-x-2.2.1.tgz", + "integrity": "sha512-WL8EFpmjlTTVrHkIFmLzfux3ZpG+XM32VLjggEvGoz8rMq6bCFqH/SlqudHfnAUdFrWprQwypJ451xcQ5Tqwgw==", + "requires": {} + }, "react-native-safe-area-context": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.3.1.tgz", @@ -29473,6 +29704,12 @@ } } }, + "react-native-zip-archive": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-native-zip-archive/-/react-native-zip-archive-6.0.9.tgz", + "integrity": "sha512-IYf3yHJ7sHzj9ucO3Amx/TtsZcTgHdfj+Dar8p1e32E+wBsn7mv0PDp2X/oCLGci0nG9i2DBstrnCW74/7NLYQ==", + "requires": {} + }, "react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", diff --git a/package.json b/package.json index ed63a4318..dcbc13c5e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "prepare": "husky install" }, "dependencies": { + "@cd-z/react-native-epub-creator": "^1.3.3", "@gorhom/bottom-sheet": "^4.4.5", "@react-native-async-storage/async-storage": "^1.18.1", "@react-native-community/clipboard": "^1.5.1", @@ -60,6 +61,7 @@ "react-native-pager-view": "^6.2.0", "react-native-paper": "^5.7.2", "react-native-reanimated": "~2.9.1", + "react-native-saf-x": "^2.2.1", "react-native-safe-area-context": "4.3.1", "react-native-screens": "~3.15.0", "react-native-shimmer-placeholder": "^2.0.9", @@ -67,6 +69,7 @@ "react-native-tts": "^4.1.0", "react-native-vector-icons": "^9.0.0", "react-native-webview": "11.23.0", + "react-native-zip-archive": "^6.0.9", "react-redux": "^7.2.6", "redux-persist": "^6.0.0", "rn-fetch-blob": "^0.12.0", diff --git a/src/screens/novel/NovelScreen.js b/src/screens/novel/NovelScreen.js index 37ac26b2f..1099a9911 100644 --- a/src/screens/novel/NovelScreen.js +++ b/src/screens/novel/NovelScreen.js @@ -49,17 +49,18 @@ import NovelInfoHeader from './components/Info/NovelInfoHeader'; import NovelBottomSheet from './components/NovelBottomSheet'; import TrackSheet from './components/Tracker/TrackSheet'; import { Row } from '../../components/Common'; -import JumpToChapterModal from './components/JumpToChapterModal'; +import JumpToChapterModal from './components/Modal/JumpToChapterModal'; import { Actionbar } from '../../components/Actionbar/Actionbar'; -import EditInfoModal from './components/EditInfoModal'; +import EditInfoModal from './components/Modal/EditInfoModal'; import { pickCustomNovelCover } from '../../database/queries/NovelQueries'; -import DownloadCustomChapterModal from './components/DownloadCustomChapterModal'; +import DownloadCustomChapterModal from './components/Modal/DownloadCustomChapterModal'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import useBoolean from '@hooks/useBoolean'; import { useCategorySettings } from '@hooks/useSettings'; import { openChapter } from '../../utils/handleNavigateParams'; import NovelScreenLoading from './components/LoadingAnimation/NovelScreenLoading'; import { useTrackerReducer } from '@redux/hooks'; +import EpubIconButton from './components/EpubIconButton'; const Novel = ({ route, navigation }) => { const item = route.params; @@ -535,7 +536,11 @@ const Novel = ({ route, navigation }) => { } /> - + showExtraMenu(false)} diff --git a/src/screens/novel/components/EpubIconButton.tsx b/src/screens/novel/components/EpubIconButton.tsx new file mode 100644 index 000000000..7c0fe49e9 --- /dev/null +++ b/src/screens/novel/components/EpubIconButton.tsx @@ -0,0 +1,156 @@ +import * as React from 'react'; +import useBoolean from '@hooks/useBoolean'; +import { IconButton, Portal } from 'react-native-paper'; +import ChooseEpubLocationModal from './Modal/ChooseEpubLocationModal'; +import { Dimensions, StatusBar, StyleProp } from 'react-native'; +import { IconProps } from 'react-native-paper/lib/typescript/src/components/MaterialCommunityIcon'; +import { ThemeColors } from '@theme/types'; + +import EpubBuilder from '@cd-z/react-native-epub-creator'; +import { ChapterItem, LibraryNovelInfo } from '@database/types'; +import { showToast } from '@hooks/showToast'; +import { getChapterFromDb } from '@database/queries/DownloadQueries'; +import { useReaderSettings } from '@redux/hooks'; + +interface extendedNovelInfo extends LibraryNovelInfo { + chapters: ChapterItem[]; +} +interface EpubIconButtonProps { + theme: ThemeColors; + style: StyleProp; + novel: extendedNovelInfo; +} + +const EpubIconButton: React.FC = ({ + theme, + style, + novel, +}) => { + const chooseEpubLocationModal = useBoolean(false); + const readerSettings = useReaderSettings(); + const layoutHeight = Dimensions.get('window').height; + const epubStyle = `html { + scroll-behavior: smooth; + overflow-x: hidden; + padding-top: ${StatusBar.currentHeight}; + word-wrap: break-word; + } + body { + padding-left: ${readerSettings.padding}%; + padding-right: ${readerSettings.padding}%; + padding-bottom: 40px; + font-size: ${readerSettings.textSize}px; + color: ${readerSettings.textColor}; + text-align: ${readerSettings.textAlign}; + line-height: ${readerSettings.lineHeight}; + font-family: "${readerSettings.fontFamily}"; + } + chapter{ + display: block; + } + hr { + margin-top: 20px; + margin-bottom: 20px; + } + a { + color: ${theme.primary}; + } + img { + display: block; + width: auto; + height: auto; + max-width: 100%; + } + + .nextButton, + .infoText { + width: 100%; + border-radius: 50px; + border-width: 1; + color: ${theme.onPrimary}; + background-color: ${theme.primary}; + font-family: ${readerSettings.fontFamily}; + font-size: 16px; + border-width: 0; + } + .nextButton { + min-height: 40px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + padding: 0 16px; + } + .infoText { + background-color: transparent; + text-align:center; + border: none; + margin: 0px; + color: inherit; + padding-top: 16px; + padding-bottom: 16px; + } + .chapterCtn { + min-height: ${layoutHeight - 140}; + margin-bottom: auto; + } ${readerSettings.customCSS}`; + + const createEpub = async (uri: string) => { + var epub = new EpubBuilder( + { + title: novel.novelName, + fileName: novel.novelName.replace(/\s/g, ''), + language: 'en', + cover: novel.novelCover, + description: novel.novelSummary, + author: novel.author, + bookId: novel.novelId.toString(), + stylesheet: epubStyle, + }, + uri, + ); + try { + // save and create the .epub file + await epub.prepare(); + for (let i = 0; i < novel.chapters.length; i++) { + const chapter = novel.chapters[i]; + if (chapter.downloaded) { + const downloaded = await getChapterFromDb(chapter.chapterId); + + await epub.addChapter({ + title: downloaded.chapterName?.trim() ?? 'Chapter ' + i, + fileName: 'Chapter' + i, + htmlBody: downloaded.chapterText, + }); + } + } + var epubFilePath = await epub.save(); + showToast('Epub file saved at: ' + epubFilePath); + } catch (error) { + // remove the temp created folder + showToast('Cannot create because: ' + error); + console.error(error); + + await epub.discardChanges(); + } + }; + + return ( + <> + + + + + + ); +}; +export default EpubIconButton; diff --git a/src/screens/novel/components/Modal/ChooseEpubLocationModal.tsx b/src/screens/novel/components/Modal/ChooseEpubLocationModal.tsx new file mode 100644 index 000000000..c97dcb4d7 --- /dev/null +++ b/src/screens/novel/components/Modal/ChooseEpubLocationModal.tsx @@ -0,0 +1,151 @@ +import React, { useState } from 'react'; +import { StyleSheet, View } from 'react-native'; +import { getString } from '@strings/translations'; +import { Button } from '@components'; + +import { Modal, Portal, TextInput, Text } from 'react-native-paper'; +import { useTheme } from '@hooks/useTheme'; +import { useSettings } from '@hooks/reduxHooks'; +import { openDocumentTree } from 'react-native-saf-x'; + +interface ChooseEpubLocationModalProps { + hideModal: () => void; + modalVisible: boolean; + onSubmit: (uri: string) => void; +} + +const ChooseEpubLocationModal: React.FC = ({ + hideModal, + modalVisible, + onSubmit: onSubmitProp, +}) => { + const { epubLocation = '' } = useSettings(); + const theme = useTheme(); + const [uri, setUri] = useState(epubLocation); + const [error, setError] = useState(''); + + const onDismiss = () => { + hideModal(); + setError(''); + setUri(epubLocation); + }; + + const onChangeText = (txt: string) => { + setUri(txt); + }; + + const onSubmit = () => { + onSubmitProp(uri); + hideModal(); + }; + + const openFolderPicker = async () => { + try { + const resultUri = await openDocumentTree(true); + if (resultUri) { + setUri(resultUri.uri); + } + } catch (err) { + console.log(err); + } + }; + + return ( + + + + + {getString('novelScreen.convertToEpubModal.chooseLocation')} + + + + } + /> + + + +