User history #1846

Merged
daovist merged 17 commits from user-history into master 2018-09-07 07:21:38 +02:00
9 changed files with 75 additions and 8 deletions
Showing only changes of commit 5cd7794fa0 - Show all commits

View file

@ -231,7 +231,6 @@ class FileViewer extends React.PureComponent<Props> {
<div className={classnames('video', {}, className)}>
{isPlaying && (
<div className="content__view">
<p>hai</p>
{!isReadyToPlay ? (
<div className={layoverClass} style={layoverStyle}>
<LoadingScreen status={loadStatusMessage} />

View file

@ -73,8 +73,11 @@ export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED';
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
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
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';

View file

@ -0,0 +1 @@
export const HISTORY_ITEMS_PER_PAGE = 30;

View file

@ -4,6 +4,7 @@ import { doNavigate } from 'redux/actions/navigation';
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
import { doCheckSubscription } from 'redux/actions/subscriptions';
import { doSetClientSetting } from 'redux/actions/settings';
import { doSetContentHistoryItem } from 'redux/actions/content';
import {
doFetchFileInfo,
doFetchCostInfoForUri,
@ -42,6 +43,7 @@ const perform = dispatch => ({
openModal: (modal, props) => dispatch(doNotify(modal, props)),
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
setViewed: uri => dispatch(doSetContentHistoryItem(uri)),
});
export default connect(

View file

@ -46,8 +46,7 @@ type Props = {
prepareEdit: ({}, string) => void,
checkSubscription: (uri: string) => void,
subscriptions: Array<Subscription>,
setClientSetting: (string, boolean | string) => void,
autoplay: boolean,
setViewed: string => void,
};
class FilePage extends React.Component<Props> {
@ -71,7 +70,7 @@ class FilePage extends React.Component<Props> {
}
componentDidMount() {
const { uri, fileInfo, fetchFileInfo, fetchCostInfo } = this.props;
const { uri, fileInfo, fetchFileInfo, fetchCostInfo, setViewed } = this.props;
if (fileInfo === undefined) {
fetchFileInfo(uri);
@ -81,6 +80,8 @@ class FilePage extends React.Component<Props> {
fetchCostInfo(uri);
this.checkSubscription(this.props);
setViewed(uri);
}
componentWillReceiveProps(nextProps: Props) {
@ -129,7 +130,7 @@ class FilePage extends React.Component<Props> {
const { title, thumbnail } = metadata;
const { height, channel_name: channelName, value } = claim;
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 fileName = fileInfo ? fileInfo.file_name : null;
const mediaType = getMediaType(contentType, fileName);

View file

@ -504,3 +504,27 @@ export function savePosition(claimId: string, outpoint: string, position: number
});
};
}
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 doSetContentHistoryAll() {
return dispatch => {
dispatch({ type: ACTIONS.CLEAR_CONTENT_HISTORY_ALL });
};
}

View file

@ -6,6 +6,7 @@ const defaultState = {
rewardedContentClaimIds: [],
channelClaimCounts: {},
positions: {},
history: [],
};
reducers[ACTIONS.FETCH_FEATURED_CONTENT_STARTED] = state =>
@ -94,6 +95,32 @@ reducers[ACTIONS.SET_CONTENT_POSITION] = (state, action) => {
};
};
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) {
const handler = reducers[action.type];
if (handler) return handler(state, action);

View file

@ -1,5 +1,6 @@
import { createSelector } from 'reselect';
import { makeSelectClaimForUri } from 'lbry-redux';
import { HISTORY_ITEMS_PER_PAGE } from 'constants/content';
export const selectState = state => state.content || {};
@ -40,3 +41,11 @@ export const makeSelectContentPositionForUri = uri =>
const id = claim.claim_id;
return state.positions[id] ? state.positions[id][outpoint] : null;
});
export const makeSelectHistoryForPage = (page = 1) =>
createSelector(selectState, state =>
state.history.slice((page - 1) * HISTORY_ITEMS_PER_PAGE, HISTORY_ITEMS_PER_PAGE)
);
export const makeSelectHistoryForUri = uri =>
createSelector(selectState, state => state.history.find(i => i.uri === uri));

View file

@ -100,15 +100,16 @@ const store = createStore(
const compressor = createCompressor();
const saveClaimsFilter = createFilter('claims', ['byId', 'claimsByUri']);
const subscriptionsFilter = createFilter('subscriptions', ['subscriptions']);
const contentFilter = createFilter('content', ['positions', 'history']);
// We only need to persist the receiveAddress for the wallet
const walletFilter = createFilter('wallet', ['receiveAddress']);
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
// read the data
transforms: [saveClaimsFilter, subscriptionsFilter, walletFilter, compressor],
transforms: [saveClaimsFilter, subscriptionsFilter, walletFilter, contentFilter, compressor],
debounce: 10000,
storage: localForage,
};