import React from 'react'; import { normalizeURI, parseURI } from 'lbry-redux'; import { ActivityIndicator, Platform, Text, TouchableOpacity, View } from 'react-native'; import { navigateToUri, formatBytes } from 'utils/helper'; import Colors from 'styles/colors'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import DateTime from 'component/dateTime'; import FileItemMedia from 'component/fileItemMedia'; import Icon from 'react-native-vector-icons/FontAwesome5'; import Link from 'component/link'; import NsfwOverlay from 'component/nsfwOverlay'; import ProgressBar from 'component/progressBar'; import fileListStyle from 'styles/fileList'; class FileListItem extends React.PureComponent { state = { url: null, }; getStorageForFileInfo = fileInfo => { if (!fileInfo.completed) { const written = formatBytes(fileInfo.written_bytes); const total = formatBytes(fileInfo.total_bytes); return `(${written} / ${total})`; } return formatBytes(fileInfo.written_bytes); }; formatTitle = title => { if (!title) { return title; } return title.length > 80 ? title.substring(0, 77).trim() + '...' : title; }; getDownloadProgress = fileInfo => { return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100); }; componentDidMount() { const { claim, resolveUri, uri, batchResolve } = this.props; if (!claim && !batchResolve) { resolveUri(uri); } } componentDidUpdate() { const { claim, resolveUri, uri } = this.props; if (!claim && uri !== this.state.url) { this.setState({ url: uri }, () => resolveUri(uri)); } } defaultOnPress = () => { const { autoplay, claim, featuredResult, navigation, uri, shortUrl } = this.props; if (featuredResult && !claim) { navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH, params: { vanityUrl: uri.trim() } }); } else { navigateToUri(navigation, shortUrl || uri, { autoplay }, false, claim ? claim.permanent_url : null); } }; onPressHandler = () => { const { claim, onPress } = this.props; if (onPress) { onPress(claim); } else { this.defaultOnPress(); } }; render() { const { blackListedOutpoints, claim, fileInfo, filteredOutpoints, metadata, nsfw, featuredResult, isResolvingUri, isDownloaded, style, obscureNsfw, onPress, navigation, rewardedContentClaimIds, thumbnail, hideChannel, onLongPress, selected, title, } = this.props; const uri = normalizeURI(this.props.uri); const obscure = obscureNsfw && nsfw; const isResolving = !fileInfo && isResolvingUri; const duration = claim && claim.value && claim.value.video ? claim.value.video.duration : null; let name, channel, height, isRewardContent, channelClaimId, fullChannelUri, shortChannelUri, shouldHide, signingChannel; if (claim) { name = claim.name; signingChannel = claim.signing_channel; channel = signingChannel ? signingChannel.name : null; height = claim.height; isRewardContent = rewardedContentClaimIds.includes(claim.claim_id); channelClaimId = signingChannel ? signingChannel.claim_id : null; fullChannelUri = channelClaimId ? `${channel}#${channelClaimId}` : channel; shortChannelUri = signingChannel ? signingChannel.short_url : null; if (blackListedOutpoints || filteredOutpoints) { const outpointsToHide = !blackListedOutpoints ? filteredOutpoints : blackListedOutpoints.concat(filteredOutpoints); shouldHide = outpointsToHide.some(outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout); } // TODO: hide channels on tag pages? // shouldHide = 'channel' === claim.value_type; } if (shouldHide || (!isResolvingUri && !claim && !featuredResult)) { return null; } return ( <View style={style}> <TouchableOpacity style={style} onPress={this.onPressHandler} onLongPress={() => { if (onLongPress) { onLongPress(claim); } }} > <FileItemMedia style={fileListStyle.thumbnail} duration={duration} resizeMode="cover" title={title || name || normalizeURI(uri).substring(7)} thumbnail={thumbnail} /> {selected && ( <View style={fileListStyle.selectedOverlay}> <Icon name={'check-circle'} solid color={Colors.NextLbryGreen} size={32} /> </View> )} {fileInfo && fileInfo.completed && fileInfo.download_path && ( <Icon style={fileListStyle.downloadedIcon} solid color={Colors.NextLbryGreen} name={'folder'} size={16} /> )} <View style={fileListStyle.detailsContainer}> {featuredResult && ( <Text style={fileListStyle.featuredUri} numberOfLines={1}> {uri} </Text> )} {!title && !name && !channel && isResolving && ( <View> {!title && !name && <Text style={fileListStyle.uri}>{uri}</Text>} {!title && !name && ( <View style={fileListStyle.row}> <ActivityIndicator size={'small'} color={featuredResult ? Colors.White : Colors.LbryGreen} /> </View> )} </View> )} {(title || name) && ( <View style={fileListStyle.titleContainer}> <Text style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}> {this.formatTitle(title) || this.formatTitle(name)} </Text> {isRewardContent && <Icon style={fileListStyle.rewardIcon} name="award" size={12} />} </View> )} {featuredResult && !isResolving && !claim && ( <View style={fileListStyle.titleContainer}> <Text style={fileListStyle.featuredTitle}>{__('Nothing here. Publish something!')}</Text> </View> )} {channel && !hideChannel && ( <Link style={fileListStyle.publisher} text={channel} onPress={() => { navigateToUri( navigation, normalizeURI(shortChannelUri || fullChannelUri), null, false, fullChannelUri ); }} /> )} <View style={fileListStyle.info}> {fileInfo && !isNaN(fileInfo.written_bytes) && fileInfo.written_bytes > 0 && ( <Text style={fileListStyle.infoText}>{this.getStorageForFileInfo(fileInfo)}</Text> )} <DateTime style={fileListStyle.publishInfo} textStyle={fileListStyle.infoText} timeAgo uri={uri} /> </View> {fileInfo && fileInfo.download_path && ( <View style={fileListStyle.downloadInfo}> {!fileInfo.completed && ( <ProgressBar borderRadius={3} color={Colors.NextLbryGreen} height={3} style={fileListStyle.progress} progress={this.getDownloadProgress(fileInfo)} /> )} </View> )} </View> </TouchableOpacity> {obscure && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />} </View> ); } } export default FileListItem;