Skip to content

Commit

Permalink
Use cache to improve file preview experience
Browse files Browse the repository at this point in the history
  • Loading branch information
robertying committed May 4, 2019
1 parent 73f2959 commit a1216e2
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/components/AssignmentBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ const AssignmentBoard: FunctionComponent<
ext
});
} else {
showToast("文件下载中……", 3000);
const success = await shareFile(url, ext);
showToast("文件下载中……", 1000);
const success = await shareFile(url, filename, ext);
if (!success) {
showToast("文件下载失败", 3000);
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/NoticeBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ const NoticeBoard: FunctionComponent<
ext
});
} else {
showToast("文件下载中……", 3000);
const success = await shareFile(url, ext);
showToast("文件下载中……", 1000);
const success = await shareFile(url, filename, ext);
if (!success) {
showToast("文件下载失败", 3000);
}
Expand Down
39 changes: 31 additions & 8 deletions src/helpers/share.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Platform } from "react-native";
import Share from "react-native-share";
import RNFetchBlob from "rn-fetch-blob";

Expand All @@ -22,30 +23,52 @@ export const mimeTypes: any = {
rar: "application/x-rar-compressed"
};

export const shareFile = (url: string, ext: string) => {
export const shareFile = (url: string, name: string, ext: string) => {
return new Promise<boolean>(async (resolve, reject) => {
if (!supportedFileTypes.includes(ext.toLowerCase())) {
reject("Unsupported file type");
}

const res = await RNFetchBlob.fetch("GET", url);
const status = res.respInfo.status;
const filePath = await downloadFile(url, name, ext).catch(() =>
reject("Download failed")
);

if (status !== 200) {
reject();
} else {
const base64Str = res.base64();
if (filePath) {
Share.open({
url: `data:${mimeTypes[ext]};base64,${base64Str}`,
url: Platform.OS === "android" ? "file://" + filePath : filePath,
type: mimeTypes[ext],
title: "打开文件",
showAppsToView: true
});

resolve(true);
}
});
};

export const downloadFile = (url: string, name: string, ext: string) => {
return new Promise<string>(async (resolve, reject) => {
const dirs = RNFetchBlob.fs.dirs;
const filePath = `${dirs.DocumentDir}/files/${name}.${ext}`;
const exists = await RNFetchBlob.fs.exists(filePath);

if (!exists) {
const res = await RNFetchBlob.config({
fileCache: true,
path: filePath
}).fetch("GET", url);
const status = res.respInfo.status;
if (status !== 200) {
reject();
} else {
resolve(res.path());
}
} else {
resolve(filePath);
}
});
};

export const getExtension = (filename: string) => {
return filename.split(".").pop();
};
4 changes: 2 additions & 2 deletions src/screens/CourseDetailScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ const CourseDetailScreen: INavigationScreen<
ext
});
} else {
showToast("文件下载中……", 3000);
const success = await shareFile(url, ext);
showToast("文件下载中……", 1000);
const success = await shareFile(url, filename, ext);
if (!success) {
showToast("文件下载失败", 3000);
}
Expand Down
4 changes: 2 additions & 2 deletions src/screens/FilesScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ const FilesScreen: INavigationScreen<IFilesScreenProps> = props => {
ext
});
} else {
showToast("文件下载中……", 3000);
const success = await shareFile(url, ext);
showToast("文件下载中……", 1000);
const success = await shareFile(url, filename, ext);
if (!success) {
showToast("文件下载失败", 3000);
}
Expand Down
38 changes: 36 additions & 2 deletions src/screens/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { iOSColors } from "react-native-typography";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import MaterialIcons from "react-native-vector-icons/MaterialIcons";
import { connect } from "react-redux";
import RNFetchBlob from "rn-fetch-blob";
import packageConfig from "../../package.json";
import Divider from "../components/Divider";
import SettingsListItem from "../components/SettingsListItem";
Expand Down Expand Up @@ -135,6 +136,29 @@ const SettingsScreen: INavigationScreen<ISettingsScreenProps> = props => {
}
};

const onClearFileCachePress = () => {
Alert.alert(
"清空文件缓存",
"确定要清空文件缓存吗?",
[
{
text: "取消",
style: "cancel"
},
{
text: "确定",
onPress: async () => {
await RNFetchBlob.fs.unlink(
`${RNFetchBlob.fs.dirs.DocumentDir}/files`
);
showToast("成功清空文件缓存", 1500);
}
}
],
{ cancelable: true }
);
};

const renderListItem: ListRenderItem<{}> = ({ index }) => {
switch (index) {
case 0:
Expand Down Expand Up @@ -169,6 +193,15 @@ const SettingsScreen: INavigationScreen<ISettingsScreenProps> = props => {
/>
);
case 3:
return (
<SettingsListItem
variant="none"
icon={<MaterialCommunityIcons name="file-hidden" size={20} />}
text="清空文件缓存"
onPress={onClearFileCachePress}
/>
);
case 4:
return Platform.OS === "android" ? (
<SettingsListItem
variant="none"
Expand Down Expand Up @@ -197,7 +230,7 @@ const SettingsScreen: INavigationScreen<ISettingsScreenProps> = props => {
onPress={onCheckUpdatePress}
/>
) : null;
case 4:
case 5:
return (
<SettingsListItem
variant="arrow"
Expand All @@ -207,7 +240,7 @@ const SettingsScreen: INavigationScreen<ISettingsScreenProps> = props => {
onPress={onAcknowledgementsPress}
/>
);
case 5:
case 6:
return (
<SettingsListItem
variant="arrow"
Expand All @@ -228,6 +261,7 @@ const SettingsScreen: INavigationScreen<ISettingsScreenProps> = props => {
{ key: "autoRefreshing" },
{ key: "calendarSync" },
{ key: "logout" },
{ key: "clearFileCache" },
{ key: "checkUpdate" },
{ key: "acknowledgement" },
{ key: "about" }
Expand Down
36 changes: 25 additions & 11 deletions src/screens/WebViewScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialIcons";
import { WebView } from "react-native-webview";
import MediumPlaceholder from "../components/MediumPlaceholder";
import { shareFile } from "../helpers/share";
import { downloadFile, shareFile } from "../helpers/share";
import { showToast } from "../redux/actions/toast";
import { store } from "../redux/store";
import { INavigationScreen } from "../types/NavigationScreen";

export interface IWebViewScreenProps {
readonly url: string;
}

const WebViewScreen: INavigationScreen<IWebViewScreenProps> = props => {
const WebViewScreen: INavigationScreen<{}> = props => {
const url = props.navigation.getParam("url");
const name = props.navigation.getParam("filename");
const ext = props.navigation.getParam("ext");

const [loading, setLoading] = useState(true);
const [filePath, setFilePath] = useState("");

useEffect(() => {
if (loading) {
(async () => {
const filePath = await downloadFile(url, name, ext);
if (filePath) {
setFilePath(filePath);
setLoading(false);
}
})();
}
}, [loading]);

return (
<>
<WebView
source={{
uri: url
uri: filePath
}}
useWebKit={false}
// tslint:disable-next-line: jsx-no-lambda
onLoadEnd={() => setLoading(false)}
originWhitelist={["*"]}
/>
{loading && (
<View
Expand Down Expand Up @@ -58,7 +68,11 @@ WebViewScreen.navigationOptions = ({ navigation }) => {
// tslint:disable-next-line: jsx-no-lambda
onPress={() => {
store.dispatch(showToast("准备文件中……", 1500));
shareFile(navigation.getParam("url"), navigation.getParam("ext"));
shareFile(
navigation.getParam("url"),
navigation.getParam("filename"),
navigation.getParam("ext")
);
}}
color="white"
size={24}
Expand Down

0 comments on commit a1216e2

Please sign in to comment.