Merge pull request #141 from lbryio/image-and-html-file-types

add support for viewing images, HTML and text files in the app
This commit is contained in:
Akinwale Ariwodola 2018-05-25 19:53:33 +01:00 committed by GitHub
commit 7c8f9a6662
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 40 deletions

15
app/package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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>
); );

View file

@ -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,35 +188,69 @@ 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}> <View style={filePageStyle.pageContainer}>
<View style={filePageStyle.mediaContainer}> {this.state.showWebView && isWebViewable && <WebView source={{ uri: localFileUri }}
{(!fileInfo || (isPlayable && !canLoadMedia)) && style={filePageStyle.viewer} />}
<FileItemMedia style={filePageStyle.thumbnail} title={title} thumbnail={metadata.thumbnail} />}
{isPlayable && !this.state.mediaLoaded && <ActivityIndicator size="large" color={Colors.LbryGreen} style={filePageStyle.loading} />} {this.state.showImageViewer && <ImageViewer style={StyleSheet.flatten(filePageStyle.viewer)}
{!completed && !canLoadMedia && <FileDownloadButton uri={uri} style={filePageStyle.downloadButton} />} imageUrls={this.state.imageUrls}
{!fileInfo && <FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />} renderIndicator={() => null} />}
</View>
{canLoadMedia && <View style={playerBgStyle} />} {!this.state.showWebView && (
{canLoadMedia && <MediaPlayer fileInfo={fileInfo} <View style={filePageStyle.pageContainer}>
uri={uri} <View style={filePageStyle.mediaContainer}>
style={playerStyle} {(canOpen || (!fileInfo || (isPlayable && !canLoadMedia))) &&
onFullscreenToggled={this.handleFullscreenToggle} <FileItemMedia style={filePageStyle.thumbnail} title={title} thumbnail={metadata.thumbnail} />}
onMediaLoaded={() => { this.setState({ mediaLoaded: true }); }}/>} {(canOpen || (isPlayable && !this.state.mediaLoaded)) && <ActivityIndicator size="large" color={Colors.LbryGreen} style={filePageStyle.loading} />}
{((isPlayable && !completed && !canLoadMedia) || !completed || canOpen) &&
{ showActions && <FileDownloadButton uri={uri} style={filePageStyle.downloadButton} openFile={openFile} />}
<View style={filePageStyle.actions}> {!fileInfo && <FilePrice uri={uri} style={filePageStyle.filePriceContainer} textStyle={filePageStyle.filePriceText} />}
{completed && <Button color="red" title="Delete" onPress={this.onDeletePressed} />} </View>
{!completed && fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes && {canLoadMedia && <View style={playerBgStyle} />}
<Button color="red" title="Stop Download" onPress={this.onStopDownloadPressed} /> {canLoadMedia && <MediaPlayer fileInfo={fileInfo}
} uri={uri}
</View>} style={playerStyle}
<ScrollView style={showActions ? filePageStyle.scrollContainerActions : filePageStyle.scrollContainer}> onFullscreenToggled={this.handleFullscreenToggle}
<Text style={filePageStyle.title} selectable={true}>{title}</Text> onMediaLoaded={() => { this.setState({ mediaLoaded: true }); }}/>}
{channelName && <Text style={filePageStyle.channelName} selectable={true}>{channelName}</Text>}
{description && <Text style={filePageStyle.description} selectable={true}>{description}</Text>} { showActions &&
</ScrollView> <View style={filePageStyle.actions}>
{completed && <Button color="red" title="Delete" onPress={this.onDeletePressed} />}
{!completed && fileInfo && !fileInfo.stopped && fileInfo.written_bytes < fileInfo.total_bytes &&
<Button color="red" title="Stop Download" onPress={this.onStopDownloadPressed} />
}
</View>}
<ScrollView style={showActions ? filePageStyle.scrollContainerActions : filePageStyle.scrollContainer}>
<Text style={filePageStyle.title} selectable={true}>{title}</Text>
{channelName && <Text style={filePageStyle.channelName} selectable={true}>{channelName}</Text>}
{description && <Text style={filePageStyle.description} selectable={true}>{description}</Text>}
</ScrollView>
</View>
)}
<UriBar value={uri} navigation={navigation} /> <UriBar value={uri} navigation={navigation} />
</View> </View>
); );

View file

@ -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
} }
}); });