unified display of channel results #108
11 changed files with 204 additions and 92 deletions
|
@ -12,7 +12,7 @@ import {
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectBlackListedOutpoints, selectFilteredOutpoints, selectRewardContentClaimIds } from 'lbryinc';
|
import { selectBlackListedOutpoints, selectFilteredOutpoints, selectRewardContentClaimIds } from 'lbryinc';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import FileResultItem from './view';
|
import ClaimResultItem from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||||
|
@ -37,4 +37,4 @@ const perform = dispatch => ({
|
||||||
export default connect(
|
export default connect(
|
||||||
select,
|
select,
|
||||||
perform,
|
perform,
|
||||||
)(FileResultItem);
|
)(ClaimResultItem);
|
|
@ -1,10 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { normalizeURI, parseURI } from 'lbry-redux';
|
import { normalizeURI, parseURI } from 'lbry-redux';
|
||||||
import { ActivityIndicator, Platform, Text, TouchableOpacity, View } from 'react-native';
|
import { ActivityIndicator, Platform, Text, TouchableOpacity, View } from 'react-native';
|
||||||
import { navigateToUri, formatBytes } from 'utils/helper';
|
import { navigateToUri, formatTitle, getDownloadProgress, getStorageForFileInfo } from 'utils/helper';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
|
import ChannelIconItem from 'component/channelIconItem';
|
||||||
|
import channelIconStyle from 'styles/channelIcon';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import DateTime from 'component/dateTime';
|
import DateTime from 'component/dateTime';
|
||||||
|
import FastImage from 'react-native-fast-image';
|
||||||
import FileItemMedia from 'component/fileItemMedia';
|
import FileItemMedia from 'component/fileItemMedia';
|
||||||
import FilePrice from 'component/filePrice';
|
import FilePrice from 'component/filePrice';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
|
@ -12,30 +15,29 @@ import Link from 'component/link';
|
||||||
import NsfwOverlay from 'component/nsfwOverlay';
|
import NsfwOverlay from 'component/nsfwOverlay';
|
||||||
import ProgressBar from 'component/progressBar';
|
import ProgressBar from 'component/progressBar';
|
||||||
import fileListStyle from 'styles/fileList';
|
import fileListStyle from 'styles/fileList';
|
||||||
|
import seedrandom from 'seedrandom';
|
||||||
|
|
||||||
class FileResultItem extends React.PureComponent {
|
class ClaimResultItem extends React.PureComponent {
|
||||||
getStorageForFileInfo = fileInfo => {
|
state = {
|
||||||
if (!fileInfo.completed) {
|
autoStyle: null,
|
||||||
const written = formatBytes(fileInfo.written_bytes);
|
};
|
||||||
const total = formatBytes(fileInfo.total_bytes);
|
|
||||||
return `(${written} / ${total})`;
|
componentDidMount() {
|
||||||
|
const { result } = this.props;
|
||||||
|
|
||||||
|
if (!result || !result.name || !result.claimId) {
|
||||||
|
this.setState({
|
||||||
|
autoStyle:
|
||||||
|
ChannelIconItem.AUTO_THUMB_STYLES[Math.floor(Math.random() * ChannelIconItem.AUTO_THUMB_STYLES.length)],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// result property set, use deterministic random style
|
||||||
|
const rng = seedrandom(normalizeURI(`${result.name}#${result.claimId}`));
|
||||||
|
const index = Math.floor(rng.quick() * ChannelIconItem.AUTO_THUMB_STYLES.length);
|
||||||
|
this.setState({ autoStyle: ChannelIconItem.AUTO_THUMB_STYLES[index] });
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
onPressHandler = () => {
|
onPressHandler = () => {
|
||||||
const { autoplay, navigation, result } = this.props;
|
const { autoplay, navigation, result } = this.props;
|
||||||
const { claimId, name } = result;
|
const { claimId, name } = result;
|
||||||
|
@ -58,6 +60,8 @@ class FileResultItem extends React.PureComponent {
|
||||||
title,
|
title,
|
||||||
} = result;
|
} = result;
|
||||||
|
|
||||||
|
const isChannel = name && name.startsWith('@');
|
||||||
|
const hasThumbnail = !!thumbnailUrl;
|
||||||
const obscure = obscureNsfw && nsfw;
|
const obscure = obscureNsfw && nsfw;
|
||||||
const url = normalizeURI(`${name}#${claimId}`);
|
const url = normalizeURI(`${name}#${claimId}`);
|
||||||
const hasChannel = !!channel;
|
const hasChannel = !!channel;
|
||||||
|
@ -66,7 +70,11 @@ class FileResultItem extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={style}>
|
<View style={style}>
|
||||||
<TouchableOpacity style={style} onPress={this.onPressHandler}>
|
<TouchableOpacity
|
||||||
|
style={[style, isChannel ? fileListStyle.channelContainer : null]}
|
||||||
|
onPress={this.onPressHandler}
|
||||||
|
>
|
||||||
|
{!isChannel && (
|
||||||
<FileItemMedia
|
<FileItemMedia
|
||||||
style={fileListStyle.thumbnail}
|
style={fileListStyle.thumbnail}
|
||||||
duration={duration}
|
duration={duration}
|
||||||
|
@ -74,6 +82,27 @@ class FileResultItem extends React.PureComponent {
|
||||||
title={title || name || normalizeURI(url).substring(7)}
|
title={title || name || normalizeURI(url).substring(7)}
|
||||||
thumbnail={thumbnailUrl}
|
thumbnail={thumbnailUrl}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isChannel && (
|
||||||
|
<View style={fileListStyle.thumbnail}>
|
||||||
|
<View style={[fileListStyle.channelThumbnailContainer, this.state.autoStyle]}>
|
||||||
|
{hasThumbnail && (
|
||||||
|
<FastImage
|
||||||
|
style={fileListStyle.channelThumbnail}
|
||||||
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
|
source={{ uri: thumbnailUrl }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!hasThumbnail && (
|
||||||
|
<Text style={channelIconStyle.autothumbCharacter}>
|
||||||
|
{title ? title.substring(0, 1).toUpperCase() : name.substring(1, 2).toUpperCase()}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{fileInfo && fileInfo.completed && fileInfo.download_path && (
|
{fileInfo && fileInfo.completed && fileInfo.download_path && (
|
||||||
<Icon
|
<Icon
|
||||||
style={featuredResult ? fileListStyle.featuredDownloadedIcon : fileListStyle.downloadedIcon}
|
style={featuredResult ? fileListStyle.featuredDownloadedIcon : fileListStyle.downloadedIcon}
|
||||||
|
@ -94,25 +123,32 @@ class FileResultItem extends React.PureComponent {
|
||||||
{(title || name) && (
|
{(title || name) && (
|
||||||
<View style={fileListStyle.titleContainer}>
|
<View style={fileListStyle.titleContainer}>
|
||||||
<Text style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}>
|
<Text style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}>
|
||||||
{this.formatTitle(title) || this.formatTitle(name)}
|
{formatTitle(title) || formatTitle(name)}
|
||||||
</Text>
|
</Text>
|
||||||
{isRewardContent && <Icon style={fileListStyle.rewardIcon} name="award" size={12} />}
|
{isRewardContent && <Icon style={fileListStyle.rewardIcon} name="award" size={12} />}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hasChannel && (
|
{hasChannel ||
|
||||||
|
(isChannel && (
|
||||||
<Link
|
<Link
|
||||||
style={fileListStyle.publisher}
|
style={fileListStyle.publisher}
|
||||||
text={channel}
|
text={isChannel ? name : channel}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigateToUri(navigation, normalizeURI(channelUrl), null, false, channelUrl);
|
navigateToUri(
|
||||||
|
navigation,
|
||||||
|
normalizeURI(isChannel ? url : channelUrl),
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
isChannel ? url : channelUrl,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
|
|
||||||
<View style={fileListStyle.info}>
|
<View style={fileListStyle.info}>
|
||||||
{fileInfo && !isNaN(fileInfo.written_bytes) && fileInfo.written_bytes > 0 && (
|
{fileInfo && !isNaN(fileInfo.written_bytes) && fileInfo.written_bytes > 0 && (
|
||||||
<Text>{this.getStorageForFileInfo(fileInfo)}</Text>
|
<Text>{getStorageForFileInfo(fileInfo)}</Text>
|
||||||
)}
|
)}
|
||||||
<DateTime
|
<DateTime
|
||||||
style={fileListStyle.publishInfo}
|
style={fileListStyle.publishInfo}
|
||||||
|
@ -130,7 +166,7 @@ class FileResultItem extends React.PureComponent {
|
||||||
color={Colors.NextLbryGreen}
|
color={Colors.NextLbryGreen}
|
||||||
height={3}
|
height={3}
|
||||||
style={fileListStyle.progress}
|
style={fileListStyle.progress}
|
||||||
progress={this.getDownloadProgress(fileInfo)}
|
progress={getDownloadProgress(fileInfo)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
@ -143,4 +179,4 @@ class FileResultItem extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FileResultItem;
|
export default ClaimResultItem;
|
|
@ -1,10 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { normalizeURI, parseURI } from 'lbry-redux';
|
import { normalizeURI, parseURI } from 'lbry-redux';
|
||||||
import { ActivityIndicator, Platform, Text, TouchableOpacity, View } from 'react-native';
|
import { ActivityIndicator, Platform, Text, TouchableOpacity, View } from 'react-native';
|
||||||
import { navigateToUri, formatBytes } from 'utils/helper';
|
import { navigateToUri, formatTitle, getDownloadProgress, getStorageForFileInfo } from 'utils/helper';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
|
import ChannelIconItem from 'component/channelIconItem';
|
||||||
|
import channelIconStyle from 'styles/channelIcon';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import DateTime from 'component/dateTime';
|
import DateTime from 'component/dateTime';
|
||||||
|
import FastImage from 'react-native-fast-image';
|
||||||
import FileItemMedia from 'component/fileItemMedia';
|
import FileItemMedia from 'component/fileItemMedia';
|
||||||
import FilePrice from 'component/filePrice';
|
import FilePrice from 'component/filePrice';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
|
@ -15,27 +18,10 @@ import fileListStyle from 'styles/fileList';
|
||||||
|
|
||||||
class FileListItem extends React.PureComponent {
|
class FileListItem extends React.PureComponent {
|
||||||
state = {
|
state = {
|
||||||
|
autoStyle: null,
|
||||||
url: null,
|
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 => {
|
getDownloadProgress = fileInfo => {
|
||||||
return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
||||||
};
|
};
|
||||||
|
@ -45,6 +31,11 @@ class FileListItem extends React.PureComponent {
|
||||||
if (!claim && !batchResolve) {
|
if (!claim && !batchResolve) {
|
||||||
resolveUri(uri);
|
resolveUri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
autoStyle:
|
||||||
|
ChannelIconItem.AUTO_THUMB_STYLES[Math.floor(Math.random() * ChannelIconItem.AUTO_THUMB_STYLES.length)],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
|
@ -135,10 +126,13 @@ class FileListItem extends React.PureComponent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isChannel = name && name.startsWith('@');
|
||||||
|
const hasThumbnail = !!thumbnail;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={style}>
|
<View style={style}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={style}
|
style={[style, isChannel ? fileListStyle.channelContainer : null]}
|
||||||
onPress={this.onPressHandler}
|
onPress={this.onPressHandler}
|
||||||
onLongPress={() => {
|
onLongPress={() => {
|
||||||
if (onLongPress) {
|
if (onLongPress) {
|
||||||
|
@ -146,6 +140,7 @@ class FileListItem extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{!isChannel && (
|
||||||
<FileItemMedia
|
<FileItemMedia
|
||||||
style={fileListStyle.thumbnail}
|
style={fileListStyle.thumbnail}
|
||||||
duration={duration}
|
duration={duration}
|
||||||
|
@ -153,6 +148,27 @@ class FileListItem extends React.PureComponent {
|
||||||
title={title || name || normalizeURI(uri).substring(7)}
|
title={title || name || normalizeURI(uri).substring(7)}
|
||||||
thumbnail={thumbnail}
|
thumbnail={thumbnail}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isChannel && (
|
||||||
|
<View style={fileListStyle.thumbnail}>
|
||||||
|
<View style={[fileListStyle.channelThumbnailContainer, this.state.autoStyle]}>
|
||||||
|
{hasThumbnail && (
|
||||||
|
<FastImage
|
||||||
|
style={fileListStyle.channelThumbnail}
|
||||||
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
|
source={{ uri: thumbnail }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!hasThumbnail && (
|
||||||
|
<Text style={channelIconStyle.autothumbCharacter}>
|
||||||
|
{title ? title.substring(0, 1).toUpperCase() : claim.name.substring(1, 2).toUpperCase()}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{selected && (
|
{selected && (
|
||||||
<View style={fileListStyle.selectedOverlay}>
|
<View style={fileListStyle.selectedOverlay}>
|
||||||
<Icon name={'check-circle'} solid color={Colors.NextLbryGreen} size={32} />
|
<Icon name={'check-circle'} solid color={Colors.NextLbryGreen} size={32} />
|
||||||
|
@ -194,7 +210,7 @@ class FileListItem extends React.PureComponent {
|
||||||
{(title || name) && (
|
{(title || name) && (
|
||||||
<View style={fileListStyle.titleContainer}>
|
<View style={fileListStyle.titleContainer}>
|
||||||
<Text style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}>
|
<Text style={featuredResult ? fileListStyle.featuredTitle : fileListStyle.title}>
|
||||||
{this.formatTitle(title) || this.formatTitle(name)}
|
{formatTitle(title) || formatTitle(name)}
|
||||||
</Text>
|
</Text>
|
||||||
{isRewardContent && <Icon style={fileListStyle.rewardIcon} name="award" size={12} />}
|
{isRewardContent && <Icon style={fileListStyle.rewardIcon} name="award" size={12} />}
|
||||||
</View>
|
</View>
|
||||||
|
@ -206,17 +222,17 @@ class FileListItem extends React.PureComponent {
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{channel && !hideChannel && (
|
{(channel || isChannel) && !hideChannel && (
|
||||||
<Link
|
<Link
|
||||||
style={fileListStyle.publisher}
|
style={fileListStyle.publisher}
|
||||||
text={channel}
|
text={isChannel ? name : channel}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigateToUri(
|
navigateToUri(
|
||||||
navigation,
|
navigation,
|
||||||
normalizeURI(shortChannelUri || fullChannelUri),
|
normalizeURI(isChannel ? uri : shortChannelUri || fullChannelUri),
|
||||||
null,
|
null,
|
||||||
false,
|
false,
|
||||||
fullChannelUri,
|
isChannel ? claim && claim.permanent_url : fullChannelUri,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -224,7 +240,7 @@ class FileListItem extends React.PureComponent {
|
||||||
|
|
||||||
<View style={fileListStyle.info}>
|
<View style={fileListStyle.info}>
|
||||||
{fileInfo && !isNaN(fileInfo.written_bytes) && fileInfo.written_bytes > 0 && (
|
{fileInfo && !isNaN(fileInfo.written_bytes) && fileInfo.written_bytes > 0 && (
|
||||||
<Text style={fileListStyle.infoText}>{this.getStorageForFileInfo(fileInfo)}</Text>
|
<Text style={fileListStyle.infoText}>{getStorageForFileInfo(fileInfo)}</Text>
|
||||||
)}
|
)}
|
||||||
<DateTime style={fileListStyle.publishInfo} textStyle={fileListStyle.infoText} timeAgo uri={uri} />
|
<DateTime style={fileListStyle.publishInfo} textStyle={fileListStyle.infoText} timeAgo uri={uri} />
|
||||||
</View>
|
</View>
|
||||||
|
@ -237,7 +253,7 @@ class FileListItem extends React.PureComponent {
|
||||||
color={Colors.NextLbryGreen}
|
color={Colors.NextLbryGreen}
|
||||||
height={3}
|
height={3}
|
||||||
style={fileListStyle.progress}
|
style={fileListStyle.progress}
|
||||||
progress={this.getDownloadProgress(fileInfo)}
|
progress={getDownloadProgress(fileInfo)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { normalizeURI } from 'lbry-redux';
|
||||||
import { navigateToUri } from 'utils/helper';
|
import { navigateToUri } from 'utils/helper';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import FileListItem from 'component/fileListItem';
|
import FileListItem from 'component/fileListItem';
|
||||||
import FileResultItem from 'component/fileResultItem';
|
import ClaimResultItem from 'component/claimResultItem';
|
||||||
import fileListStyle from 'styles/fileList';
|
import fileListStyle from 'styles/fileList';
|
||||||
import relatedContentStyle from 'styles/relatedContent';
|
import relatedContentStyle from 'styles/relatedContent';
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ export default class RelatedContent extends React.PureComponent {
|
||||||
{isSearching && <ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />}
|
{isSearching && <ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />}
|
||||||
{recommendedContent &&
|
{recommendedContent &&
|
||||||
recommendedContent.map(result => (
|
recommendedContent.map(result => (
|
||||||
<FileResultItem
|
<ClaimResultItem
|
||||||
style={fileListStyle.item}
|
style={fileListStyle.item}
|
||||||
key={result.claimId}
|
key={result.claimId}
|
||||||
result={result}
|
result={result}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { buildURI, normalizeURI } from 'lbry-redux';
|
||||||
import { ActivityIndicator, FlatList, Image, Text, View } from 'react-native';
|
import { ActivityIndicator, FlatList, Image, Text, View } from 'react-native';
|
||||||
import { navigateToUri } from 'utils/helper';
|
import { navigateToUri } from 'utils/helper';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
|
import ChannelIconItem from 'component/channelIconItem';
|
||||||
|
import channelIconStyle from 'styles/channelIcon';
|
||||||
import discoverStyle from 'styles/discover';
|
import discoverStyle from 'styles/discover';
|
||||||
import FileItem from 'component/fileItem';
|
import FileItem from 'component/fileItem';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
|
@ -11,11 +13,20 @@ import Link from 'component/link';
|
||||||
import Tag from 'component/tag';
|
import Tag from 'component/tag';
|
||||||
|
|
||||||
class SuggestedSubscriptionItem extends React.PureComponent {
|
class SuggestedSubscriptionItem extends React.PureComponent {
|
||||||
|
state = {
|
||||||
|
autoStyle: null,
|
||||||
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { claim, uri, resolveUri } = this.props;
|
const { claim, uri, resolveUri } = this.props;
|
||||||
if (!claim) {
|
if (!claim) {
|
||||||
resolveUri(uri);
|
resolveUri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
autoStyle:
|
||||||
|
ChannelIconItem.AUTO_THUMB_STYLES[Math.floor(Math.random() * ChannelIconItem.AUTO_THUMB_STYLES.length)],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -28,6 +39,7 @@ class SuggestedSubscriptionItem extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasThumbnail = !!thumbnail;
|
||||||
if (isResolvingUri) {
|
if (isResolvingUri) {
|
||||||
return (
|
return (
|
||||||
<View style={subscriptionsStyle.itemLoadingContainer}>
|
<View style={subscriptionsStyle.itemLoadingContainer}>
|
||||||
|
@ -38,12 +50,15 @@ class SuggestedSubscriptionItem extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={subscriptionsStyle.suggestedItem}>
|
<View style={subscriptionsStyle.suggestedItem}>
|
||||||
<View style={subscriptionsStyle.suggestedItemThumbnailContainer}>
|
<View style={[subscriptionsStyle.suggestedItemThumbnailContainer, this.state.autoStyle]}>
|
||||||
<Image
|
{hasThumbnail && (
|
||||||
style={subscriptionsStyle.suggestedItemThumbnail}
|
<Image style={subscriptionsStyle.suggestedItemThumbnail} resizeMode={'cover'} source={{ uri: thumbnail }} />
|
||||||
resizeMode={'cover'}
|
)}
|
||||||
source={thumbnail ? { uri: thumbnail } : require('../../assets/default_avatar.jpg')}
|
{!hasThumbnail && (
|
||||||
/>
|
<Text style={channelIconStyle.autothumbCharacter}>
|
||||||
|
{title ? title.substring(0, 1).toUpperCase() : claim ? claim.name.substring(1, 2).toUpperCase() : ''}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={subscriptionsStyle.suggestedItemDetails}>
|
<View style={subscriptionsStyle.suggestedItemDetails}>
|
||||||
|
|
|
@ -21,6 +21,7 @@ import ChannelRewardsDriver from 'component/channelRewardsDriver';
|
||||||
import Colors from 'styles/colors';
|
import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import EmptyStateView from 'component/emptyStateView';
|
import EmptyStateView from 'component/emptyStateView';
|
||||||
|
import FastImage from 'react-native-fast-image';
|
||||||
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
import Link from 'component/link';
|
import Link from 'component/link';
|
||||||
|
@ -867,9 +868,9 @@ export default class ChannelCreator extends React.PureComponent {
|
||||||
>
|
>
|
||||||
<View style={[channelCreatorStyle.channelListAvatar, itemAutoStyle]}>
|
<View style={[channelCreatorStyle.channelListAvatar, itemAutoStyle]}>
|
||||||
{itemThumbnailUrl && (
|
{itemThumbnailUrl && (
|
||||||
<Image
|
<FastImage
|
||||||
style={channelCreatorStyle.avatarImage}
|
style={channelCreatorStyle.avatarImage}
|
||||||
resizeMode={'cover'}
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
source={{ uri: itemThumbnailUrl }}
|
source={{ uri: itemThumbnailUrl }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -15,7 +15,7 @@ import Colors from 'styles/colors';
|
||||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||||
import PageHeader from 'component/pageHeader';
|
import PageHeader from 'component/pageHeader';
|
||||||
import FileListItem from 'component/fileListItem';
|
import FileListItem from 'component/fileListItem';
|
||||||
import FileResultItem from 'component/fileResultItem';
|
import ClaimResultItem from 'component/claimResultItem';
|
||||||
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
import FloatingWalletBalance from 'component/floatingWalletBalance';
|
||||||
import UriBar from 'component/uriBar';
|
import UriBar from 'component/uriBar';
|
||||||
import searchStyle from 'styles/search';
|
import searchStyle from 'styles/search';
|
||||||
|
@ -213,7 +213,12 @@ class SearchPage extends React.PureComponent {
|
||||||
ListEmptyComponent={!isSearching ? this.listEmptyComponent() : null}
|
ListEmptyComponent={!isSearching ? this.listEmptyComponent() : null}
|
||||||
ListHeaderComponent={this.listHeaderComponent(this.state.showTagResult, this.state.currentQuery)}
|
ListHeaderComponent={this.listHeaderComponent(this.state.showTagResult, this.state.currentQuery)}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<FileResultItem key={item.claimId} result={item} style={searchStyle.resultItem} navigation={navigation} />
|
<ClaimResultItem
|
||||||
|
key={item.claimId}
|
||||||
|
result={item}
|
||||||
|
style={searchStyle.resultItem}
|
||||||
|
navigation={navigation}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -73,7 +73,7 @@ class SubscriptionsPage extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// this.onComponentFocused();
|
this.onComponentFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
|
|
@ -38,6 +38,18 @@ const fileListStyle = StyleSheet.create({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
channelThumbnailContainer: {
|
||||||
|
width: thumbnailHeight, // maintain same width and height
|
||||||
|
height: thumbnailHeight,
|
||||||
|
borderRadius: 140,
|
||||||
|
overflow: 'hidden',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
channelThumbnail: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
selectedOverlay: {
|
selectedOverlay: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 0,
|
left: 0,
|
||||||
|
@ -63,6 +75,9 @@ const fileListStyle = StyleSheet.create({
|
||||||
marginTop: screenWidthPixels <= 720 ? 1 : 3,
|
marginTop: screenWidthPixels <= 720 ? 1 : 3,
|
||||||
color: Colors.LbryGreen,
|
color: Colors.LbryGreen,
|
||||||
},
|
},
|
||||||
|
channelContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
loading: {
|
loading: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
},
|
},
|
||||||
|
|
|
@ -199,6 +199,8 @@ const subscriptionsStyle = StyleSheet.create({
|
||||||
height: 70,
|
height: 70,
|
||||||
borderRadius: 140,
|
borderRadius: 140,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
suggestedItemThumbnail: {
|
suggestedItemThumbnail: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
|
@ -370,3 +370,25 @@ export function uploadImageAsset(filePath, success, failure) {
|
||||||
export function formatLbryUrlForWeb(url) {
|
export function formatLbryUrlForWeb(url) {
|
||||||
return url.replace('lbry://', '/').replace(/#/g, ':');
|
return url.replace('lbry://', '/').replace(/#/g, ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDownloadProgress(fileInfo) {
|
||||||
|
return Math.ceil((fileInfo.written_bytes / fileInfo.total_bytes) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatTitle(title) {
|
||||||
|
if (!title) {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return title.length > 80 ? title.substring(0, 77).trim() + '...' : title;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue