User history #1846
36 changed files with 716 additions and 161 deletions
|
@ -50,7 +50,7 @@
|
||||||
"formik": "^0.10.4",
|
"formik": "^0.10.4",
|
||||||
"hast-util-sanitize": "^1.1.2",
|
"hast-util-sanitize": "^1.1.2",
|
||||||
"keytar": "^4.2.1",
|
"keytar": "^4.2.1",
|
||||||
"lbry-redux": "lbryio/lbry-redux#421321a78397251589e5a890f4caa95e79975e2b",
|
"lbry-redux": "lbryio/lbry-redux#d1cee82af119c0c5f98ec27f94b2e7f61e34b54c",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
"mammoth": "^1.4.6",
|
"mammoth": "^1.4.6",
|
||||||
"mime": "^2.3.1",
|
"mime": "^2.3.1",
|
||||||
|
|
|
@ -24,6 +24,9 @@ type Props = {
|
||||||
stretch?: boolean,
|
stretch?: boolean,
|
||||||
affixClass?: string, // class applied to prefix/postfix label
|
affixClass?: string, // class applied to prefix/postfix label
|
||||||
firstInList?: boolean, // at the top of a list, no padding top
|
firstInList?: boolean, // at the top of a list, no padding top
|
||||||
|
inputProps: {
|
||||||
|
disabled?: boolean,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormField extends React.PureComponent<Props> {
|
export class FormField extends React.PureComponent<Props> {
|
||||||
|
|
|
@ -9,6 +9,7 @@ type Props = {
|
||||||
verticallyCentered?: boolean,
|
verticallyCentered?: boolean,
|
||||||
stretch?: boolean,
|
stretch?: boolean,
|
||||||
alignRight?: boolean,
|
alignRight?: boolean,
|
||||||
|
centered?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormRow extends React.PureComponent<Props> {
|
export class FormRow extends React.PureComponent<Props> {
|
||||||
|
@ -17,7 +18,7 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children, padded, verticallyCentered, stretch, alignRight } = this.props;
|
const { children, padded, verticallyCentered, stretch, alignRight, centered } = this.props;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('form-row', {
|
className={classnames('form-row', {
|
||||||
|
@ -25,6 +26,7 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
'form-row--vertically-centered': verticallyCentered,
|
'form-row--vertically-centered': verticallyCentered,
|
||||||
'form-row--stretch': stretch,
|
'form-row--stretch': stretch,
|
||||||
'form-row--right': alignRight,
|
'form-row--right': alignRight,
|
||||||
|
'form-row--centered': centered,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -8,7 +8,10 @@ import {
|
||||||
makeSelectClaimIsMine,
|
makeSelectClaimIsMine,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
import {
|
||||||
|
selectRewardContentClaimIds,
|
||||||
|
makeSelectContentPositionForUri,
|
||||||
|
} from 'redux/selectors/content';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import { selectPendingPublish } from 'redux/selectors/publish';
|
import { selectPendingPublish } from 'redux/selectors/publish';
|
||||||
import FileCard from './view';
|
import FileCard from './view';
|
||||||
|
@ -32,12 +35,14 @@ const select = (state, props) => {
|
||||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
||||||
...fileCardInfo,
|
...fileCardInfo,
|
||||||
pending: !!pendingPublish,
|
pending: !!pendingPublish,
|
||||||
|
position: makeSelectContentPositionForUri(props.uri)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
|
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
||||||
import type { Claim, Metadata } from 'types/claim';
|
import type { Claim, Metadata } from 'types/claim';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import FilePrice from 'component/filePrice';
|
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { openCopyLinkMenu } from '../../util/contextMenu';
|
import FilePrice from 'component/filePrice';
|
||||||
|
import { openCopyLinkMenu } from 'util/contextMenu';
|
||||||
|
|
||||||
// TODO: iron these out
|
// TODO: iron these out
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -21,8 +22,10 @@ type Props = {
|
||||||
rewardedContentClaimIds: Array<string>,
|
rewardedContentClaimIds: Array<string>,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
showPrice: boolean,
|
|
||||||
pending?: boolean,
|
pending?: boolean,
|
||||||
|
position: ?number,
|
||||||
|
lastViewed: ?number,
|
||||||
|
clearHistoryUri: string => void,
|
||||||
/* eslint-disable react/no-unused-prop-types */
|
/* eslint-disable react/no-unused-prop-types */
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
|
@ -59,8 +62,10 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
rewardedContentClaimIds,
|
rewardedContentClaimIds,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
showPrice,
|
|
||||||
pending,
|
pending,
|
||||||
|
position,
|
||||||
|
clearHistoryUri,
|
||||||
|
showPrice,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const shouldHide = !claimIsMine && !pending && obscureNsfw && metadata && metadata.nsfw;
|
const shouldHide = !claimIsMine && !pending && obscureNsfw && metadata && metadata.nsfw;
|
||||||
|
@ -103,6 +108,7 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
{showPrice && <FilePrice hideFree uri={uri} />}
|
{showPrice && <FilePrice hideFree uri={uri} />}
|
||||||
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
||||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
|
{position && <Icon icon={icons.REFRESH} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -7,8 +7,7 @@ import {
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doOpenFileInShell } from 'redux/actions/file';
|
import { doOpenFileInShell } from 'redux/actions/file';
|
||||||
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
|
import { doPurchaseUri, doStartDownload, doSetPlayingUri } from 'redux/actions/content';
|
||||||
import { doPause } from 'redux/actions/media';
|
|
||||||
import FileDownloadLink from './view';
|
import FileDownloadLink from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
|
@ -24,7 +23,7 @@ const perform = dispatch => ({
|
||||||
openInShell: path => dispatch(doOpenFileInShell(path)),
|
openInShell: path => dispatch(doOpenFileInShell(path)),
|
||||||
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
||||||
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
||||||
doPause: () => dispatch(doPause()),
|
pause: () => dispatch(doSetPlayingUri(null)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Props = {
|
||||||
restartDownload: (string, number) => void,
|
restartDownload: (string, number) => void,
|
||||||
openInShell: string => void,
|
openInShell: string => void,
|
||||||
purchaseUri: string => void,
|
purchaseUri: string => void,
|
||||||
doPause: () => void,
|
pause: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileDownloadLink extends React.PureComponent<Props> {
|
class FileDownloadLink extends React.PureComponent<Props> {
|
||||||
|
@ -50,14 +50,13 @@ class FileDownloadLink extends React.PureComponent<Props> {
|
||||||
purchaseUri,
|
purchaseUri,
|
||||||
costInfo,
|
costInfo,
|
||||||
loading,
|
loading,
|
||||||
doPause,
|
pause,
|
||||||
claim,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const openFile = () => {
|
const openFile = () => {
|
||||||
if (fileInfo) {
|
if (fileInfo) {
|
||||||
openInShell(fileInfo.download_path);
|
openInShell(fileInfo.download_path);
|
||||||
doPause();
|
pause();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ import { connect } from 'react-redux';
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import { doChangeVolume } from 'redux/actions/app';
|
import { doChangeVolume } from 'redux/actions/app';
|
||||||
import { selectVolume } from 'redux/selectors/app';
|
import { selectVolume } from 'redux/selectors/app';
|
||||||
import { doPlayUri, doSetPlayingUri } from 'redux/actions/content';
|
import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content';
|
||||||
import { doPlay, doPause, savePosition } from 'redux/actions/media';
|
|
||||||
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
|
||||||
import {
|
import {
|
||||||
makeSelectMetadataForUri,
|
makeSelectMetadataForUri,
|
||||||
makeSelectContentTypeForUri,
|
makeSelectContentTypeForUri,
|
||||||
|
@ -15,9 +13,9 @@ import {
|
||||||
makeSelectDownloadingForUri,
|
makeSelectDownloadingForUri,
|
||||||
selectSearchBarFocused,
|
selectSearchBarFocused,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
|
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
||||||
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
|
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
import { selectPlayingUri, makeSelectContentPositionForUri } from 'redux/selectors/content';
|
||||||
import { selectPlayingUri } from 'redux/selectors/content';
|
|
||||||
import { selectFileInfoErrors } from 'redux/selectors/file_info';
|
import { selectFileInfoErrors } from 'redux/selectors/file_info';
|
||||||
import FileViewer from './view';
|
import FileViewer from './view';
|
||||||
|
|
||||||
|
@ -32,8 +30,7 @@ const select = (state, props) => ({
|
||||||
playingUri: selectPlayingUri(state),
|
playingUri: selectPlayingUri(state),
|
||||||
contentType: makeSelectContentTypeForUri(props.uri)(state),
|
contentType: makeSelectContentTypeForUri(props.uri)(state),
|
||||||
volume: selectVolume(state),
|
volume: selectVolume(state),
|
||||||
mediaPaused: selectMediaPaused(state),
|
position: makeSelectContentPositionForUri(props.uri)(state),
|
||||||
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
searchBarFocused: selectSearchBarFocused(state),
|
searchBarFocused: selectSearchBarFocused(state),
|
||||||
fileInfoErrors: selectFileInfoErrors(state),
|
fileInfoErrors: selectFileInfoErrors(state),
|
||||||
|
@ -43,10 +40,9 @@ const perform = dispatch => ({
|
||||||
play: uri => dispatch(doPlayUri(uri)),
|
play: uri => dispatch(doPlayUri(uri)),
|
||||||
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
||||||
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
||||||
doPlay: () => dispatch(doPlay()),
|
|
||||||
doPause: () => dispatch(doPause()),
|
|
||||||
savePosition: (claimId, position) => dispatch(savePosition(claimId, position)),
|
|
||||||
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
||||||
|
savePosition: (claimId, outpoint, position) =>
|
||||||
|
dispatch(savePosition(claimId, outpoint, position)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -27,9 +27,11 @@ class MediaPlayer extends React.PureComponent {
|
||||||
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentDidUpdate(nextProps) {
|
||||||
const el = this.refs.media.children[0];
|
const el = this.refs.media.children[0];
|
||||||
if (!this.props.paused && nextProps.paused && !el.paused) el.pause();
|
if (this.props.playingUri && !nextProps.playingUri && !el.paused) {
|
||||||
|
el.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -86,11 +88,15 @@ class MediaPlayer extends React.PureComponent {
|
||||||
document.addEventListener('keydown', this.togglePlayListener);
|
document.addEventListener('keydown', this.togglePlayListener);
|
||||||
const mediaElement = this.media.children[0];
|
const mediaElement = this.media.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.currentTime = position || 0;
|
if (position) {
|
||||||
mediaElement.addEventListener('play', () => this.props.doPlay());
|
mediaElement.currentTime = position;
|
||||||
mediaElement.addEventListener('pause', () => this.props.doPause());
|
}
|
||||||
mediaElement.addEventListener('timeupdate', () =>
|
mediaElement.addEventListener('timeupdate', () =>
|
||||||
this.props.savePosition(claim.claim_id, mediaElement.currentTime)
|
this.props.savePosition(
|
||||||
|
claim.claim_id,
|
||||||
|
`${claim.txid}:${claim.nout}`,
|
||||||
|
mediaElement.currentTime
|
||||||
|
)
|
||||||
);
|
);
|
||||||
mediaElement.addEventListener('click', this.togglePlayListener);
|
mediaElement.addEventListener('click', this.togglePlayListener);
|
||||||
mediaElement.addEventListener('loadedmetadata', loadedMetadata.bind(this), {
|
mediaElement.addEventListener('loadedmetadata', loadedMetadata.bind(this), {
|
||||||
|
@ -136,7 +142,6 @@ class MediaPlayer extends React.PureComponent {
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.removeEventListener('click', this.togglePlayListener);
|
mediaElement.removeEventListener('click', this.togglePlayListener);
|
||||||
}
|
}
|
||||||
this.props.doPause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFullScreen(event) {
|
toggleFullScreen(event) {
|
||||||
|
|
|
@ -34,11 +34,8 @@ type Props = {
|
||||||
volume: number,
|
volume: number,
|
||||||
claim: Claim,
|
claim: Claim,
|
||||||
uri: string,
|
uri: string,
|
||||||
doPlay: () => void,
|
savePosition: (string, string, number) => void,
|
||||||
doPause: () => void,
|
position: ?number,
|
||||||
savePosition: (string, number) => void,
|
|
||||||
mediaPaused: boolean,
|
|
||||||
mediaPosition: ?number,
|
|
||||||
className: ?string,
|
className: ?string,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
play: string => void,
|
play: string => void,
|
||||||
|
@ -202,11 +199,8 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
volume,
|
volume,
|
||||||
claim,
|
claim,
|
||||||
uri,
|
uri,
|
||||||
doPlay,
|
|
||||||
doPause,
|
|
||||||
savePosition,
|
savePosition,
|
||||||
mediaPaused,
|
position,
|
||||||
mediaPosition,
|
|
||||||
className,
|
className,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
mediaType,
|
mediaType,
|
||||||
|
@ -251,14 +245,12 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
downloadCompleted={fileInfo.completed}
|
downloadCompleted={fileInfo.completed}
|
||||||
changeVolume={changeVolume}
|
changeVolume={changeVolume}
|
||||||
volume={volume}
|
volume={volume}
|
||||||
doPlay={doPlay}
|
|
||||||
doPause={doPause}
|
|
||||||
savePosition={savePosition}
|
savePosition={savePosition}
|
||||||
claim={claim}
|
claim={claim}
|
||||||
uri={uri}
|
uri={uri}
|
||||||
paused={mediaPaused}
|
position={position}
|
||||||
position={mediaPosition}
|
|
||||||
startedPlayingCb={this.startedPlayingCb}
|
startedPlayingCb={this.startedPlayingCb}
|
||||||
|
playingUri={playingUri}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,11 +4,10 @@ import {
|
||||||
selectPageTitle,
|
selectPageTitle,
|
||||||
selectIsBackDisabled,
|
selectIsBackDisabled,
|
||||||
selectIsForwardDisabled,
|
selectIsForwardDisabled,
|
||||||
selectNavLinks,
|
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||||
import { doDownloadUpgrade } from 'redux/actions/app';
|
import { doDownloadUpgrade } from 'redux/actions/app';
|
||||||
import { selectIsUpgradeAvailable } from 'redux/selectors/app';
|
import { selectIsUpgradeAvailable, selectNavLinks } from 'redux/selectors/app';
|
||||||
import { formatCredits } from 'util/formatCredits';
|
import { formatCredits } from 'util/formatCredits';
|
||||||
import Page from './view';
|
import Page from './view';
|
||||||
|
|
||||||
|
@ -28,4 +27,7 @@ const perform = dispatch => ({
|
||||||
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(Page);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(Page);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import InvitePage from 'page/invite';
|
||||||
import BackupPage from 'page/backup';
|
import BackupPage from 'page/backup';
|
||||||
import SubscriptionsPage from 'page/subscriptions';
|
import SubscriptionsPage from 'page/subscriptions';
|
||||||
import SearchPage from 'page/search';
|
import SearchPage from 'page/search';
|
||||||
|
import UserHistoryPage from 'page/userHistory';
|
||||||
|
|
||||||
const route = (props, page, routesMap) => {
|
const route = (props, page, routesMap) => {
|
||||||
const component = routesMap[page];
|
const component = routesMap[page];
|
||||||
|
@ -53,6 +54,7 @@ const Router = props => {
|
||||||
wallet: <WalletPage params={params} />,
|
wallet: <WalletPage params={params} />,
|
||||||
subscriptions: <SubscriptionsPage params={params} />,
|
subscriptions: <SubscriptionsPage params={params} />,
|
||||||
search: <SearchPage {...params} />,
|
search: <SearchPage {...params} />,
|
||||||
|
user_history: <UserHistoryPage {...params} />,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectNavLinks } from 'lbry-redux';
|
import { selectNavLinks } from 'redux/selectors/app';
|
||||||
import { selectNotifications } from 'redux/selectors/subscriptions';
|
import { selectNotifications } from 'redux/selectors/subscriptions';
|
||||||
import SideBar from './view';
|
import SideBar from './view';
|
||||||
|
|
||||||
|
|
27
src/renderer/component/userHistory/index.js
Normal file
27
src/renderer/component/userHistory/index.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { selectHistoryPageCount, makeSelectHistoryForPage } from 'redux/selectors/content';
|
||||||
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
|
import { selectCurrentParams, makeSelectCurrentParam } from 'lbry-redux';
|
||||||
|
import { doClearContentHistoryUri } from 'redux/actions/content';
|
||||||
|
import UserHistory from './view';
|
||||||
|
|
||||||
|
const select = state => {
|
||||||
|
const paramPage = Number(makeSelectCurrentParam('page')(state) || 0);
|
||||||
|
return {
|
||||||
|
pageCount: selectHistoryPageCount(state),
|
||||||
|
page: paramPage,
|
||||||
|
params: selectCurrentParams(state),
|
||||||
|
history: makeSelectHistoryForPage(paramPage)(state),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
|
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserHistory);
|
167
src/renderer/component/userHistory/view.jsx
Normal file
167
src/renderer/component/userHistory/view.jsx
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import { FormField, FormRow } from 'component/common/form';
|
||||||
|
import ReactPaginate from 'react-paginate';
|
||||||
|
import UserHistoryItem from 'component/userHistoryItem';
|
||||||
|
|
||||||
|
type HistoryItem = {
|
||||||
|
uri: string,
|
||||||
|
lastViewed: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
history: Array<HistoryItem>,
|
||||||
|
page: number,
|
||||||
|
pageCount: number,
|
||||||
|
navigate: (string, {}) => void,
|
||||||
|
clearHistoryUri: string => void,
|
||||||
|
params: { page: number },
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
itemsSelected: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserHistoryPage extends React.PureComponent<Props, State> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
itemsSelected: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
(this: any).selectAll = this.selectAll.bind(this);
|
||||||
|
(this: any).unselectAll = this.unselectAll.bind(this);
|
||||||
|
(this: any).removeSelected = this.removeSelected.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect(uri: string) {
|
||||||
|
const { itemsSelected } = this.state;
|
||||||
|
|
||||||
|
const newItemsSelected = { ...itemsSelected };
|
||||||
|
if (itemsSelected[uri]) {
|
||||||
|
delete newItemsSelected[uri];
|
||||||
|
} else {
|
||||||
|
newItemsSelected[uri] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
itemsSelected: { ...newItemsSelected },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changePage(pageNumber: number) {
|
||||||
|
const { params } = this.props;
|
||||||
|
const newParams = { ...params, page: pageNumber };
|
||||||
|
this.props.navigate('/user_history', newParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
paginate(e: SyntheticKeyboardEvent<*>) {
|
||||||
|
const pageFromInput = Number(e.currentTarget.value);
|
||||||
|
if (
|
||||||
|
pageFromInput &&
|
||||||
|
e.keyCode === 13 &&
|
||||||
|
!Number.isNaN(pageFromInput) &&
|
||||||
|
pageFromInput > 0 &&
|
||||||
|
pageFromInput <= this.props.pageCount
|
||||||
|
) {
|
||||||
|
this.changePage(pageFromInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAll() {
|
||||||
|
const { history } = this.props;
|
||||||
|
const newSelectedState = {};
|
||||||
|
history.forEach(({ uri }) => (newSelectedState[uri] = true));
|
||||||
|
this.setState({ itemsSelected: newSelectedState });
|
||||||
|
}
|
||||||
|
|
||||||
|
unselectAll() {
|
||||||
|
this.setState({
|
||||||
|
itemsSelected: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSelected() {
|
||||||
|
const { clearHistoryUri } = this.props;
|
||||||
|
const { itemsSelected } = this.state;
|
||||||
|
|
||||||
|
Object.keys(itemsSelected).forEach(uri => clearHistoryUri(uri));
|
||||||
|
this.setState({
|
||||||
|
itemsSelected: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { history, page, pageCount } = this.props;
|
||||||
|
const { itemsSelected } = this.state;
|
||||||
|
|
||||||
|
const allSelected = Object.keys(itemsSelected).length === history.length;
|
||||||
|
const selectHandler = allSelected ? this.unselectAll : this.selectAll;
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className="card__actions card__actions--between">
|
||||||
|
{Object.keys(itemsSelected).length ? (
|
||||||
|
<Button button="link" label={__('Delete')} onClick={this.removeSelected} />
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
{/* Using an empty span so spacing stays the same if the button isn't rendered */}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
label={allSelected ? __('Cancel') : __('Select All')}
|
||||||
|
onClick={selectHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{!!history.length && (
|
||||||
|
<table className="card--section table table--stretch table--history">
|
||||||
|
<tbody>
|
||||||
|
{history.map(item => (
|
||||||
|
<UserHistoryItem
|
||||||
|
key={item.uri}
|
||||||
|
uri={item.uri}
|
||||||
|
lastViewed={item.lastViewed}
|
||||||
|
selected={!!itemsSelected[item.uri]}
|
||||||
|
onSelect={() => {
|
||||||
|
this.onSelect(item.uri);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
{pageCount > 1 && (
|
||||||
|
<FormRow padded verticallyCentered centered>
|
||||||
|
<ReactPaginate
|
||||||
|
pageCount={pageCount}
|
||||||
|
pageRangeDisplayed={2}
|
||||||
|
previousLabel="‹"
|
||||||
|
nextLabel="›"
|
||||||
|
activeClassName="pagination__item--selected"
|
||||||
|
pageClassName="pagination__item"
|
||||||
|
previousClassName="pagination__item pagination__item--previous"
|
||||||
|
nextClassName="pagination__item pagination__item--next"
|
||||||
|
breakClassName="pagination__item pagination__item--break"
|
||||||
|
marginPagesDisplayed={2}
|
||||||
|
onPageChange={e => this.changePage(e.selected)}
|
||||||
|
forcePage={page}
|
||||||
|
initialPage={page}
|
||||||
|
containerClassName="pagination"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
className="paginate-channel"
|
||||||
|
onKeyUp={e => this.paginate(e)}
|
||||||
|
prefix={__('Go to page:')}
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default UserHistoryPage;
|
16
src/renderer/component/userHistoryItem/index.js
Normal file
16
src/renderer/component/userHistoryItem/index.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doResolveUri, makeSelectClaimForUri } from 'lbry-redux';
|
||||||
|
import UserHistoryItem from './view';
|
||||||
|
|
||||||
|
const select = (state, props) => ({
|
||||||
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserHistoryItem);
|
64
src/renderer/component/userHistoryItem/view.jsx
Normal file
64
src/renderer/component/userHistoryItem/view.jsx
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
import moment from 'moment';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import Button from 'component/button';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
lastViewed: number,
|
||||||
|
uri: string,
|
||||||
|
claim: ?Claim,
|
||||||
|
selected: boolean,
|
||||||
|
onSelect: () => void,
|
||||||
|
resolveUri: string => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserHistoryItem extends React.PureComponent<Props> {
|
||||||
|
componentDidMount() {
|
||||||
|
const { claim, uri, resolveUri } = this.props;
|
||||||
|
|
||||||
|
if (!claim) {
|
||||||
|
resolveUri(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { lastViewed, selected, onSelect, claim } = this.props;
|
||||||
|
|
||||||
|
let name;
|
||||||
|
let title;
|
||||||
|
let uri;
|
||||||
|
if (claim && claim.value && claim.value.stream) {
|
||||||
|
({ name } = claim);
|
||||||
|
({ title } = claim.value.stream.metadata);
|
||||||
|
uri = claim.permanent_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
onClick={onSelect}
|
||||||
|
className={classnames({
|
||||||
|
history__selected: selected,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
<input checked={selected} type="checkbox" onClick={onSelect} />
|
||||||
|
</td>
|
||||||
|
<td>{moment(lastViewed).from(moment())}</td>
|
||||||
|
<td>{title}</td>
|
||||||
|
<td>
|
||||||
|
<Button
|
||||||
|
tourniquet
|
||||||
|
button="link"
|
||||||
|
label={name ? `lbry://${name}` : `lbry://...`}
|
||||||
|
navigate="/show"
|
||||||
|
navigateParams={{ uri }}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserHistoryItem;
|
|
@ -73,7 +73,11 @@ export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED';
|
||||||
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
|
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
|
||||||
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
|
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
|
||||||
export const PUBLISH_FAILED = 'PUBLISH_FAILED';
|
export const PUBLISH_FAILED = 'PUBLISH_FAILED';
|
||||||
export const SET_PLAYING_URI = 'PLAY_URI';
|
export const SET_PLAYING_URI = 'SET_PLAYING_URI';
|
||||||
|
export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION';
|
||||||
|
export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED';
|
||||||
|
export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI';
|
||||||
|
export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL';
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
|
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
|
||||||
|
@ -181,14 +185,6 @@ export const FETCH_SUBSCRIPTIONS_START = 'FETCH_SUBSCRIPTIONS_START';
|
||||||
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
||||||
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
||||||
|
|
||||||
// Video controls
|
|
||||||
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
|
||||||
|
|
||||||
// Media controls
|
|
||||||
export const MEDIA_PLAY = 'MEDIA_PLAY';
|
|
||||||
export const MEDIA_PAUSE = 'MEDIA_PAUSE';
|
|
||||||
export const MEDIA_POSITION = 'MEDIA_POSITION';
|
|
||||||
|
|
||||||
// Publishing
|
// Publishing
|
||||||
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
||||||
export const UPDATE_PUBLISH_FORM = 'UPDATE_PUBLISH_FORM';
|
export const UPDATE_PUBLISH_FORM = 'UPDATE_PUBLISH_FORM';
|
||||||
|
|
1
src/renderer/constants/content.js
Normal file
1
src/renderer/constants/content.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const HISTORY_ITEMS_PER_PAGE = 50;
|
|
@ -4,6 +4,7 @@ import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
|
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
|
||||||
import { doCheckSubscription } from 'redux/actions/subscriptions';
|
import { doCheckSubscription } from 'redux/actions/subscriptions';
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
|
import { doSetContentHistoryItem } from 'redux/actions/content';
|
||||||
import {
|
import {
|
||||||
doFetchFileInfo,
|
doFetchFileInfo,
|
||||||
doFetchCostInfoForUri,
|
doFetchCostInfoForUri,
|
||||||
|
@ -17,7 +18,6 @@ import {
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
|
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
import { selectMediaPaused } from 'redux/selectors/media';
|
|
||||||
import { doPrepareEdit } from 'redux/actions/publish';
|
import { doPrepareEdit } from 'redux/actions/publish';
|
||||||
import FilePage from './view';
|
import FilePage from './view';
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ const select = (state, props) => ({
|
||||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
||||||
subscriptions: selectSubscriptions(state),
|
subscriptions: selectSubscriptions(state),
|
||||||
playingUri: selectPlayingUri(state),
|
playingUri: selectPlayingUri(state),
|
||||||
isPaused: selectMediaPaused(state),
|
|
||||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
});
|
});
|
||||||
|
@ -44,6 +43,10 @@ const perform = dispatch => ({
|
||||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||||
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
|
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
|
setViewed: uri => dispatch(doSetContentHistoryItem(uri)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(FilePage);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(FilePage);
|
||||||
|
|
|
@ -46,8 +46,7 @@ type Props = {
|
||||||
prepareEdit: ({}, string) => void,
|
prepareEdit: ({}, string) => void,
|
||||||
checkSubscription: (uri: string) => void,
|
checkSubscription: (uri: string) => void,
|
||||||
subscriptions: Array<Subscription>,
|
subscriptions: Array<Subscription>,
|
||||||
setClientSetting: (string, boolean | string) => void,
|
setViewed: string => void,
|
||||||
autoplay: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilePage extends React.Component<Props> {
|
class FilePage extends React.Component<Props> {
|
||||||
|
@ -71,7 +70,7 @@ class FilePage extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { uri, fileInfo, fetchFileInfo, fetchCostInfo } = this.props;
|
const { uri, fileInfo, fetchFileInfo, fetchCostInfo, setViewed } = this.props;
|
||||||
|
|
||||||
if (fileInfo === undefined) {
|
if (fileInfo === undefined) {
|
||||||
fetchFileInfo(uri);
|
fetchFileInfo(uri);
|
||||||
|
@ -81,13 +80,19 @@ class FilePage extends React.Component<Props> {
|
||||||
fetchCostInfo(uri);
|
fetchCostInfo(uri);
|
||||||
|
|
||||||
this.checkSubscription(this.props);
|
this.checkSubscription(this.props);
|
||||||
|
|
||||||
|
setViewed(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps: Props) {
|
componentWillReceiveProps(nextProps: Props) {
|
||||||
const { fetchFileInfo, uri } = this.props;
|
const { fetchFileInfo, uri, setViewed } = this.props;
|
||||||
if (nextProps.fileInfo === undefined) {
|
if (nextProps.fileInfo === undefined) {
|
||||||
fetchFileInfo(uri);
|
fetchFileInfo(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uri !== nextProps.uri) {
|
||||||
|
setViewed(nextProps.uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onAutoplayChange(event: SyntheticInputEvent<*>) {
|
onAutoplayChange(event: SyntheticInputEvent<*>) {
|
||||||
|
@ -129,7 +134,7 @@ class FilePage extends React.Component<Props> {
|
||||||
const { title, thumbnail } = metadata;
|
const { title, thumbnail } = metadata;
|
||||||
const { height, channel_name: channelName, value } = claim;
|
const { height, channel_name: channelName, value } = claim;
|
||||||
const { PLAYABLE_MEDIA_TYPES, PREVIEW_MEDIA_TYPES } = FilePage;
|
const { PLAYABLE_MEDIA_TYPES, PREVIEW_MEDIA_TYPES } = FilePage;
|
||||||
const isRewardContent = rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent = (rewardedContentClaimIds || []).includes(claim.claim_id);
|
||||||
const shouldObscureThumbnail = obscureNsfw && metadata.nsfw;
|
const shouldObscureThumbnail = obscureNsfw && metadata.nsfw;
|
||||||
const fileName = fileInfo ? fileInfo.file_name : null;
|
const fileName = fileInfo ? fileInfo.file_name : null;
|
||||||
const mediaType = getMediaType(contentType, fileName);
|
const mediaType = getMediaType(contentType, fileName);
|
||||||
|
|
4
src/renderer/page/userHistory/index.js
Normal file
4
src/renderer/page/userHistory/index.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import UserHistoryPage from './view';
|
||||||
|
|
||||||
|
export default connect(null, null)(UserHistoryPage);
|
15
src/renderer/page/userHistory/view.jsx
Normal file
15
src/renderer/page/userHistory/view.jsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import Page from 'component/page';
|
||||||
|
import UserHistory from 'component/userHistory';
|
||||||
|
|
||||||
|
class UserHistoryPage extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<UserHistory />
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default UserHistoryPage;
|
|
@ -16,7 +16,7 @@ import Native from 'native';
|
||||||
import { doFetchRewardedContent } from 'redux/actions/content';
|
import { doFetchRewardedContent } from 'redux/actions/content';
|
||||||
import { doFetchDaemonSettings } from 'redux/actions/settings';
|
import { doFetchDaemonSettings } from 'redux/actions/settings';
|
||||||
import { doAuthNavigate } from 'redux/actions/navigation';
|
import { doAuthNavigate } from 'redux/actions/navigation';
|
||||||
import { doPause } from 'redux/actions/media';
|
import { doAuthenticate } from 'redux/actions/user';
|
||||||
import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions';
|
import { doCheckSubscriptionsInit } from 'redux/actions/subscriptions';
|
||||||
import {
|
import {
|
||||||
selectIsUpgradeSkipped,
|
selectIsUpgradeSkipped,
|
||||||
|
@ -28,7 +28,6 @@ import {
|
||||||
selectRemoteVersion,
|
selectRemoteVersion,
|
||||||
selectUpgradeTimer,
|
selectUpgradeTimer,
|
||||||
} from 'redux/selectors/app';
|
} from 'redux/selectors/app';
|
||||||
import { doAuthenticate } from 'redux/actions/user';
|
|
||||||
import { lbrySettings as config } from 'package.json';
|
import { lbrySettings as config } from 'package.json';
|
||||||
|
|
||||||
const { autoUpdater } = remote.require('electron-updater');
|
const { autoUpdater } = remote.require('electron-updater');
|
||||||
|
@ -109,9 +108,6 @@ export function doDownloadUpgradeRequested() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
// Pause video if needed
|
|
||||||
dispatch(doPause());
|
|
||||||
|
|
||||||
const autoUpdateDeclined = selectAutoUpdateDeclined(state);
|
const autoUpdateDeclined = selectAutoUpdateDeclined(state);
|
||||||
|
|
||||||
if (['win32', 'darwin'].includes(process.platform)) {
|
if (['win32', 'darwin'].includes(process.platform)) {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// @flow
|
||||||
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
import * as NOTIFICATION_TYPES from 'constants/notification_types';
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
|
@ -494,3 +495,45 @@ export function doPublish(params) {
|
||||||
Lbry.publishDeprecated(params, null, success, failure);
|
Lbry.publishDeprecated(params, null, success, failure);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function savePosition(claimId: string, outpoint: string, position: number) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.SET_CONTENT_POSITION,
|
||||||
|
data: { claimId, outpoint, position },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doSetContentHistoryItem(uri: string) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.SET_CONTENT_LAST_VIEWED,
|
||||||
|
data: { uri, lastViewed: Date.now() },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doClearContentHistoryUri(uri: string) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.CLEAR_CONTENT_HISTORY_URI,
|
||||||
|
data: { uri },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doClearContentHistoryAll() {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({ type: ACTIONS.CLEAR_CONTENT_HISTORY_ALL });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doSetHistoryPage(page) {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.SET_CONTENT_HISTORY_PAGE,
|
||||||
|
data: { page },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as actions from 'constants/action_types';
|
|
||||||
import type { Dispatch } from 'redux/reducers/media';
|
|
||||||
|
|
||||||
export const doPlay = () => (dispatch: Dispatch) =>
|
|
||||||
dispatch({
|
|
||||||
type: actions.MEDIA_PLAY,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const doPause = () => (dispatch: Dispatch) =>
|
|
||||||
dispatch({
|
|
||||||
type: actions.MEDIA_PAUSE,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function savePosition(claimId: String, position: Number) {
|
|
||||||
return function(dispatch: Dispatch, getState: Function) {
|
|
||||||
const state = getState();
|
|
||||||
const claim = state.claims.byId[claimId];
|
|
||||||
const outpoint = `${claim.txid}:${claim.nout}`;
|
|
||||||
dispatch({
|
|
||||||
type: actions.MEDIA_POSITION,
|
|
||||||
data: {
|
|
||||||
outpoint,
|
|
||||||
position,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -3,9 +3,10 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
playingUri: null,
|
playingUri: null,
|
||||||
currentlyIsPlaying: false,
|
|
||||||
rewardedContentClaimIds: [],
|
rewardedContentClaimIds: [],
|
||||||
channelClaimCounts: {},
|
channelClaimCounts: {},
|
||||||
|
positions: {},
|
||||||
|
history: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[ACTIONS.FETCH_FEATURED_CONTENT_STARTED] = state =>
|
reducers[ACTIONS.FETCH_FEATURED_CONTENT_STARTED] = state =>
|
||||||
|
@ -80,6 +81,46 @@ reducers[ACTIONS.FETCH_CHANNEL_CLAIM_COUNT_COMPLETED] = (state, action) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
reducers[ACTIONS.SET_CONTENT_POSITION] = (state, action) => {
|
||||||
|
const { claimId, outpoint, position } = action.data;
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
positions: {
|
||||||
|
...state.positions,
|
||||||
|
[claimId]: {
|
||||||
|
...state.positions[claimId],
|
||||||
|
[outpoint]: position,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
reducers[ACTIONS.SET_CONTENT_LAST_VIEWED] = (state, action) => {
|
||||||
|
const { uri, lastViewed } = action.data;
|
||||||
|
const { history } = state;
|
||||||
|
const historyObj = { uri, lastViewed };
|
||||||
|
const index = history.findIndex(i => i.uri === uri);
|
||||||
|
const newHistory =
|
||||||
|
index === -1
|
||||||
|
? [historyObj].concat(history)
|
||||||
|
: [historyObj].concat(history.slice(0, index), history.slice(index + 1));
|
||||||
|
return { ...state, history: [...newHistory] };
|
||||||
|
};
|
||||||
|
|
||||||
|
reducers[ACTIONS.CLEAR_CONTENT_HISTORY_URI] = (state, action) => {
|
||||||
|
const { uri } = action.data;
|
||||||
|
const { history } = state;
|
||||||
|
const index = history.findIndex(i => i.uri === uri);
|
||||||
|
return index === -1
|
||||||
|
? state
|
||||||
|
: {
|
||||||
|
...state,
|
||||||
|
history: history.slice(0, index).concat(history.slice(index + 1)),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
reducers[ACTIONS.CLEAR_CONTENT_HISTORY_ALL] = state => ({ ...state, history: [] });
|
||||||
|
|
||||||
export default function reducer(state = defaultState, action) {
|
export default function reducer(state = defaultState, action) {
|
||||||
const handler = reducers[action.type];
|
const handler = reducers[action.type];
|
||||||
if (handler) return handler(state, action);
|
if (handler) return handler(state, action);
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// @flow
|
|
||||||
import * as actions from 'constants/action_types';
|
|
||||||
import { handleActions } from 'util/redux-utils';
|
|
||||||
|
|
||||||
export type MediaState = {
|
|
||||||
paused: Boolean,
|
|
||||||
positions: {
|
|
||||||
[string]: number,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Action = any;
|
|
||||||
export type Dispatch = (action: Action) => any;
|
|
||||||
|
|
||||||
const defaultState = { paused: true, positions: {} };
|
|
||||||
|
|
||||||
export default handleActions(
|
|
||||||
{
|
|
||||||
[actions.MEDIA_PLAY]: (state: MediaState, action: Action) => ({
|
|
||||||
...state,
|
|
||||||
paused: false,
|
|
||||||
}),
|
|
||||||
|
|
||||||
[actions.MEDIA_PAUSE]: (state: MediaState, action: Action) => ({
|
|
||||||
...state,
|
|
||||||
paused: true,
|
|
||||||
}),
|
|
||||||
|
|
||||||
[actions.MEDIA_POSITION]: (state: MediaState, action: Action) => {
|
|
||||||
const { outpoint, position } = action.data;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
positions: {
|
|
||||||
...state.positions,
|
|
||||||
[outpoint]: position,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultState
|
|
||||||
);
|
|
|
@ -3,7 +3,7 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
const getCurrentPath = () => {
|
const getCurrentPath = () => {
|
||||||
const { hash } = document.location;
|
const { hash } = document.location;
|
||||||
if (hash !== '') return hash.replace(/^#/, '');
|
if (hash !== '') return hash.replace(/^#/, '');
|
||||||
return '/discover';
|
return '/user_history';
|
||||||
};
|
};
|
||||||
|
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
import { selectCurrentPage, selectHistoryStack } from 'lbry-redux';
|
||||||
|
|
||||||
export const selectState = state => state.app || {};
|
export const selectState = state => state.app || {};
|
||||||
|
|
||||||
|
@ -86,3 +87,162 @@ export const selectCurrentLanguage = createSelector(
|
||||||
export const selectVolume = createSelector(selectState, state => state.volume);
|
export const selectVolume = createSelector(selectState, state => state.volume);
|
||||||
|
|
||||||
export const selectUpgradeTimer = createSelector(selectState, state => state.checkUpgradeTimer);
|
export const selectUpgradeTimer = createSelector(selectState, state => state.checkUpgradeTimer);
|
||||||
|
|
||||||
|
export const selectNavLinks = createSelector(
|
||||||
|
selectCurrentPage,
|
||||||
|
selectHistoryStack,
|
||||||
|
(currentPage, historyStack) => {
|
||||||
|
const isWalletPage = page =>
|
||||||
|
page === 'wallet' ||
|
||||||
|
page === 'send' ||
|
||||||
|
page === 'getcredits' ||
|
||||||
|
page === 'rewards' ||
|
||||||
|
page === 'history' ||
|
||||||
|
page === 'invite' ||
|
||||||
|
page === 'backup';
|
||||||
|
|
||||||
|
const isMyLbryPage = page =>
|
||||||
|
page === 'downloaded' || page === 'published' || page === 'user_history';
|
||||||
|
|
||||||
|
const previousStack = historyStack.slice().reverse();
|
||||||
|
|
||||||
|
const getPreviousSubLinkPath = checkIfValidPage => {
|
||||||
|
for (let i = 0; i < previousStack.length; i += 1) {
|
||||||
|
const currentStackItem = previousStack[i];
|
||||||
|
|
||||||
|
// Trim off the "/" from the path
|
||||||
|
const pageInStack = currentStackItem.path.slice(1);
|
||||||
|
if (checkIfValidPage(pageInStack)) {
|
||||||
|
return currentStackItem.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gets the last active sublink in a section
|
||||||
|
const getActiveSublink = category => {
|
||||||
|
if (category === 'wallet') {
|
||||||
|
const previousPath = getPreviousSubLinkPath(isWalletPage);
|
||||||
|
return previousPath || '/wallet';
|
||||||
|
} else if (category === 'myLbry') {
|
||||||
|
const previousPath = getPreviousSubLinkPath(isMyLbryPage);
|
||||||
|
return previousPath || '/downloaded';
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isCurrentlyWalletPage = isWalletPage(currentPage);
|
||||||
|
const isCurrentlyMyLbryPage = isMyLbryPage(currentPage);
|
||||||
|
|
||||||
|
const walletSubLinks = [
|
||||||
|
{
|
||||||
|
label: 'Overview',
|
||||||
|
path: '/wallet',
|
||||||
|
active: currentPage === 'wallet',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Send & Receive',
|
||||||
|
path: '/send',
|
||||||
|
active: currentPage === 'send',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Transactions',
|
||||||
|
path: '/history',
|
||||||
|
active: currentPage === 'history',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Get Credits',
|
||||||
|
path: '/getcredits',
|
||||||
|
active: currentPage === 'getcredits',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Rewards',
|
||||||
|
path: '/rewards',
|
||||||
|
active: currentPage === 'rewards',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Invites',
|
||||||
|
path: '/invite',
|
||||||
|
active: currentPage === 'invite',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Backup',
|
||||||
|
path: '/backup',
|
||||||
|
active: currentPage === 'backup',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const myLbrySubLinks = [
|
||||||
|
{
|
||||||
|
label: 'Downloads',
|
||||||
|
path: '/downloaded',
|
||||||
|
active: currentPage === 'downloaded',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Publishes',
|
||||||
|
path: '/published',
|
||||||
|
active: currentPage === 'published',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'History',
|
||||||
|
path: '/user_history',
|
||||||
|
active: currentPage === 'user_history',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const navLinks = {
|
||||||
|
primary: [
|
||||||
|
{
|
||||||
|
label: 'Explore',
|
||||||
|
path: '/discover',
|
||||||
|
active: currentPage === 'discover',
|
||||||
|
icon: 'Compass',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Subscriptions',
|
||||||
|
path: '/subscriptions',
|
||||||
|
active: currentPage === 'subscriptions',
|
||||||
|
icon: 'AtSign',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
label: 'Wallet',
|
||||||
|
icon: 'CreditCard',
|
||||||
|
subLinks: walletSubLinks,
|
||||||
|
path: isCurrentlyWalletPage ? '/wallet' : getActiveSublink('wallet'),
|
||||||
|
active: isWalletPage(currentPage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'My LBRY',
|
||||||
|
icon: 'Folder',
|
||||||
|
subLinks: myLbrySubLinks,
|
||||||
|
path: isCurrentlyMyLbryPage ? '/downloaded' : getActiveSublink('myLbry'),
|
||||||
|
active: isMyLbryPage(currentPage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Publish',
|
||||||
|
icon: 'UploadCloud',
|
||||||
|
path: '/publish',
|
||||||
|
active: currentPage === 'publish',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Settings',
|
||||||
|
icon: 'Settings',
|
||||||
|
path: '/settings',
|
||||||
|
active: currentPage === 'settings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Help',
|
||||||
|
path: '/help',
|
||||||
|
icon: 'HelpCircle',
|
||||||
|
active: currentPage === 'help',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
return navLinks;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
import { makeSelectClaimForUri, selectClaimsByUri } from 'lbry-redux';
|
||||||
|
import { HISTORY_ITEMS_PER_PAGE } from 'constants/content';
|
||||||
|
|
||||||
export const selectState = state => state.content || {};
|
export const selectState = state => state.content || {};
|
||||||
|
|
||||||
|
@ -29,3 +31,40 @@ export const selectRewardContentClaimIds = createSelector(
|
||||||
selectState,
|
selectState,
|
||||||
state => state.rewardedContentClaimIds
|
state => state.rewardedContentClaimIds
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const makeSelectContentPositionForUri = uri =>
|
||||||
|
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
|
||||||
|
if (!claim) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const outpoint = `${claim.txid}:${claim.nout}`;
|
||||||
|
const id = claim.claim_id;
|
||||||
|
return state.positions[id] ? state.positions[id][outpoint] : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const selectHistoryPageCount = createSelector(selectState, state =>
|
||||||
|
Math.ceil(state.history.length / HISTORY_ITEMS_PER_PAGE)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const makeSelectHistoryForPage = page =>
|
||||||
|
createSelector(selectState, selectClaimsByUri, (state, claimsByUri) => {
|
||||||
|
const left = page * HISTORY_ITEMS_PER_PAGE;
|
||||||
|
const historyItems = state.history.slice(left, left + HISTORY_ITEMS_PER_PAGE);
|
||||||
|
|
||||||
|
// See if we have the claim info for the uris in your history
|
||||||
|
// If not, it will need to be fetched in the component
|
||||||
|
return historyItems.map((historyItem) => {
|
||||||
|
const { uri, lastViewed } = historyItem;
|
||||||
|
const claimAtUri = claimsByUri[uri];
|
||||||
|
|
||||||
|
if (claimAtUri) {
|
||||||
|
return { lastViewed, uri, ...claimAtUri }
|
||||||
|
} else {
|
||||||
|
console.log("jsut returning item")
|
||||||
|
return historyItem;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
export const makeSelectHistoryForUri = uri =>
|
||||||
|
createSelector(selectState, state => state.history.find(i => i.uri === uri));
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import { makeSelectClaimForUri } from 'lbry-redux';
|
|
||||||
|
|
||||||
const selectState = state => state.media || {};
|
|
||||||
|
|
||||||
export const selectMediaPaused = createSelector(selectState, state => state.paused);
|
|
||||||
|
|
||||||
export const makeSelectMediaPositionForUri = uri =>
|
|
||||||
createSelector(selectState, makeSelectClaimForUri(uri), (state, claim) => {
|
|
||||||
const outpoint = `${claim.txid}:${claim.nout}`;
|
|
||||||
return state.positions[outpoint] || null;
|
|
||||||
});
|
|
|
@ -19,6 +19,10 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.form-row--centered {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
&.form-row--stretch {
|
&.form-row--stretch {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,10 +54,10 @@ table.table,
|
||||||
tr {
|
tr {
|
||||||
border-bottom: var(--table-item-border);
|
border-bottom: var(--table-item-border);
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
&:nth-child(even):not(.odd) {
|
&:nth-child(even) {
|
||||||
background-color: var(--table-item-odd);
|
background-color: var(--table-item-odd);
|
||||||
}
|
}
|
||||||
&:nth-child(odd):not(.even) {
|
&:nth-child(odd) {
|
||||||
background-color: var(--table-item-even);
|
background-color: var(--table-item-even);
|
||||||
}
|
}
|
||||||
&.thead {
|
&.thead {
|
||||||
|
@ -107,3 +107,48 @@ table.table--transactions {
|
||||||
width: 15%;
|
width: 15%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.table--history {
|
||||||
|
margin-top: $spacing-vertical * 1/3;
|
||||||
|
|
||||||
|
tbody {
|
||||||
|
tr {
|
||||||
|
&:nth-child(even),
|
||||||
|
&:nth-child(odd) {
|
||||||
|
background-color: var(--table-item-even);
|
||||||
|
|
||||||
|
&.history__selected {
|
||||||
|
color: red;
|
||||||
|
background-color: var(--table-item-odd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
cursor: default;
|
||||||
|
padding: $spacing-vertical * 1/3 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-of-type(1) {
|
||||||
|
width: 7.5%;
|
||||||
|
}
|
||||||
|
td:nth-of-type(2) {
|
||||||
|
width: 17.5%;
|
||||||
|
}
|
||||||
|
td:nth-of-type(3) {
|
||||||
|
width: 40%;
|
||||||
|
max-width: 30vw;
|
||||||
|
padding-right: $spacing-vertical * 2/3;
|
||||||
|
}
|
||||||
|
td:nth-of-type(4) {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-of-type(3),
|
||||||
|
td:nth-of-type(4) {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import settingsReducer from 'redux/reducers/settings';
|
||||||
import userReducer from 'redux/reducers/user';
|
import userReducer from 'redux/reducers/user';
|
||||||
import shapeShiftReducer from 'redux/reducers/shape_shift';
|
import shapeShiftReducer from 'redux/reducers/shape_shift';
|
||||||
import subscriptionsReducer from 'redux/reducers/subscriptions';
|
import subscriptionsReducer from 'redux/reducers/subscriptions';
|
||||||
import mediaReducer from 'redux/reducers/media';
|
|
||||||
import publishReducer from 'redux/reducers/publish';
|
import publishReducer from 'redux/reducers/publish';
|
||||||
import { persistStore, autoRehydrate } from 'redux-persist';
|
import { persistStore, autoRehydrate } from 'redux-persist';
|
||||||
import createCompressor from 'redux-persist-transform-compress';
|
import createCompressor from 'redux-persist-transform-compress';
|
||||||
|
@ -69,7 +68,6 @@ const reducers = combineReducers({
|
||||||
user: userReducer,
|
user: userReducer,
|
||||||
shapeShift: shapeShiftReducer,
|
shapeShift: shapeShiftReducer,
|
||||||
subscriptions: subscriptionsReducer,
|
subscriptions: subscriptionsReducer,
|
||||||
media: mediaReducer,
|
|
||||||
publish: publishReducer,
|
publish: publishReducer,
|
||||||
notifications: notificationsReducer,
|
notifications: notificationsReducer,
|
||||||
blacklist: blacklistReducer,
|
blacklist: blacklistReducer,
|
||||||
|
@ -102,15 +100,16 @@ const store = createStore(
|
||||||
const compressor = createCompressor();
|
const compressor = createCompressor();
|
||||||
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
|
||||||
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
|
||||||
|
const contentFilter = createFilter('content', ['positions', 'history']);
|
||||||
|
|
||||||
// We only need to persist the receiveAddress for the wallet
|
// We only need to persist the receiveAddress for the wallet
|
||||||
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
const walletFilter = createFilter('wallet', ['receiveAddress']);
|
||||||
|
|
||||||
const persistOptions = {
|
const persistOptions = {
|
||||||
whitelist: ['claims', 'subscriptions', 'publish', 'wallet'],
|
whitelist: ['claims', 'subscriptions', 'publish', 'wallet', 'content'],
|
||||||
// Order is important. Needs to be compressed last or other transforms can't
|
// Order is important. Needs to be compressed last or other transforms can't
|
||||||
// read the data
|
// read the data
|
||||||
transforms: [saveClaimsFilter, subscriptionsFilter, walletFilter, compressor],
|
transforms: [saveClaimsFilter, subscriptionsFilter, walletFilter, contentFilter, compressor],
|
||||||
debounce: 10000,
|
debounce: 10000,
|
||||||
storage: localForage,
|
storage: localForage,
|
||||||
};
|
};
|
||||||
|
|
|
@ -5655,9 +5655,9 @@ lazy-val@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc"
|
resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc"
|
||||||
|
|
||||||
lbry-redux@lbryio/lbry-redux#421321a78397251589e5a890f4caa95e79975e2b:
|
lbry-redux@lbryio/lbry-redux#d1cee82af119c0c5f98ec27f94b2e7f61e34b54c:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/421321a78397251589e5a890f4caa95e79975e2b"
|
resolved "https://codeload.github.com/lbryio/lbry-redux/tar.gz/d1cee82af119c0c5f98ec27f94b2e7f61e34b54c"
|
||||||
dependencies:
|
dependencies:
|
||||||
proxy-polyfill "0.1.6"
|
proxy-polyfill "0.1.6"
|
||||||
reselect "^3.0.0"
|
reselect "^3.0.0"
|
||||||
|
|
Loading…
Reference in a new issue