victorsoares96 / epubjs-react-native

ePub.js Reader for React Native
MIT License
160 stars 51 forks source link

Getting Rendition is not defined while opening and reopening epub book several times #287

Open TalhaAbbas55 opened 5 months ago

TalhaAbbas55 commented 5 months ago

Summary

I am getting an issue of rendition is not defined in both Android and IOS, it shows at random times mostly on real devices and less time on Android and IOS emulator

image image

the message appears differently in IOS and Android, sometimes when I open the book for the first time, it does not appear but when I open the book for a second time, no matter whether it is same book or different from my app, the message appears then there,

a

What platform(s) does this occur on?

Android, iOS

What workflow(s) does this occur on?

Bare Workflow

Environment (or package.json)

{ "name": "aabBooksMobile", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "patch-package && react-native start", "test": "jest", "android-wifi": "adb kill-server && adb tcpip 5555 && adb connect 192.168.0.32:5555 && adb devices", "postinstall": "patch-package"

}, "dependencies": { "@epubjs-react-native/core": "^1.4.4", "@epubjs-react-native/file-system": "^1.1.2", "@react-native-async-storage/async-storage": "^1.22.3", "@react-native-clipboard/clipboard": "^1.14.1", "@react-navigation/bottom-tabs": "^6.5.19", "@react-navigation/native": "^6.1.16", "@react-navigation/native-stack": "^6.9.25", "@reduxjs/toolkit": "^2.2.2", "axios": "^1.6.8", "eventemitter3": "^5.0.1", "patch-package": "^8.0.0", "react": "18.2.0", "react-native": "0.73.6", "react-native-bouncy-checkbox": "^3.0.7", "react-native-dropdown-select-list": "^2.0.5", "react-native-element-dropdown": "^2.10.4", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.16.0", "react-native-global-font": "^1.0.3", "react-native-popup-menu": "^0.16.1", "react-native-range-slider": "^0.1.2", "react-native-raw-bottom-sheet": "^3.0.0", "react-native-reanimated": "^3.8.1", "react-native-reanimated-carousel": "^3.5.1", "react-native-safe-area-context": "^4.9.0", "react-native-screens": "^3.29.0", "react-native-simple-dialogs": "^2.0.3", "react-native-snap-carousel": "^4.0.0-beta.6", "react-native-swipe-gestures": "^1.0.5", "react-native-webview": "^13.8.4", "react-redux": "^9.1.0", "rn-range-slider": "^2.2.2" }, "devDependencies": { "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", "@react-native/babel-preset": "0.73.21", "@react-native/eslint-config": "0.73.2", "@react-native/js-polyfills": "^0.75.0-main", "@react-native/metro-babel-transformer": "^0.75.0-main", "@react-native/metro-config": "^0.73.5", "@react-native/typescript-config": "0.73.1", "@types/react": "^18.2.6", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", "eslint": "^8.19.0", "jest": "^29.6.3", "metro-config": "^0.80.7", "metro-runtime": "^0.80.7", "prettier": "2.8.8", "react-native-svg": "^15.1.0", "react-native-svg-transformer": "^1.3.0", "react-test-renderer": "18.2.0", "typescript": "5.0.4" }, "engines": { "node": ">=18" } }

Your .epub file

https://aab-book-stag.s3.eu-west-2.amazonaws.com/65718a24835592f22a309948/9780853304029.epub

Minimal reproducible example

I produced this bug while working on this code

function Inner({
  link,
  setNavigation,
  fontSize,
  fontFamily,
  theme,
  lineheight,
  bookMarkData,
  selectedBook,
  isDrawerOpen,
}) {
  const dispatch = useDispatch();
  const {width, height} = useWindowDimensions();
  const {
    goNext,
    goPrevious,
    goToLocation,
    changeTheme,
    getCurrentLocation,
    changeFontFamily,
    changeFontSize,
    onAddAnnotation,
    removeAnnotation,
    removeAnnotationByCfi,
    addMark,
    removeMark,
    addAnnotation,
    section,
    removeSelection,
    injectJavascript,
  } = useReader();

  injectJavascript('console.log("Hello World")');

  const currentLocation = useSelector(state => state.location.value);
  const [enableSelection, setEnableSelection] = useState(true);
  const [currentSelection, setCurrentSelection] = useState({});
  const [showColorModal, setShowColorModal] = useState(false);
  const [enableSwipe, setEnableSwipe] = useState(false);
  const index = currentLocation?.start?.index;
  const [allHighLights, setAllHighLights] = useState([]);
  const [key, setKey] = useState(0);

  const getAllHighLights = async index => {
    const highLights = await getApiWithAuth(
      `${HIGHLIGHTS}?chapterNo=${index}&bookId=${selectedBook._id}`,
    );
    if (highLights.success) {
      setAllHighLights(highLights.data.data);
      highLights.data.data.forEach(highLight => {
        removeAnnotationByCfi(highLight.hightLight.cfiRange);
        addAnnotation('highlight', highLight.hightLight.cfiRange, undefined, {
          color: highLight.color,
        });
      });
    } else {
      dispatch(setToastMessage('Error Fetching Highlights'));
      dispatch(setShowToast());
    }
  };

  useEffect(() => {
    getAllHighLights(index);
  }, [index]);

  const cords = useRef({x: 0, y: 0});

  const handleGoToLocation = location => {
    goToLocation(location);
  };

  useEffect(() => {
    setKey(key + 1);
  }, []);

  useEffect(() => {
    if (bookMarkData) {
      // console.log('yess------', bookMarkData.start.cfiRange);
      setTimeout(() => {
        handleGoToLocation(bookMarkData?.start?.cfiRange);
      }, 2000); // 2000 milliseconds = 2 seconds
    }
  }, [bookMarkData]);
  useEffect(() => {
    changeFontFamily(fontFamily);
    changeFontSize(`${fontSize}px`);
    const customizedTheme = {...themes[theme]};
    // Assuming `p` tag is what you want to target, but adjust as necessary
    customizedTheme.p = {
      ...customizedTheme.p,
      'line-height': `${Math.round(lineheight + 100 / 10)}px !important`, // Apply dynamic line height
    };

    changeTheme(customizedTheme);
  }, [fontSize, fontFamily, theme, lineheight]);

  const config = {
    velocityThreshold: 0.3,
    directionalOffsetThreshold: 80,
    gestureIsClickThreshold: 5,
  };

  const handleHighlighColor = async (color: string) => {
    annotationsListRef.current?.close();
    setTimeout(() => {
      setShowColorModal(false);
    }, 150);

    let oldHighLight = allHighLights.find(
      oneHighlight =>
        oneHighlight?.hightLight?.cfiRange === currentSelection?.cfiRange,
    );

    if (color === 'none') {
      removeAnnotationByCfi(currentSelection.cfiRange);

      setCurrentSelection({});
      if (oldHighLight?._id) {
        const response = await deleteApi(`${HIGHLIGHTS}${oldHighLight?._id}`);

        if (!response.success) {
          dispatch(setToastMessage('Error Removing Highlight'));
          dispatch(setShowToast());
          return;
        }

        dispatch(setToastMessage('Highlight Removed'));
        dispatch(setShowToast());
        setAllHighLights(
          allHighLights.filter(highLight => highLight._id !== oldHighLight._id),
        );
      }
      return;
    }

    removeAnnotationByCfi(currentSelection.cfiRange);
    addAnnotation('highlight', currentSelection.cfiRange, undefined, {
      color: color,
    });

    if (oldHighLight?._id) {
      const response = await patchApiWithAuth(
        `${HIGHLIGHTS}?_id=${oldHighLight?._id}`,
        {
          color,
        },
      );

      if (!response.success) {
        dispatch(setToastMessage('Error Changing Highlight Color'));
        dispatch(setShowToast());
        return;
      }

      dispatch(setToastMessage('Highlight Color Changed'));
      dispatch(setShowToast());

      const tempAllHighLights = allHighLights.map(highLight => {
        if (highLight._id === oldHighLight._id) {
          return {...highLight, color};
        }
        return highLight;
      });

      return;
    }

    const body = {
      bookId: selectedBook._id,
      chapterNo: currentLocation.start.index,
      color,
      hightLight: {
        chapterId: currentLocation.start.href,
        selectedText: currentSelection.selectedText,
        cfiRange: currentSelection.cfiRange,
      },
    };
    const response = await postAPIWithAuth(HIGHLIGHTS, body);
    if (!response.success) {
      dispatch(setToastMessage('Error Adding Highlight'));
      dispatch(setShowToast());
      return;
    }
    const tempAllHighLights = [...allHighLights, response.data.data];
    setAllHighLights(tempAllHighLights);
    tempAllHighLights.forEach(highLight => {
      removeAnnotationByCfi(highLight.hightLight.cfiRange);
      addAnnotation('highlight', highLight.hightLight.cfiRange, undefined, {
        color: highLight.color,
      });
    });
    dispatch(setToastMessage('Highlight Added'));
    dispatch(setShowToast());

    setCurrentSelection({});
  };

  const onSwipe = (gestureName, gestureState) => {
    const {SWIPE_LEFT, SWIPE_RIGHT} = swipeDirections;
    // dispatch(currentBookLocation(getCurrentLocation()));

    switch (gestureName) {
      case SWIPE_LEFT:
        goNext();
        break;
      case SWIPE_RIGHT:
        goPrevious();
        break;
    }
  };

  useEffect(() => {
    let timeoutId;

    if (!enableSelection) {
      timeoutId = setTimeout(() => {
        setEnableSelection(true);
      }, 200);
    }

    return () => {
      if (timeoutId) {
        clearTimeout(timeoutId);
      }
    };
  }, [enableSelection]);

  const copyText = () => {
    annotationsListRef.current?.close();
    setTimeout(() => {
      setShowColorModal(false);
    }, 100);
    if (currentSelection?.selectedText) {
      Clipboard.setString(currentSelection?.selectedText);
    } else {
      const currentHighlight = allHighLights.find(
        oneHighlight =>
          oneHighlight?.hightLight?.cfiRange === currentSelection?.cfiRange,
      );

      if (currentHighlight) {
        Clipboard.setString(currentHighlight?.hightLight?.selectedText);
      }
    }

    dispatch(setToastMessage('Text Copied'));
    dispatch(setShowToast());
  };

  const addNotesHandler = () => {
    annotationsListRef.current?.close();

    setTimeout(() => {
      setShowColorModal(false);
    }, 100);
    dispatch(setToastMessage('Feature Coming Soon'));
    dispatch(setShowToast());
  };

  const annotationsListRef = React.useRef(null);

  useEffect(() => {
    if (isDrawerOpen) {
      removeSelection();
    }
  }, [isDrawerOpen]);

  return (
    <>
      <View style={{flex: 1}}>
        <View style={{flex: 1}}>
          <GestureRecognizer
            style={{flex: 1}}
            onSwipe={(direction, state) => {
              setEnableSelection(false); // Disable selection during swipe
              onSwipe(direction, state);
              setTimeout(() => setEnableSelection(true), 300); // Re-enable selection after swipe
            }}
            config={config}>
            <Reader
              onRendered={() => {
                console.log('redderdssdded');
              }}
              onDisplayError={reson => console.log(reson, 'res hskj')}
              // key={key}
              menuItems={[]}
              onPressAnnotation={annotation => {
                setCurrentSelection(annotation);
                setShowColorModal(true);
                annotationsListRef.current.open();
              }}
              allowPopups
              injectedJavascript='console.log("Hello World")'
              getInjectionJavascriptFn={() => {
                return 'console.log("Hello World")';
              }}
              // initialAnnotations={[]}
              src={link}
              width={width - 38}
              height={height - 320}
              fileSystem={useFileSystem}
              onNavigationLoaded={e => {
                setNavigation(e);
              }}
              // defaultTheme={'light'}
              onSelected={(selectedText, cfiRange) => {
                setShowColorModal(true);

                setTimeout(() => {
                  annotationsListRef.current.open();
                }, 150);
                setCurrentSelection({selectedText, cfiRange});
              }}
              enableSelection={enableSelection}
              enableSwipe={enableSwipe}
              onLocationChange={(total, current, progress, currentSEction) => {
                console.log(
                  total,
                  current,
                  progress,
                  currentSEction,
                  'current',
                );
                dispatch(currentBookLocation(current));
                setEnableSelection(false);
              }}
              onReady={() => {
                setEnableSwipe(true);
              }}
              onPressExternalLink={url => {
                Linking.openURL(url).catch(err =>
                  console.error('Failed to open URL:', err),
                );
              }}
            />
          </GestureRecognizer>
        </View>
      </View>

      <AnnotationsOption
        handleHighlighColor={handleHighlighColor}
        refRBSheetRef={annotationsListRef}
        showAnnotationSheet={showColorModal}
        currentSelectionColor={currentSelection?.styles?.color}
        copyText={copyText}
        addNotesHandler={addNotesHandler}
        setShowAnnotationSheet={setShowColorModal}
      />
    </>
  );
}

Also, I am not finding the method to inject the javascript in the component as we do in our web app this way EpubBookWeb

because if I find that way then I can control this by myself

the

I confirm that i have

TalhaAbbas55 commented 5 months ago

hi @victorsoares96 , I appreciate your help I am working on a project for the client and the client is in a hurry, I am also facing a problem while adding or managing bookmarks because my App is available for both mobile and desktop but the bookmark function that this library has doesn't have bookmarks with responsive ideas (means to work on different screen sizes at same time), it only stores the current location of the page which will be different for another device with another size, can you help me in that regard as well

TalhaAbbas55 commented 5 months ago

if I can just get a way to change the characters per location which are right now 1600 ( I checked that from node_modules) then that would be a help

victorsoares96 commented 5 months ago

@TalhaAbbas55 you need a way to change this parameter is that it?

image

source: https://github.com/victorsoares96/epubjs-react-native/blob/master/src/template.ts#L167

TalhaAbbas55 commented 5 months ago

@TalhaAbbas55 you need a way to change this parameter is that it?

image

source: https://github.com/victorsoares96/epubjs-react-native/blob/master/src/template.ts#L167

yes, you got it right

TalhaAbbas55 commented 5 months ago

but this is a separate issue, the issue which I mentioned in title is something else which is unknown to me

TalhaAbbas55 commented 3 months ago

this "rendition is not defined" issue is very serious, did you get the solution for this @victorsoares96 ?

victorsoares96 commented 3 months ago

I believe the problem "rendition is not defined" is being caused by you calling injectJavascript('console.log("Hello World")'); outside of a function, it is probably trying to execute your javascript before initialization of the reader component, please try to remove this snippet or place it in the appropriate location

TalhaAbbas55 commented 2 months ago

hi @victorsoares96 , no still after removing that error "rendition is not defined" after removing injectJavascript('console.log("Hello World")');