diff --git a/src/renderer/component/fileViewer/view.jsx b/src/renderer/component/fileViewer/view.jsx index 1e226ef5e..2062fd7df 100644 --- a/src/renderer/component/fileViewer/view.jsx +++ b/src/renderer/component/fileViewer/view.jsx @@ -231,7 +231,6 @@ class FileViewer extends React.PureComponent {
{isPlaying && (
-

hai

{!isReadyToPlay ? (
diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js index 7cace66ca..d97032bc6 100644 --- a/src/renderer/constants/action_types.js +++ b/src/renderer/constants/action_types.js @@ -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'; diff --git a/src/renderer/constants/content.js b/src/renderer/constants/content.js new file mode 100644 index 000000000..31a776af2 --- /dev/null +++ b/src/renderer/constants/content.js @@ -0,0 +1 @@ +export const HISTORY_ITEMS_PER_PAGE = 30; diff --git a/src/renderer/page/file/index.js b/src/renderer/page/file/index.js index 9799fa4b5..1870c9f9f 100644 --- a/src/renderer/page/file/index.js +++ b/src/renderer/page/file/index.js @@ -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( diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx index da35a01d1..ad3a133e7 100644 --- a/src/renderer/page/file/view.jsx +++ b/src/renderer/page/file/view.jsx @@ -46,8 +46,7 @@ type Props = { prepareEdit: ({}, string) => void, checkSubscription: (uri: string) => void, subscriptions: Array, - setClientSetting: (string, boolean | string) => void, - autoplay: boolean, + setViewed: string => void, }; class FilePage extends React.Component { @@ -71,7 +70,7 @@ class FilePage extends React.Component { } 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 { fetchCostInfo(uri); this.checkSubscription(this.props); + + setViewed(uri); } componentWillReceiveProps(nextProps: Props) { @@ -129,7 +130,7 @@ class FilePage extends React.Component { 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); diff --git a/src/renderer/redux/actions/content.js b/src/renderer/redux/actions/content.js index 2fd51a748..e9d98817f 100644 --- a/src/renderer/redux/actions/content.js +++ b/src/renderer/redux/actions/content.js @@ -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 }); + }; +} diff --git a/src/renderer/redux/reducers/content.js b/src/renderer/redux/reducers/content.js index 3a760515a..0b96be940 100644 --- a/src/renderer/redux/reducers/content.js +++ b/src/renderer/redux/reducers/content.js @@ -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); diff --git a/src/renderer/redux/selectors/content.js b/src/renderer/redux/selectors/content.js index 0811f8e42..0f77fc811 100644 --- a/src/renderer/redux/selectors/content.js +++ b/src/renderer/redux/selectors/content.js @@ -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)); diff --git a/src/renderer/store.js b/src/renderer/store.js index ba2f25b86..37cbd6cf0 100644 --- a/src/renderer/store.js +++ b/src/renderer/store.js @@ -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, };