diff --git a/README.md b/README.md
index 6502490..4982408 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# react-native-image-cache-wrapper
+# react-native-image-cache-wrapper - Strange error fixed version - Алдаа зассан хувилбар
[](https://www.npmjs.com/package/react-native-image-cache-wrapper)
The best react native image cache wrapper.
diff --git a/index.js b/index.js
index 8779642..fbec0c7 100644
--- a/index.js
+++ b/index.js
@@ -5,216 +5,269 @@
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
-'use strict';
-import React, {Component} from 'react';
-import {
- View,
- Image,
- ImageBackground,
- Platform
-} from 'react-native';
+"use strict";
+import React, { Component } from "react";
+import { View, Image, ImageBackground, Platform } from "react-native";
-import RNFetchBlob from 'rn-fetch-blob';
+import RNFetchBlob from "rn-fetch-blob";
+import RNFS from "react-native-fs";
+const SHA1 = require("crypto-js/sha1");
-const SHA1 = require('crypto-js/sha1');
-
-const defaultImageTypes = ['png', 'jpeg', 'jpg', 'gif', 'bmp', 'tiff', 'tif'];
+const defaultImageTypes = ["png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif"];
export default class CachedImage extends Component {
-
- static defaultProps = {
- expiration: 86400 * 7, // default cache a week
- activityIndicator: null, // default not show an activity indicator
- };
-
- static cacheDir = RNFetchBlob.fs.dirs.CacheDir + "/CachedImage/";
-
- /**
- * delete a cache file
- * @param url
- */
- static deleteCache = url => {
- const cacheFile = _getCacheFilename(url);
- return _unlinkFile(cacheFile);
- };
-
- /**
- * clear all cache files
- */
- static clearCache = () => _unlinkFile(CachedImage.cacheDir);
-
- /**
- * check if a url is cached
- */
- static isUrlCached = (url: string, success: Function, failure: Function) => {
- const cacheFile = _getCacheFilename(url);
- RNFetchBlob.fs.exists(cacheFile)
- .then((exists) => {
- success && success(exists);
- })
- .catch((error) => {
- failure && failure(error);
- });
- };
-
- /**
- * make a cache filename
- * @param url
- * @returns {string}
- */
- static getCacheFilename = (url) => {
- return _getCacheFilename(url);
+ static defaultProps = {
+ expiration: 86400 * 7, // default cache a week
+ activityIndicator: null // default not show an activity indicator
+ };
+
+ static cacheDir = RNFetchBlob.fs.dirs.CacheDir + "/CachedImage/";
+
+ static sameURL = [];
+ /**
+ * delete a cache file
+ * @param url
+ */
+ static deleteCache = url => {
+ const cacheFile = _getCacheFilename(url);
+ CachedImage.sameURL.splice(CachedImage.sameURL.indexOf(cacheFile));
+
+ return _unlinkFile(cacheFile);
+ };
+
+ /**
+ * clear all cache files
+ */
+ static clearCache = async () => {
+ let obj = await RNFS.readDir(CachedImage.cacheDir);
+
+ for (let file of obj) {
+ _unlinkFile(file.path);
}
-
- /**
- * Same as ReactNaive.Image.getSize only it will not download the image if it has a cached version
- * @param url
- * @param success callback (width,height)=>{}
- * @param failure callback (error:string)=>{}
- */
- static getSize = (url: string, success: Function, failure: Function) => {
-
- CachedImage.prefetch(url, 0,
- (cacheFile) => {
- if (Platform.OS === 'android') {
- url = "file://" + cacheFile;
- } else {
- url = cacheFile;
- }
- Image.getSize(url, success, failure);
- },
- (error) => {
- Image.getSize(url, success, failure);
- });
-
- };
-
- /**
- * prefech an image
- *
- * @param url
- * @param expiration if zero or not set, no expiration
- * @param success callback (cacheFile:string)=>{}
- * @param failure callback (error:string)=>{}
- */
- static prefetch = (url: string, expiration: number, success: Function, failure: Function) => {
-
- // source invalidate
- if (!url || url.toString() !== url) {
- failure && failure("no url.");
- return;
+ CachedImage.sameURL = [];
+ };
+
+ static async getCacheSize() {
+ let hasCachedImageFolder = await RNFS.exists(CachedImage.cacheDir);
+ if (hasCachedImageFolder) {
+ let obj = await RNFS.readDir(CachedImage.cacheDir);
+ let size = 0;
+ for (let item of obj) {
+ size += item.size;
+ }
+ return (size / 1024 / 1024).toFixed(2);
+ }
+ return 0;
+ }
+
+ /**
+ * check if a url is cached
+ */
+ static isUrlCached = (url: string, success: Function, failure: Function) => {
+ const cacheFile = _getCacheFilename(url);
+ RNFetchBlob.fs
+ .exists(cacheFile)
+ .then(exists => {
+ success && success(exists);
+ })
+ .catch(error => {
+ failure && failure(error);
+ });
+ };
+
+ /**
+ * make a cache filename
+ * @param url
+ * @returns {string}
+ */
+ static getCacheFilename = url => {
+ return _getCacheFilename(url);
+ };
+
+ /**
+ * Same as ReactNaive.Image.getSize only it will not download the image if it has a cached version
+ * @param url
+ * @param success callback (width,height)=>{}
+ * @param failure callback (error:string)=>{}
+ */
+ static getSize = (url: string, success: Function, failure: Function) => {
+ CachedImage.prefetch(
+ url,
+ 0,
+ cacheFile => {
+ if (Platform.OS === "android") {
+ url = "file://" + cacheFile;
+ } else {
+ url = cacheFile;
}
-
- const cacheFile = _getCacheFilename(url);
-
- RNFetchBlob.fs.stat(cacheFile)
- .then((stats) => {
- // if exist and not expired then use it.
- if (!Boolean(expiration) || (expiration * 1000 + stats.lastModified) > (new Date().getTime())) {
- success && success(cacheFile);
- } else {
- _saveCacheFile(url, success, failure);
- }
- })
- .catch((error) => {
- // not exist
- _saveCacheFile(url, success, failure);
- });
- };
-
- constructor(props) {
-
- super(props);
- this.state = {
- source: null,
- };
-
- this._useDefaultSource = false;
- this._downloading = false;
- this._mounted = false;
+ Image.getSize(url, success, failure);
+ },
+ error => {
+ Image.getSize(url, success, failure);
+ }
+ );
+ };
+
+ /**
+ * prefech an image
+ *
+ * @param url
+ * @param expiration if zero or not set, no expiration
+ * @param success callback (cacheFile:string)=>{}
+ * @param failure callback (error:string)=>{}
+ */
+ static prefetch = (
+ url: string,
+ expiration: number,
+ success: Function,
+ failure: Function
+ ) => {
+ // source invalidate
+ if (!url || url.toString() !== url) {
+ failure && failure("no url.");
+ return;
}
- componentDidMount() {
- this._mounted = true;
+ const cacheFile = _getCacheFilename(url);
+ if (CachedImage.sameURL.includes(cacheFile)) {
+ success && success(cacheFile);
+ return;
}
+ CachedImage.sameURL.push(cacheFile);
+
+ RNFetchBlob.fs
+ .stat(cacheFile)
+ .then(stats => {
+ // if exist and not expired then use it.
+ if (
+ !Boolean(expiration) ||
+ expiration * 1000 + stats.lastModified > new Date().getTime()
+ ) {
+ success && success(cacheFile);
+ } else {
+ _saveCacheFile(url, success, failure);
+ }
+ })
+ .catch(error => {
+ // not exist
+ // success && success(cacheFile)
+
+ _saveCacheFile(url, success, failure);
+ });
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ source: null
+ };
- componentWillUnmount() {
- this._mounted = false;
+ this._useDefaultSource = false;
+ this._downloading = false;
+ this._mounted = false;
+ }
+
+ componentDidMount() {
+ this._mounted = true;
+ }
+
+ componentWillUnmount() {
+ this._mounted = false;
+ }
+
+ render() {
+ if (this.props.source && this.props.source.uri) {
+ if (!this.state.source && !this._downloading) {
+ this._downloading = true;
+ CachedImage.prefetch(
+ this.props.source.uri,
+ this.props.expiration,
+ cacheFile => {
+ setTimeout(() => {
+ if (this._mounted) {
+ this.setState({ source: { uri: "file://" + cacheFile } });
+ }
+ this._downloading = false;
+ }, 0);
+ },
+ error => {
+ // cache failed use original source
+ if (this._mounted) {
+ setTimeout(() => {
+ this.setState({ source: this.props.source });
+ }, 0);
+ }
+ this._downloading = false;
+ }
+ );
+ }
+ } else {
+ this.state.source = this.props.source;
}
- render() {
-
- if (this.props.source && this.props.source.uri) {
- if (!this.state.source && !this._downloading) {
- this._downloading = true;
- CachedImage.prefetch(this.props.source.uri,
- this.props.expiration,
- (cacheFile) => {
- setTimeout(() => {
- if (this._mounted) {
- this.setState({source: {uri: "file://" + cacheFile}});
- }
- this._downloading = false;
- }, 0);
- }, (error) => {
- // cache failed use original source
- if (this._mounted) {
- setTimeout(() => {
- this.setState({source: this.props.source});
- }, 0);
- }
- this._downloading = false;
- });
+ if (this.state.source) {
+ const renderImage = (props, children) =>
+ children != null ? (
+ {children}
+ ) : (
+
+ );
+
+ const result = renderImage(
+ {
+ ...this.props,
+ source: this.state.source,
+ onError: error => {
+ // error happened, delete cache
+ if (this.props.source && this.props.source.uri) {
+ CachedImage.deleteCache(this.props.source.uri);
}
- } else {
- this.state.source = this.props.source;
- }
-
- if (this.state.source) {
-
- const renderImage = (props, children) => (children != null ?
- {children} :
- );
-
- const result = renderImage({
- ...this.props,
- source: this.state.source,
- onError: (error) => {
- // error happened, delete cache
- if (this.props.source && this.props.source.uri) {
- CachedImage.deleteCache(this.props.source.uri);
- }
- if (this.props.onError) {
- this.props.onError(error);
- } else {
- if (!this._useDefaultSource && this.props.defaultSource) {
- this._useDefaultSource = true;
- setTimeout(() => {
- this.setState({source: this.props.defaultSource});
- }, 0);
- }
- }
- }
- }, this.props.children);
-
- return (result);
- } else {
- return (
-
- {this.props.activityIndicator}
- );
- }
+ if (this.props.onError) {
+ this.props.onError(error);
+ } else {
+ if (!this._useDefaultSource && this.props.defaultSource) {
+ this._useDefaultSource = true;
+ setTimeout(() => {
+ if (this.props.source && this.props.source.uri) {
+ this.setState({ source: this.props.source });
+ } else this.setState({ source: this.props.defaultSource });
+ }, 0);
+ }
+ }
+ }
+ },
+ this.props.children
+ );
+
+ return result;
+ } else {
+ return (
+
+ {this.props.activityIndicator}
+
+ );
}
+ }
}
async function _unlinkFile(file) {
- try {
- return await RNFetchBlob.fs.unlink(file);
- } catch (e) {
- }
+ try {
+ CachedImage.sameURL.splice(CachedImage.sameURL.indexOf(file));
+ return await RNFetchBlob.fs.unlink(file);
+ } catch (e) {}
}
/**
@@ -223,13 +276,12 @@ async function _unlinkFile(file) {
* @returns {string}
*/
function _getCacheFilename(url) {
+ if (!url || url.toString() !== url) return "";
- if (!url || url.toString() !== url) return "";
-
- let ext = url.replace(/.+\./, "").toLowerCase();
- if (defaultImageTypes.indexOf(ext) === -1) ext = "png";
- let hash = SHA1(url);
- return CachedImage.cacheDir + hash + "." + ext;
+ let ext = url.replace(/.+\./, "").toLowerCase();
+ if (defaultImageTypes.indexOf(ext) === -1) ext = "png";
+ let hash = SHA1(url);
+ return CachedImage.cacheDir + hash + "." + ext;
}
/**
@@ -240,77 +292,84 @@ function _getCacheFilename(url) {
* @param success callback (cacheFile:string)=>{}
* @param failure callback (error:string)=>{}
*/
-async function _saveCacheFile(url: string, success: Function, failure: Function) {
-
- try {
- const isNetwork = !!(url && url.match(/^https?:\/\//));
- const isBase64 = !!(url && url.match(/^data:/));
- const cacheFile = _getCacheFilename(url);
-
- if (isNetwork) {
- const tempCacheFile = cacheFile + '.tmp';
- _unlinkFile(tempCacheFile);
- RNFetchBlob.config({
- // response data will be saved to this path if it has access right.
- path: tempCacheFile,
+async function _saveCacheFile(
+ url: string,
+ success: Function,
+ failure: Function
+) {
+ try {
+ const isNetwork = !!(url && url.match(/^https?:\/\//));
+ const isBase64 = !!(url && url.match(/^data:/));
+ const cacheFile = _getCacheFilename(url);
+
+ if (isNetwork) {
+ const tempCacheFile = cacheFile + ".tmp";
+ _unlinkFile(tempCacheFile);
+ RNFetchBlob.config({
+ // response data will be saved to this path if it has access right.
+ path: tempCacheFile
+ })
+ .fetch("GET", url)
+ .then(async res => {
+ if (
+ res &&
+ res.respInfo &&
+ res.respInfo.headers &&
+ !res.respInfo.headers["Content-Encoding"] &&
+ !res.respInfo.headers["Transfer-Encoding"] &&
+ res.respInfo.headers["Content-Length"]
+ ) {
+ const expectedContentLength =
+ res.respInfo.headers["Content-Length"];
+ let actualContentLength;
+
+ try {
+ const fileStats = await RNFetchBlob.fs.stat(res.path());
+
+ if (!fileStats || !fileStats.size) {
+ throw new Error("FileNotFound:" + url);
+ }
+
+ actualContentLength = fileStats.size;
+ } catch (error) {
+ throw new Error("DownloadFailed:" + url);
+ }
+
+ if (expectedContentLength != actualContentLength) {
+ throw new Error("DownloadFailed:" + url);
+ }
+ }
+
+ _unlinkFile(cacheFile);
+ RNFetchBlob.fs
+ .mv(tempCacheFile, cacheFile)
+ .then(() => {
+ success && success(cacheFile);
})
- .fetch(
- 'GET',
- url
- )
- .then(async (res) => {
-
- if (res && res.respInfo && res.respInfo.headers && !res.respInfo.headers["Content-Encoding"] && !res.respInfo.headers["Transfer-Encoding"] && res.respInfo.headers["Content-Length"]) {
- const expectedContentLength = res.respInfo.headers["Content-Length"];
- let actualContentLength;
-
- try {
- const fileStats = await RNFetchBlob.fs.stat(res.path());
-
- if (!fileStats || !fileStats.size) {
- throw new Error("FileNotFound:"+url);
- }
-
- actualContentLength = fileStats.size;
- } catch (error) {
- throw new Error("DownloadFailed:"+url);
- }
-
- if (expectedContentLength != actualContentLength) {
- throw new Error("DownloadFailed:"+url);
- }
- }
-
- _unlinkFile(cacheFile);
- RNFetchBlob.fs
- .mv(tempCacheFile, cacheFile)
- .then(() => {
- success && success(cacheFile);
- })
- .catch(async (error) => {
- throw error;
- });
- })
- .catch(async (error) => {
- _unlinkFile(tempCacheFile);
- _unlinkFile(cacheFile);
- failure && failure(error);
- });
- } else if (isBase64) {
- let data = url.replace(/data:/i, '');
- RNFetchBlob.fs
- .writeFile(cacheFile, data, 'base64')
- .then(() => {
- success && success(cacheFile);
- })
- .catch(async (error) => {
- _unlinkFile(cacheFile);
- failure && failure(error);
- });
- } else {
- failure && failure(new Error("NotSupportedUrl"));
- }
- } catch (error) {
- failure && failure(error);
+ .catch(async error => {
+ throw error;
+ });
+ })
+ .catch(async error => {
+ _unlinkFile(tempCacheFile);
+ _unlinkFile(cacheFile);
+ failure && failure(error);
+ });
+ } else if (isBase64) {
+ let data = url.replace(/data:/i, "");
+ RNFetchBlob.fs
+ .writeFile(cacheFile, data, "base64")
+ .then(() => {
+ success && success(cacheFile);
+ })
+ .catch(async error => {
+ _unlinkFile(cacheFile);
+ failure && failure(error);
+ });
+ } else {
+ failure && failure(new Error("NotSupportedUrl"));
}
-}
\ No newline at end of file
+ } catch (error) {
+ failure && failure(error);
+ }
+}