add support for viewing images, HTML and text files in the app #141
5 changed files with 106 additions and 40 deletions
15
app/package-lock.json
generated
15
app/package-lock.json
generated
|
@ -3953,7 +3953,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lbry-redux": {
|
"lbry-redux": {
|
||||||
"version": "github:lbryio/lbry-redux#30c18725d8c6c141c30c57f0a324d0abb8963b99",
|
"version": "github:lbryio/lbry-redux#8cbeed792906335577bbf4382a2707f8e463e242",
|
||||||
"requires": {
|
"requires": {
|
||||||
"proxy-polyfill": "0.1.6",
|
"proxy-polyfill": "0.1.6",
|
||||||
"reselect": "3.0.1"
|
"reselect": "3.0.1"
|
||||||
|
@ -5174,6 +5174,19 @@
|
||||||
"react-native-drawer-layout": "1.3.2"
|
"react-native-drawer-layout": "1.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-native-image-pan-zoom": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-KnuSM0Rs+XD7EFovgJfGsU/Bl0sFIvqTZQ04hebW9dtuKekBOBMEEnuuvTxrktbBBhzDlwgxRrVWlTt6PGREDw=="
|
||||||
|
},
|
||||||
|
"react-native-image-zoom-viewer": {
|
||||||
|
"version": "2.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-2.2.5.tgz",
|
||||||
|
"integrity": "sha512-kXpetilVqHajZDYrc8QjPEmB7wRNxoOlmtZaATshNZKUp7DABL7lubdKxqfC3GiFuvVfp6Ei8hkaADRF53AeTw==",
|
||||||
|
"requires": {
|
||||||
|
"react-native-image-pan-zoom": "2.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-native-safe-area-view": {
|
"react-native-safe-area-view": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz",
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"moment": "^2.22.1",
|
"moment": "^2.22.1",
|
||||||
"react": "16.2.0",
|
"react": "16.2.0",
|
||||||
"react-native": "0.55.3",
|
"react-native": "0.55.3",
|
||||||
|
"react-native-image-zoom-viewer": "^2.2.5",
|
||||||
"react-native-vector-icons": "^4.5.0",
|
"react-native-vector-icons": "^4.5.0",
|
||||||
"react-native-video": "2.0.0",
|
"react-native-video": "2.0.0",
|
||||||
"react-navigation": "^1.5.12",
|
"react-navigation": "^1.5.12",
|
||||||
|
|
|
@ -39,13 +39,9 @@ class FileDownloadButton extends React.PureComponent {
|
||||||
loading,
|
loading,
|
||||||
doPause,
|
doPause,
|
||||||
style,
|
style,
|
||||||
|
openFile
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const openFile = () => {
|
|
||||||
//openInShell(fileInfo.download_path);
|
|
||||||
//doPause();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loading || downloading) {
|
if (loading || downloading) {
|
||||||
const progress =
|
const progress =
|
||||||
fileInfo && fileInfo.written_bytes ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0,
|
fileInfo && fileInfo.written_bytes ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0,
|
||||||
|
@ -77,7 +73,7 @@ class FileDownloadButton extends React.PureComponent {
|
||||||
);
|
);
|
||||||
} else if (fileInfo && fileInfo.download_path) {
|
} else if (fileInfo && fileInfo.download_path) {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity style={[style, fileDownloadButtonStyle.container]} onPress={() => openFile()}>
|
<TouchableOpacity style={[style, fileDownloadButtonStyle.container]} onPress={openFile}>
|
||||||
<Text style={fileDownloadButtonStyle.text}>Open</Text>
|
<Text style={fileDownloadButtonStyle.text}>Open</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,14 +4,17 @@ import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Alert,
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
Text,
|
NativeModules,
|
||||||
TextInput,
|
|
||||||
View,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StatusBar,
|
StatusBar,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
NativeModules
|
View,
|
||||||
|
WebView
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import ImageViewer from 'react-native-image-zoom-viewer';
|
||||||
import Colors from '../../styles/colors';
|
import Colors from '../../styles/colors';
|
||||||
import ChannelPage from '../channel';
|
import ChannelPage from '../channel';
|
||||||
import FileDownloadButton from '../../component/fileDownloadButton';
|
import FileDownloadButton from '../../component/fileDownloadButton';
|
||||||
|
@ -31,7 +34,10 @@ class FilePage extends React.PureComponent {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
mediaLoaded: false,
|
mediaLoaded: false,
|
||||||
fullscreenMode: false
|
fullscreenMode: false,
|
||||||
|
showImageViewer: false,
|
||||||
|
showWebView: false,
|
||||||
|
imageUrls: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +126,13 @@ class FilePage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localUriForFileInfo = (fileInfo) => {
|
||||||
|
if (!fileInfo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return 'file:///' + fileInfo.download_path;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
claim,
|
claim,
|
||||||
|
@ -163,7 +176,7 @@ class FilePage extends React.PureComponent {
|
||||||
const mediaType = Lbry.getMediaType(contentType);
|
const mediaType = Lbry.getMediaType(contentType);
|
||||||
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
const isPlayable = mediaType === 'video' || mediaType === 'audio';
|
||||||
const { height, channel_name: channelName, value } = claim;
|
const { height, channel_name: channelName, value } = claim;
|
||||||
const showActions = !this.state.fullscreenMode &&
|
const showActions = !this.state.fullscreenMode && !this.state.showImageViewer && !this.state.showWebView &&
|
||||||
(completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes));
|
(completed || (fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes));
|
||||||
const channelClaimId =
|
const channelClaimId =
|
||||||
value && value.publisherSignature && value.publisherSignature.certificateId;
|
value && value.publisherSignature && value.publisherSignature.certificateId;
|
||||||
|
@ -175,14 +188,45 @@ class FilePage extends React.PureComponent {
|
||||||
// at least 2MB (or the full download) before media can be loaded
|
// at least 2MB (or the full download) before media can be loaded
|
||||||
const canLoadMedia = fileInfo &&
|
const canLoadMedia = fileInfo &&
|
||||||
(fileInfo.written_bytes >= 2097152 || fileInfo.written_bytes == fileInfo.total_bytes); // 2MB = 1024*1024*2
|
(fileInfo.written_bytes >= 2097152 || fileInfo.written_bytes == fileInfo.total_bytes); // 2MB = 1024*1024*2
|
||||||
|
const canOpen = (mediaType === 'image' || mediaType === 'text') && completed;
|
||||||
|
const isWebViewable = mediaType === 'text';
|
||||||
|
const localFileUri = this.localUriForFileInfo(fileInfo);
|
||||||
|
|
||||||
|
const openFile = () => {
|
||||||
|
if (mediaType === 'image') {
|
||||||
|
// use image viewer
|
||||||
|
this.setState({
|
||||||
|
imageUrls: [{
|
||||||
|
url: localFileUri
|
||||||
|
}],
|
||||||
|
showImageViewer: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isWebViewable) {
|
||||||
|
// show webview
|
||||||
|
this.setState({
|
||||||
|
showWebView: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
innerContent = (
|
innerContent = (
|
||||||
|
<View style={filePageStyle.pageContainer}>
|
||||||
|
{this.state.showWebView && isWebViewable && <WebView source={{ uri: localFileUri }}
|
||||||
|
style={filePageStyle.viewer} />}
|
||||||
|
|
||||||
|
{this.state.showImageViewer && <ImageViewer style={StyleSheet.flatten(filePageStyle.viewer)}
|
||||||
|
imageUrls={this.state.imageUrls}
|
||||||
|
renderIndicator={() => null} />}
|
||||||
|
|
||||||
|
{!this.state.showWebView && (
|
||||||
<View style={filePageStyle.pageContainer}>
|
<View style={filePageStyle.pageContainer}>
|
||||||
<View style={filePageStyle.mediaContainer}>
|
<View style={filePageStyle.mediaContainer}>
|
||||||
{(!fileInfo || (isPlayable && !canLoadMedia)) &&
|
{(canOpen || (!fileInfo || (isPlayable && !canLoadMedia))) &&
|
||||||
<FileItemMedia style={filePageStyle.thumbnail} title={title} thumbnail={metadata.thumbnail} />}
|
<FileItemMedia style={filePageStyle.thumbnail} title={title} thumbnail={metadata.thumbnail} />}
|
||||||
{isPlayable && !this.state.mediaLoaded && <ActivityIndicator size="large" color={Colors.LbryGreen} style={filePageStyle.loading} />}
|
{(canOpen || (isPlayable && !this.state.mediaLoaded)) && <ActivityIndicator size="large" color={Colors.LbryGreen} style={filePageStyle.loading} />}
|
||||||
{!completed && !canLoadMedia && <FileDownloadButton uri={uri} style={filePageStyle.downloadButton} />}
|
{((isPlayable && !completed && !canLoadMedia) || !completed || canOpen) &&
|
||||||
|
<FileDownloadButton uri={uri} style={filePageStyle.downloadButton} openFile={openFile} />}
|
||||||
{!fileInfo && <FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />}
|
{!fileInfo && <FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />}
|
||||||
</View>
|
</View>
|
||||||
{canLoadMedia && <View style={playerBgStyle} />}
|
{canLoadMedia && <View style={playerBgStyle} />}
|
||||||
|
@ -204,6 +248,9 @@ class FilePage extends React.PureComponent {
|
||||||
{channelName && <Text style={filePageStyle.channelName} selectable={true}>{channelName}</Text>}
|
{channelName && <Text style={filePageStyle.channelName} selectable={true}>{channelName}</Text>}
|
||||||
{description && <Text style={filePageStyle.description} selectable={true}>{description}</Text>}
|
{description && <Text style={filePageStyle.description} selectable={true}>{description}</Text>}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
<UriBar value={uri} navigation={navigation} />
|
<UriBar value={uri} navigation={navigation} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
@ -143,6 +143,15 @@ const filePageStyle = StyleSheet.create({
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginLeft: 10
|
marginLeft: 10
|
||||||
|
},
|
||||||
|
viewer: {
|
||||||
|
position: 'absolute',
|
||||||
|
flex: 1,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
zIndex: 100
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue