diff --git a/src/pages/Importer/Index.tsx b/src/pages/Importer/Index.tsx index c35e231..3b272f0 100644 --- a/src/pages/Importer/Index.tsx +++ b/src/pages/Importer/Index.tsx @@ -3,7 +3,7 @@ import { StackScreenProps } from '@react-navigation/stack'; import { BarCodeScannedCallback, BarCodeScanner } from 'expo-barcode-scanner'; import React, { FC, useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Button, Text, TextInput } from 'react-native-paper'; +import { Button, MD3Colors, ProgressBar, Text, TextInput } from 'react-native-paper'; import { styled } from 'styled-components/native'; import { RootStackParameterList } from '../../App'; import { useImportHTML } from './useImportHTML'; @@ -73,7 +73,7 @@ export const Importer: FC> } }, [scannedString]); - const { error: importError, status: importStatus, storeHtml, importedWikiWorkspace } = useImportHTML(); + const { error: importError, status: importStatus, storeHtml, downloadPercentage, createdWikiWorkspace } = useImportHTML(); if (hasPermission === undefined) { return Requesting for camera permission; @@ -118,21 +118,37 @@ export const Importer: FC> )} {importStatus === 'error' - ? Error: {importError} + ? ( + + Error: + {importError} + + ) : ( <> - Status: {importStatus} - {importedWikiWorkspace !== undefined && ( - - )} + + Status: + {importStatus} + )} + {importStatus === 'downloading' && ( + <> + HTML + + Tiddlers + + + )} + {importStatus === 'success' && createdWikiWorkspace !== undefined && ( + + )} ); }; diff --git a/src/pages/Importer/useImportHTML.ts b/src/pages/Importer/useImportHTML.ts index 2075a81..5c4e574 100644 --- a/src/pages/Importer/useImportHTML.ts +++ b/src/pages/Importer/useImportHTML.ts @@ -5,13 +5,16 @@ import { useCallback, useState } from 'react'; import { getWikiFilePath, getWikiTiddlerStorePath, WIKI_FOLDER_PATH } from '../../constants/paths'; import { IWikiWorkspace, useWikiStore } from '../../store/wiki'; -type StoreHtmlStatus = 'idle' | 'fetching' | 'creating' | 'storing' | 'success' | 'error'; +type StoreHtmlStatus = 'idle' | 'fetching' | 'creating' | 'downloading' | 'success' | 'error'; export function useImportHTML() { const [status, setStatus] = useState('idle'); const [error, setError] = useState(); + const [skinnyHtmlDownloadPercentage, setSkinnyHtmlDownloadPercentage] = useState(0); + const [tiddlerStoreScriptDownloadPercentage, setTiddlerStoreScriptDownloadPercentage] = useState(0); const addWiki = useWikiStore(state => state.add); - const [importedWikiWorkspace, setImportedWikiWorkspace] = useState(); + const removeWiki = useWikiStore(state => state.remove); + const [createdWikiWorkspace, setCreatedWikiWorkspace] = useState(); const storeHtml = useCallback(async (urlString: string, wikiName: string) => { if (WIKI_FOLDER_PATH === undefined) return; @@ -21,31 +24,55 @@ export function useImportHTML() { getSkinnyTiddlywikiTiddlerStoreScriptUrl.pathname = '/tw-mobile-sync/get-skinny-tiddlywiki-tiddler-store-script'; // Fetch the HTML content + let newWorkspaceID: string | undefined; try { - const html = await fetch(getSkinnyHTMLUrl).then(response => response.text()); - const tiddlerStoreScript = await fetch(getSkinnyTiddlywikiTiddlerStoreScriptUrl).then(response => response.text()); - setStatus('creating'); // Save the HTML to a file - const workspace = addWiki({ name: wikiName }); - if (workspace === undefined) throw new Error('Failed to create workspace'); + const newWorkspace = addWiki({ name: wikiName }); + if (newWorkspace === undefined) throw new Error('Failed to create workspace'); + newWorkspaceID = newWorkspace.id; try { // make main folder - await fs.makeDirectoryAsync(workspace.wikiFolderLocation); + await fs.makeDirectoryAsync(newWorkspace.wikiFolderLocation); } catch {} - setStatus('storing'); - await fs.writeAsStringAsync(getWikiFilePath(workspace), html); - await fs.writeAsStringAsync(getWikiTiddlerStorePath(workspace), tiddlerStoreScript); - setImportedWikiWorkspace(workspace); + setCreatedWikiWorkspace(newWorkspace); + setStatus('downloading'); + const htmlDownloadResumable = fs.createDownloadResumable(getSkinnyHTMLUrl.toString(), getWikiFilePath(newWorkspace), {}, (progress) => { + setSkinnyHtmlDownloadPercentage(progress.totalBytesWritten / progress.totalBytesExpectedToWrite); + }); + const tiddlerStoreDownloadResumable = fs.createDownloadResumable( + getSkinnyTiddlywikiTiddlerStoreScriptUrl.toString(), + getWikiTiddlerStorePath(newWorkspace), + {}, + (progress) => { + setTiddlerStoreScriptDownloadPercentage(progress.totalBytesWritten / progress.totalBytesExpectedToWrite); + }, + ); + await Promise.all([ + htmlDownloadResumable.downloadAsync(), + tiddlerStoreDownloadResumable.downloadAsync(), + ]); setStatus('success'); } catch (error) { console.error(error, (error as Error).stack); setError((error as Error).message || 'An error occurred'); setStatus('error'); + if (newWorkspaceID !== undefined) { + removeWiki(newWorkspaceID); + } } - }, [addWiki]); + }, [addWiki, removeWiki]); - return { storeHtml, status, error, importedWikiWorkspace }; + return { + storeHtml, + status, + error, + createdWikiWorkspace, + downloadPercentage: { + skinnyHtmlDownloadPercentage, + tiddlerStoreScriptDownloadPercentage, + }, + }; }