diff --git a/app/src/component/dateTime/index.js b/app/src/component/dateTime/index.js new file mode 100644 index 00000000..3e1ad14a --- /dev/null +++ b/app/src/component/dateTime/index.js @@ -0,0 +1,16 @@ +import { connect } from 'react-redux'; +import { doFetchBlock, makeSelectBlockDate } from 'lbry-redux'; +import DateTime from './view'; + +const select = (state, props) => ({ + date: !props.date && props.block ? makeSelectBlockDate(props.block)(state) : props.date, +}); + +const perform = dispatch => ({ + fetchBlock: height => dispatch(doFetchBlock(height)), +}); + +export default connect( + select, + perform +)(DateTime); diff --git a/app/src/component/dateTime/view.js b/app/src/component/dateTime/view.js new file mode 100644 index 00000000..0261b81a --- /dev/null +++ b/app/src/component/dateTime/view.js @@ -0,0 +1,52 @@ +// @flow +import React from 'react'; +import moment from 'moment'; +import { View, Text } from 'react-native'; + +type Props = { + date?: number, + timeAgo?: boolean, + formatOptions: {}, + show?: string, +}; + +class DateTime extends React.PureComponent { + static SHOW_DATE = 'date'; + static SHOW_TIME = 'time'; + static SHOW_BOTH = 'both'; + + static defaultProps = { + formatOptions: { + month: 'long', + day: 'numeric', + year: 'numeric', + }, + }; + + render() { + const { date, formatOptions, timeAgo, style, textStyle } = this.props; + const show = this.props.show || DateTime.SHOW_BOTH; + const locale = 'en-US'; // default to en-US until we get a working i18n module for RN + + if (timeAgo) { + return date ? {moment(date).from(moment())} : null; + } + + return ( + + + {date && + (show === DateTime.SHOW_BOTH || show === DateTime.SHOW_DATE) && + date.toLocaleDateString([locale, 'en-US'], formatOptions)} + {show === DateTime.SHOW_BOTH && ' '} + {date && + (show === DateTime.SHOW_BOTH || show === DateTime.SHOW_TIME) && + date.toLocaleTimeString()} + {!date && '...'} + + + ); + } +} + +export default DateTime; diff --git a/app/src/component/fileItem/view.js b/app/src/component/fileItem/view.js index 56547638..e37d0571 100644 --- a/app/src/component/fileItem/view.js +++ b/app/src/component/fileItem/view.js @@ -2,14 +2,15 @@ import React from 'react'; import { normalizeURI } from 'lbry-redux'; import { NavigationActions } from 'react-navigation'; import { NativeModules, Text, View, TouchableOpacity } from 'react-native'; -import { navigateToUri } from '../../utils/helper'; -import Colors from '../../styles/colors'; -import FileItemMedia from '../fileItemMedia'; -import FilePrice from '../filePrice'; +import { navigateToUri } from 'utils/helper'; +import Colors from 'styles/colors'; +import DateTime from 'component/dateTime'; +import FileItemMedia from 'component/fileItemMedia'; +import FilePrice from 'component/filePrice'; import Icon from 'react-native-vector-icons/FontAwesome5'; -import Link from '../link'; -import NsfwOverlay from '../nsfwOverlay'; -import discoverStyle from '../../styles/discover'; +import Link from 'component/link'; +import NsfwOverlay from 'component/nsfwOverlay'; +import discoverStyle from 'styles/discover'; class FileItem extends React.PureComponent { constructor(props) { @@ -50,6 +51,7 @@ class FileItem extends React.PureComponent { const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw; const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id); const channelName = claim ? claim.channel_name : null; + const height = claim ? claim.height : null; return ( @@ -71,11 +73,14 @@ class FileItem extends React.PureComponent { {title} {isRewardContent && } - {channelName && - { - const channelUri = normalizeURI(channelName); - navigateToUri(navigation, channelUri); - }} />} + + {channelName && + { + const channelUri = normalizeURI(channelName); + navigateToUri(navigation, channelUri); + }} />} + + {obscureNsfw && navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />} diff --git a/app/src/component/fileListItem/view.js b/app/src/component/fileListItem/view.js index 20d4fa12..1f771617 100644 --- a/app/src/component/fileListItem/view.js +++ b/app/src/component/fileListItem/view.js @@ -8,12 +8,13 @@ import { TouchableOpacity, View } from 'react-native'; -import { navigateToUri, formatBytes } from '../../utils/helper'; -import Colors from '../../styles/colors'; -import FileItemMedia from '../fileItemMedia'; -import Link from '../../component/link'; -import NsfwOverlay from '../../component/nsfwOverlay'; -import fileListStyle from '../../styles/fileList'; +import { navigateToUri, formatBytes } from 'utils/helper'; +import Colors from 'styles/colors'; +import DateTime from 'component/dateTime'; +import FileItemMedia from 'component/fileItemMedia'; +import Link from 'component/link'; +import NsfwOverlay from 'component/nsfwOverlay'; +import fileListStyle from 'styles/fileList'; class FileListItem extends React.PureComponent { getStorageForFileInfo = (fileInfo) => { @@ -62,11 +63,11 @@ class FileListItem extends React.PureComponent { const isResolving = !fileInfo && isResolvingUri; const title = fileInfo ? fileInfo.metadata.title : metadata && metadata.title ? metadata.title : parseURI(uri).contentName; - let name; - let channel; + let name, channel, height; if (claim) { name = claim.name; channel = claim.channel_name; + height = claim.height; } return ( @@ -93,9 +94,13 @@ class FileListItem extends React.PureComponent { navigateToUri(navigation, channelUri); }} />} + + {fileInfo && {this.getStorageForFileInfo(fileInfo)}} + + + {fileInfo && - {this.getStorageForFileInfo(fileInfo)} {!fileInfo.completed && diff --git a/app/src/page/splash/index.js b/app/src/page/splash/index.js index fc149590..40b2d64b 100644 --- a/app/src/page/splash/index.js +++ b/app/src/page/splash/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { doBalanceSubscribe, doBlackListedOutpointsSubscribe, doToast } from 'lbry-redux'; +import { doBalanceSubscribe, doBlackListedOutpointsSubscribe, doUpdateBlockHeight, doToast } from 'lbry-redux'; import { doAuthenticate, doCheckSubscriptionsInit, @@ -11,7 +11,7 @@ import { selectUser, selectEmailToVerify } from 'lbryinc'; -import { doDeleteCompleteBlobs } from '../../redux/actions/file'; +import { doDeleteCompleteBlobs } from 'redux/actions/file'; import SplashScreen from './view'; const select = state => ({ @@ -29,6 +29,7 @@ const perform = dispatch => ({ fetchSubscriptions: (callback) => dispatch(doFetchMySubscriptions(callback)), notify: data => dispatch(doToast(data)), setEmailToVerify: email => dispatch(doUserEmailToVerify(email)), + updateBlockHeight: () => dispatch(doUpdateBlockHeight()), verifyUserEmail: (token, recaptcha) => dispatch(doUserEmailVerify(token, recaptcha)), verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)) }); diff --git a/app/src/page/splash/view.js b/app/src/page/splash/view.js index 1c98c3a0..3fa6259d 100644 --- a/app/src/page/splash/view.js +++ b/app/src/page/splash/view.js @@ -18,6 +18,8 @@ import Colors from '../../styles/colors'; import Constants from '../../constants'; import splashStyle from '../../styles/splash'; +const BLOCK_HEIGHT_INTERVAL = 1000 * 60 * 2.5; // every 2.5 minutes + class SplashScreen extends React.PureComponent { static navigationOptions = { title: 'Splash' @@ -147,6 +149,7 @@ class SplashScreen extends React.PureComponent { balanceSubscribe, blacklistedOutpointsSubscribe, checkSubscriptionsInit, + updateBlockHeight, navigation, notify } = this.props; @@ -154,6 +157,8 @@ class SplashScreen extends React.PureComponent { balanceSubscribe(); blacklistedOutpointsSubscribe(); checkSubscriptionsInit(); + updateBlockHeight(); + setInterval(() => { updateBlockHeight(); }, BLOCK_HEIGHT_INTERVAL); NativeModules.VersionInfo.getAppVersion().then(appVersion => { this.setState({ shouldAuthenticate: true }); authenticate(appVersion, Platform.OS); diff --git a/app/src/styles/discover.js b/app/src/styles/discover.js index 5d9e2b07..5d32987f 100644 --- a/app/src/styles/discover.js +++ b/app/src/styles/discover.js @@ -134,6 +134,18 @@ const discoverStyle = StyleSheet.create({ }, titleText: { fontFamily: 'Inter-UI-Regular' + }, + detailsRow: { + flexDirection: 'row', + justifyContent: 'space-between' + }, + dateTime: { + marginTop: 2 + }, + dateTimeText: { + fontFamily: 'Inter-UI-Regular', + fontSize: 14, + color: Colors.DescriptionGrey } }); diff --git a/app/src/styles/fileList.js b/app/src/styles/fileList.js index 968f2399..a9c9824e 100644 --- a/app/src/styles/fileList.js +++ b/app/src/styles/fileList.js @@ -45,14 +45,19 @@ const fileListStyle = StyleSheet.create({ loading: { position: 'absolute' }, - downloadInfo: { - marginTop: (screenWidthPixels <= 720) ? 4 : 8 + info: { + marginTop: (screenWidthPixels <= 720) ? 1 : 2, + flexDirection: 'row', + justifyContent: 'space-between' }, - downloadStorage: { + infoText: { fontFamily: 'Inter-UI-Regular', fontSize: (screenWidthPixels <= 720) ? 12 : 14, color: Colors.ChannelGrey }, + downloadInfo: { + marginTop: 2 + }, progress: { marginTop: (screenWidthPixels <= 720) ? 2 : 4, height: 3, @@ -65,7 +70,7 @@ const fileListStyle = StyleSheet.create({ progressRemaining: { backgroundColor: Colors.LbryGreen, opacity: 0.2 - } + }, }); export default fileListStyle;