From b2196be4ff450db74af56ace15f17f199b714356 Mon Sep 17 00:00:00 2001 From: saltrafael Date: Tue, 7 Sep 2021 07:52:27 -0300 Subject: [PATCH 1/4] Add snack bar notification --- ui/redux/actions/content.js | 18 +++++++++--------- ui/redux/actions/settings.js | 6 ++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ui/redux/actions/content.js b/ui/redux/actions/content.js index 302632b8e..596cf6152 100644 --- a/ui/redux/actions/content.js +++ b/ui/redux/actions/content.js @@ -290,10 +290,10 @@ export function doToggleLoopList(collectionId: string, loop: boolean, hideToast: type: ACTIONS.TOGGLE_LOOP_LIST, data: { collectionId, loop }, }); - if (loop && !hideToast) { + if (!hideToast) { dispatch( doToast({ - message: __('Loop is on.'), + message: loop ? __('Loop is on.') : __('Loop is off.'), }) ); } @@ -323,18 +323,18 @@ export function doToggleShuffleList(currentUri: string, collectionId: string, sh type: ACTIONS.TOGGLE_SHUFFLE_LIST, data: { collectionId, newUrls }, }); - if (!hideToast) { - dispatch( - doToast({ - message: __('Shuffle is on.'), - }) - ); - } } else { dispatch({ type: ACTIONS.TOGGLE_SHUFFLE_LIST, data: { collectionId, newUrls: false }, }); } + if (!hideToast) { + dispatch( + doToast({ + message: shuffle ? __('Shuffle is on.') : __('Shuffle is off.'), + }) + ); + } }; } diff --git a/ui/redux/actions/settings.js b/ui/redux/actions/settings.js index 6f61e2476..3b327f805 100644 --- a/ui/redux/actions/settings.js +++ b/ui/redux/actions/settings.js @@ -432,5 +432,11 @@ export function toggleAutoplayNext() { const autoplayNext = makeSelectClientSetting(SETTINGS.AUTOPLAY_NEXT)(state); dispatch(doSetClientSetting(SETTINGS.AUTOPLAY_NEXT, !autoplayNext, ready)); + + dispatch( + doToast({ + message: autoplayNext ? __('Autoplay Next is off.') : __('Autoplay Next is on.'), + }) + ); }; } -- 2.45.3 From 1471910ccdfef78473138b3f6d4ddec87a6107f2 Mon Sep 17 00:00:00 2001 From: saltrafael Date: Thu, 9 Sep 2021 09:10:43 -0300 Subject: [PATCH 2/4] Fix and improve code --- ui/component/claimMenuList/index.js | 11 +++--- ui/component/claimMenuList/view.jsx | 24 +++++++----- ui/component/claimPreviewTile/view.jsx | 12 ++---- ui/component/collectionActions/index.js | 20 +++------- ui/component/collectionActions/view.jsx | 36 ++++++------------ ui/component/collectionMenuList/index.js | 20 +++++----- ui/component/collectionMenuList/view.jsx | 31 ++++++--------- ui/component/collectionPreviewTile/view.jsx | 13 ++----- ui/component/fileRenderFloating/view.jsx | 42 ++++++++------------- ui/component/fileRenderInitiator/view.jsx | 23 +++++------ ui/component/viewers/videoViewer/index.js | 17 +++++++-- ui/component/viewers/videoViewer/view.jsx | 33 +++++++--------- ui/util/url.js | 6 +++ 13 files changed, 127 insertions(+), 161 deletions(-) diff --git a/ui/component/claimMenuList/index.js b/ui/component/claimMenuList/index.js index 0846349cf..87791afd3 100644 --- a/ui/component/claimMenuList/index.js +++ b/ui/component/claimMenuList/index.js @@ -31,14 +31,13 @@ import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscrip import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectListShuffle } from 'redux/selectors/content'; -import { doSetPlayingUri, doToggleShuffleList } from 'redux/actions/content'; +import { doToggleLoopList, doToggleShuffleList } from 'redux/actions/content'; import ClaimPreview from './view'; import fs from 'fs'; const select = (state, props) => { const claim = makeSelectClaimForUri(props.uri, false)(state); const collectionId = props.collectionId; - const resolvedList = makeSelectUrlsForCollectionId(collectionId)(state); const repostedClaim = claim && claim.reposted_claim; const contentClaim = repostedClaim || claim; const contentSigningChannel = contentClaim && contentClaim.signing_channel; @@ -73,7 +72,7 @@ const select = (state, props) => { isMyCollection: makeSelectCollectionIsMine(collectionId)(state), editedCollection: makeSelectEditedCollectionForId(collectionId)(state), isAuthenticated: Boolean(selectUserVerifiedEmail(state)), - resolvedList, + resolvedList: makeSelectUrlsForCollectionId(collectionId)(state), playNextUri, }; }; @@ -102,8 +101,10 @@ const perform = (dispatch) => ({ doChannelUnsubscribe: (subscription) => dispatch(doChannelUnsubscribe(subscription)), doCollectionEdit: (collection, props) => dispatch(doCollectionEdit(collection, props)), fetchCollectionItems: (collectionId) => dispatch(doFetchItemsInCollection({ collectionId })), - doSetPlayingUri: (uri) => dispatch(doSetPlayingUri({ uri })), - doToggleShuffleList: (collectionId) => dispatch(doToggleShuffleList(undefined, collectionId, true, true)), + doToggleShuffleList: (collectionId) => { + dispatch(doToggleLoopList(collectionId, false, true)); + dispatch(doToggleShuffleList(undefined, collectionId, true, true)); + }, }); export default connect(select, perform)(ClaimPreview); diff --git a/ui/component/claimMenuList/view.jsx b/ui/component/claimMenuList/view.jsx index cde179ece..5ba50542e 100644 --- a/ui/component/claimMenuList/view.jsx +++ b/ui/component/claimMenuList/view.jsx @@ -7,7 +7,13 @@ import React from 'react'; import classnames from 'classnames'; import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button'; import Icon from 'component/common/icon'; -import { generateShareUrl, generateRssUrl, generateLbryContentUrl, formatLbryUrlForWeb } from 'util/url'; +import { + generateShareUrl, + generateRssUrl, + generateLbryContentUrl, + formatLbryUrlForWeb, + generateListSearchUrlParams, +} from 'util/url'; import { useHistory } from 'react-router'; import { buildURI, parseURI, COLLECTIONS_CONSTS } from 'lbry-redux'; @@ -59,7 +65,6 @@ type Props = { playNextUri: string, resolvedList: boolean, fetchCollectionItems: (string) => void, - doSetPlayingUri: (string) => void, doToggleShuffleList: (string) => void, }; @@ -101,7 +106,6 @@ function ClaimMenuList(props: Props) { playNextUri, resolvedList, fetchCollectionItems, - doSetPlayingUri, doToggleShuffleList, } = props; const [doShuffle, setDoShuffle] = React.useState(false); @@ -129,15 +133,15 @@ function ClaimMenuList(props: Props) { if (doShuffle && resolvedList) { doToggleShuffleList(collectionId); if (playNextUri) { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); - const navigateUrl = formatLbryUrlForWeb(playNextUri) + `?` + collectionParams.toString(); - setDoShuffle(false); - doSetPlayingUri(playNextUri); - push(navigateUrl); + const navigateUrl = formatLbryUrlForWeb(playNextUri); + push({ + pathname: navigateUrl, + search: generateListSearchUrlParams(collectionId), + state: { collectionId, forceAutoplay: true }, + }); } } - }, [collectionId, doSetPlayingUri, doShuffle, doToggleShuffleList, playNextUri, push, resolvedList]); + }, [collectionId, doShuffle, doToggleShuffleList, playNextUri, push, resolvedList]); if (!claim) { return null; diff --git a/ui/component/claimPreviewTile/view.jsx b/ui/component/claimPreviewTile/view.jsx index 21a88e6bc..871a9ef32 100644 --- a/ui/component/claimPreviewTile/view.jsx +++ b/ui/component/claimPreviewTile/view.jsx @@ -10,9 +10,9 @@ import ChannelThumbnail from 'component/channelThumbnail'; import FileViewCountInline from 'component/fileViewCountInline'; import SubscribeButton from 'component/subscribeButton'; import useGetThumbnail from 'effects/use-get-thumbnail'; -import { formatLbryUrlForWeb } from 'util/url'; +import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; import { formatClaimPreviewTitle } from 'util/formatAriaLabel'; -import { parseURI, COLLECTIONS_CONSTS, isURIEqual } from 'lbry-redux'; +import { parseURI, isURIEqual } from 'lbry-redux'; import PreviewOverlayProperties from 'component/previewOverlayProperties'; import FileDownloadLink from 'component/fileDownloadLink'; import FileWatchLaterLink from 'component/fileWatchLaterLink'; @@ -98,13 +98,9 @@ function ClaimPreviewTile(props: Props) { const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder) || thumbnail; const canonicalUrl = claim && claim.canonical_url; const permanentUrl = claim && claim.permanent_url; - let navigateUrl = formatLbryUrlForWeb(canonicalUrl || uri || '/'); const listId = collectionId || collectionClaimId; - if (listId) { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, listId); - navigateUrl = navigateUrl + `?` + collectionParams.toString(); - } + const navigateUrl = + formatLbryUrlForWeb(canonicalUrl || uri || '/') + (listId ? generateListSearchUrlParams(listId) : ''); const navLinkProps = { to: navigateUrl, onClick: (e) => e.stopPropagation(), diff --git a/ui/component/collectionActions/index.js b/ui/component/collectionActions/index.js index 7d9c09863..3c916441a 100644 --- a/ui/component/collectionActions/index.js +++ b/ui/component/collectionActions/index.js @@ -1,17 +1,13 @@ import { connect } from 'react-redux'; import { - makeSelectClaimIsMine, makeSelectClaimForUri, - selectMyChannelClaims, makeSelectClaimIsPending, makeSelectCollectionIsMine, makeSelectEditedCollectionForId, } from 'lbry-redux'; -import { makeSelectCostInfoForUri } from 'lbryinc'; -import { doToast } from 'redux/actions/notifications'; import { doOpenModal } from 'redux/actions/app'; import { selectListShuffle } from 'redux/selectors/content'; -import { doPlayUri, doSetPlayingUri, doToggleShuffleList, doToggleLoopList } from 'redux/actions/content'; +import { doToggleShuffleList, doToggleLoopList } from 'redux/actions/content'; import CollectionActions from './view'; const select = (state, props) => { @@ -31,29 +27,23 @@ const select = (state, props) => { const shuffleList = selectListShuffle(state); const shuffle = shuffleList && shuffleList.collectionId === collectionId && shuffleList.newUrls; const playNextUri = shuffle && shuffle[0]; - const playNextClaim = makeSelectClaimForUri(playNextUri)(state); return { claim: makeSelectClaimForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - costInfo: makeSelectCostInfoForUri(props.uri)(state), - myChannels: selectMyChannelClaims(state), claimIsPending: makeSelectClaimIsPending(props.uri)(state), isMyCollection: makeSelectCollectionIsMine(collectionId)(state), collectionHasEdits: Boolean(makeSelectEditedCollectionForId(collectionId)(state)), firstItem, playNextUri, - playNextClaim, }; }; const perform = (dispatch) => ({ openModal: (modal, props) => dispatch(doOpenModal(modal, props)), - doToast: (options) => dispatch(doToast(options)), - doPlayUri: (uri) => dispatch(doPlayUri(uri)), - doSetPlayingUri: (uri) => dispatch(doSetPlayingUri({ uri })), - doToggleShuffleList: (collectionId, shuffle) => dispatch(doToggleShuffleList(undefined, collectionId, shuffle, true)), - doToggleLoopList: (collectionId, loop) => dispatch(doToggleLoopList(collectionId, loop)), + doToggleShuffleList: (collectionId, shuffle) => { + dispatch(doToggleLoopList(collectionId, false, true)); + dispatch(doToggleShuffleList(undefined, collectionId, shuffle, true)); + }, }); export default connect(select, perform)(CollectionActions); diff --git a/ui/component/collectionActions/view.jsx b/ui/component/collectionActions/view.jsx index e99cc717b..1186d9dfc 100644 --- a/ui/component/collectionActions/view.jsx +++ b/ui/component/collectionActions/view.jsx @@ -11,15 +11,12 @@ import { useHistory } from 'react-router'; import { EDIT_PAGE, PAGE_VIEW_QUERY } from 'page/collection/view'; import classnames from 'classnames'; import { ENABLE_FILE_REACTIONS } from 'config'; -import { COLLECTIONS_CONSTS } from 'lbry-redux'; -import { formatLbryUrlForWeb } from 'util/url'; +import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; type Props = { uri: string, claim: StreamClaim, - openModal: (id: string, { uri: string, claimIsMine?: boolean, isSupport?: boolean }) => void, - myChannels: ?Array, - doToast: ({ message: string }) => void, + openModal: (id: string, {}) => void, claimIsPending: boolean, isMyCollection: boolean, collectionId: string, @@ -28,11 +25,7 @@ type Props = { collectionHasEdits: boolean, isBuiltin: boolean, doToggleShuffleList: (string, boolean) => void, - doToggleLoopList: (string, boolean) => void, playNextUri: string, - playNextClaim: StreamClaim, - doPlayUri: (string) => void, - doSetPlayingUri: (string) => void, firstItem: string, }; @@ -49,11 +42,7 @@ function CollectionActions(props: Props) { collectionHasEdits, isBuiltin, doToggleShuffleList, - doToggleLoopList, playNextUri, - playNextClaim, - doPlayUri, - doSetPlayingUri, firstItem, } = props; const [doShuffle, setDoShuffle] = React.useState(false); @@ -63,23 +52,23 @@ function CollectionActions(props: Props) { const webShareable = true; // collections have cost? const doPlay = React.useCallback( - (uri) => { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); - const navigateUrl = formatLbryUrlForWeb(uri) + `?` + collectionParams.toString(); - push(navigateUrl); - doSetPlayingUri(uri); - doPlayUri(uri); + (playUri) => { + const navigateUrl = formatLbryUrlForWeb(playUri); + push({ + pathname: navigateUrl, + search: generateListSearchUrlParams(collectionId), + state: { forceAutoplay: true }, + }); }, - [collectionId, push, doSetPlayingUri, doPlayUri] + [collectionId, push] ); React.useEffect(() => { - if (playNextClaim && doShuffle) { + if (playNextUri && doShuffle) { setDoShuffle(false); doPlay(playNextUri); } - }, [doPlay, doShuffle, playNextClaim, playNextUri]); + }, [doPlay, doShuffle, playNextUri]); const lhsSection = ( <> @@ -90,7 +79,6 @@ function CollectionActions(props: Props) { title={__('Play')} onClick={() => { doToggleShuffleList(collectionId, false); - doToggleLoopList(collectionId, false); doPlay(firstItem); }} /> diff --git a/ui/component/collectionMenuList/index.js b/ui/component/collectionMenuList/index.js index e96768e36..dc687b444 100644 --- a/ui/component/collectionMenuList/index.js +++ b/ui/component/collectionMenuList/index.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux'; -import { doCollectionEdit, makeSelectNameForCollectionId, doCollectionDelete } from 'lbry-redux'; +import { makeSelectNameForCollectionId } from 'lbry-redux'; import { doOpenModal } from 'redux/actions/app'; import { selectListShuffle } from 'redux/selectors/content'; -import { doSetPlayingUri, doToggleShuffleList } from 'redux/actions/content'; +import { doToggleLoopList, doToggleShuffleList } from 'redux/actions/content'; import CollectionMenuList from './view'; const select = (state, props) => { @@ -17,10 +17,12 @@ const select = (state, props) => { }; }; -export default connect(select, { - doCollectionEdit, - doOpenModal, - doCollectionDelete, - doSetPlayingUri, - doToggleShuffleList, -})(CollectionMenuList); +const perform = (dispatch) => ({ + openModal: (modal, props) => dispatch(doOpenModal(modal, props)), + doToggleShuffleList: (collectionId) => { + dispatch(doToggleLoopList(collectionId, false, true)); + dispatch(doToggleShuffleList(undefined, collectionId, true, true)); + }, +}); + +export default connect(select, perform)(CollectionMenuList); diff --git a/ui/component/collectionMenuList/view.jsx b/ui/component/collectionMenuList/view.jsx index 17b9c1cca..8607a22dc 100644 --- a/ui/component/collectionMenuList/view.jsx +++ b/ui/component/collectionMenuList/view.jsx @@ -7,8 +7,7 @@ import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button'; import Icon from 'component/common/icon'; import * as PAGES from 'constants/pages'; import { useHistory } from 'react-router'; -import { formatLbryUrlForWeb } from 'util/url'; -import { COLLECTIONS_CONSTS } from 'lbry-redux'; +import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; type Props = { inline?: boolean, @@ -16,34 +15,26 @@ type Props = { collectionName?: string, collectionId: string, playNextUri: string, - doSetPlayingUri: ({ uri: ?string }) => void, - doToggleShuffleList: (string, string, boolean, boolean) => void, + doToggleShuffleList: (string) => void, }; function CollectionMenuList(props: Props) { - const { - inline = false, - collectionId, - collectionName, - doOpenModal, - playNextUri, - doSetPlayingUri, - doToggleShuffleList, - } = props; + const { inline = false, collectionId, collectionName, doOpenModal, playNextUri, doToggleShuffleList } = props; const [doShuffle, setDoShuffle] = React.useState(false); const { push } = useHistory(); React.useEffect(() => { if (playNextUri && doShuffle) { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); - const navigateUrl = formatLbryUrlForWeb(playNextUri) + `?` + collectionParams.toString(); setDoShuffle(false); - doSetPlayingUri({ uri: playNextUri }); - push(navigateUrl); + const navigateUrl = formatLbryUrlForWeb(playNextUri); + push({ + pathname: navigateUrl, + search: generateListSearchUrlParams(collectionId), + state: { forceAutoplay: true }, + }); } - }, [push, doSetPlayingUri, collectionId, playNextUri, doShuffle]); + }, [collectionId, doShuffle, playNextUri, push]); return ( @@ -68,7 +59,7 @@ function CollectionMenuList(props: Props) { { - doToggleShuffleList('', collectionId, true, true); + doToggleShuffleList(collectionId); setDoShuffle(true); }} > diff --git a/ui/component/collectionPreviewTile/view.jsx b/ui/component/collectionPreviewTile/view.jsx index 979175851..33e36f39f 100644 --- a/ui/component/collectionPreviewTile/view.jsx +++ b/ui/component/collectionPreviewTile/view.jsx @@ -7,8 +7,7 @@ import TruncatedText from 'component/common/truncated-text'; import CollectionCount from './collectionCount'; import CollectionPrivate from './collectionPrivate'; import CollectionMenuList from 'component/collectionMenuList'; -import { formatLbryUrlForWeb } from 'util/url'; -import { COLLECTIONS_CONSTS } from 'lbry-redux'; +import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; import FileThumbnail from 'component/fileThumbnail'; type Props = { @@ -62,16 +61,12 @@ function CollectionPreviewTile(props: Props) { if (collectionId && hasClaim && resolveCollectionItems) { resolveCollectionItems({ collectionId, page_size: 5 }); } - }, [collectionId, hasClaim]); + }, [collectionId, hasClaim, resolveCollectionItems]); // const signingChannel = claim && claim.signing_channel; - let navigateUrl = formatLbryUrlForWeb(collectionItemUrls[0] || '/'); - if (collectionId) { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); - navigateUrl = navigateUrl + `?` + collectionParams.toString(); - } + const navigateUrl = + formatLbryUrlForWeb(collectionItemUrls[0] || '/') + (collectionId ? generateListSearchUrlParams(collectionId) : ''); function handleClick(e) { if (navigateUrl) { diff --git a/ui/component/fileRenderFloating/view.jsx b/ui/component/fileRenderFloating/view.jsx index 516a3f694..371afa55d 100644 --- a/ui/component/fileRenderFloating/view.jsx +++ b/ui/component/fileRenderFloating/view.jsx @@ -11,10 +11,11 @@ import usePersistedState from 'effects/use-persisted-state'; import { PRIMARY_PLAYER_WRAPPER_CLASS } from 'page/file/view'; import Draggable from 'react-draggable'; import { onFullscreenChange } from 'util/full-screen'; +import { generateListSearchUrlParams } from 'util/url'; import { useIsMobile } from 'effects/use-screensize'; import debounce from 'util/debounce'; import { useHistory } from 'react-router'; -import { isURIEqual, COLLECTIONS_CONSTS } from 'lbry-redux'; +import { isURIEqual } from 'lbry-redux'; const IS_DESKTOP_MAC = typeof process === 'object' ? process.platform === 'darwin' : false; const DEBOUNCE_WINDOW_RESIZE_HANDLER_MS = 60; @@ -54,9 +55,8 @@ export default function FileRenderFloating(props: Props) { doFetchRecommendedContent, collectionId, } = props; - const { - location: { pathname }, - } = useHistory(); + const { location } = useHistory(); + const hideFloatingPlayer = location.state && location.state.hideFloatingPlayer; const isMobile = useIsMobile(); const mainFilePlaying = playingUri && isURIEqual(playingUri.uri, primaryUri); const [fileViewerRect, setFileViewerRect] = useState(); @@ -71,12 +71,7 @@ export default function FileRenderFloating(props: Props) { y: 0, }); - let navigateUrl; - if (collectionId) { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); - navigateUrl = uri + `?` + collectionParams.toString(); - } + const navigateUrl = uri + (collectionId ? generateListSearchUrlParams(collectionId) : ''); const playingUriSource = playingUri && playingUri.source; const isPlayable = RENDER_MODES.FLOATING_MODES.includes(renderMode); @@ -102,7 +97,7 @@ export default function FileRenderFloating(props: Props) { } } - function clampToScreen(pos) { + const clampToScreen = React.useCallback((pos) => { const ESTIMATED_SCROLL_BAR_PX = 50; const FLOATING_PLAYER_CLASS = 'content__viewer--floating'; const fpPlayerElem = document.querySelector(`.${FLOATING_PLAYER_CLASS}`); @@ -115,7 +110,7 @@ export default function FileRenderFloating(props: Props) { pos.y = getScreenHeight() - fpPlayerElem.getBoundingClientRect().height; } } - } + }, []); // Updated 'relativePos' based on persisted 'position': const stringifiedPosition = JSON.stringify(position); @@ -139,7 +134,7 @@ export default function FileRenderFloating(props: Props) { setPosition({ x: pos.x, y: pos.y }); } } - }, [isFloating, stringifiedPosition]); + }, [clampToScreen, isFloating, position.x, position.y, setPosition, stringifiedPosition]); // Listen to main-window resizing and adjust the fp position accordingly: useEffect(() => { @@ -157,9 +152,9 @@ export default function FileRenderFloating(props: Props) { // 'relativePos' is needed in the dependency list to avoid stale closure. // Otherwise, this could just be changed to a one-time effect. - }, [relativePos]); + }, [clampToScreen, relativePos.x, relativePos.y, setPosition]); - function handleResize() { + const handleResize = React.useCallback(() => { const element = mainFilePlaying ? document.querySelector(`.${PRIMARY_PLAYER_WRAPPER_CLASS}`) : document.querySelector(`.${INLINE_PLAYER_WRAPPER_CLASS}`); @@ -184,13 +179,13 @@ export default function FileRenderFloating(props: Props) { // $FlowFixMe setFileViewerRect({ ...objectRect, windowOffset: window.pageYOffset }); - } + }, [mainFilePlaying]); useEffect(() => { if (streamingUrl) { handleResize(); } - }, [streamingUrl, pathname, playingUriSource, isFloating, mainFilePlaying]); + }, [handleResize, streamingUrl]); useEffect(() => { handleResize(); @@ -201,7 +196,7 @@ export default function FileRenderFloating(props: Props) { window.removeEventListener('resize', handleResize); onFullscreenChange(window, 'remove', handleResize); }; - }, [setFileViewerRect, isFloating, playingUriSource, mainFilePlaying, videoTheaterMode]); + }, [handleResize]); useEffect(() => { // @if TARGET='app' @@ -219,9 +214,9 @@ export default function FileRenderFloating(props: Props) { if (isFloating) { doFetchRecommendedContent(uri, mature); } - }, [uri, mature, isFloating]); + }, [doFetchRecommendedContent, isFloating, mature, uri]); - if (!isPlayable || !uri || (isFloating && (isMobile || !floatingPlayerEnabled))) { + if (!isPlayable || !uri || (isFloating && (isMobile || !floatingPlayerEnabled || hideFloatingPlayer))) { return null; } @@ -312,12 +307,7 @@ export default function FileRenderFloating(props: Props) { {isFloating && (
-
diff --git a/ui/component/fileRenderInitiator/view.jsx b/ui/component/fileRenderInitiator/view.jsx index 48bde1bde..42d8ca639 100644 --- a/ui/component/fileRenderInitiator/view.jsx +++ b/ui/component/fileRenderInitiator/view.jsx @@ -22,7 +22,7 @@ type Props = { fileInfo: FileListItem, uri: string, history: { push: (string) => void }, - location: { search: ?string, pathname: string }, + location: { search: ?string, pathname: string, href: string, state: { forceAutoplay: boolean } }, obscurePreview: boolean, insufficientCredits: boolean, claimThumbnail?: string, @@ -58,14 +58,10 @@ export default function FileRenderInitiator(props: Props) { collectionId, } = props; - // force autoplay if a timestamp is present - let autoplay = props.autoplay; - // get current url - const url = window.location.href; - // check if there is a time parameter, if so force autoplay - if (url.indexOf('t=') > -1) { - autoplay = true; - } + // check if there is a time or autoplay parameter, if so force autoplay + const urlTimeParam = location && location.href && location.href.indexOf('t=') > -1; + const forceAutoplayParam = location && location.state && location.state.forceAutoplay; + const autoplay = forceAutoplayParam || urlTimeParam || props.autoplay; const cost = costInfo && costInfo.cost; const isFree = hasCostInfo && cost === 0; @@ -75,7 +71,7 @@ export default function FileRenderInitiator(props: Props) { const [thumbnail, setThumbnail] = React.useState(FileRenderPlaceholder); const containerRef = React.useRef(); - React.useEffect(() => { + useEffect(() => { if (claimThumbnail) { setTimeout(() => { let newThumbnail = claimThumbnail; @@ -96,7 +92,7 @@ export default function FileRenderInitiator(props: Props) { } }, 200); } - }, [claimThumbnail]); + }, [claimThumbnail, thumbnail]); function doAuthRedirect() { history.push(`/$/${PAGES.AUTH}?redirect=${encodeURIComponent(location.pathname)}`); @@ -138,11 +134,12 @@ export default function FileRenderInitiator(props: Props) { const videoOnPage = document.querySelector('video'); if ( (isFree || claimWasPurchased) && - ((autoplay && !videoOnPage && isPlayable) || RENDER_MODES.AUTO_RENDER_MODES.includes(renderMode)) + ((autoplay && (!videoOnPage || forceAutoplayParam) && isPlayable) || + RENDER_MODES.AUTO_RENDER_MODES.includes(renderMode)) ) { viewFile(); } - }, [autoplay, viewFile, isFree, renderMode, isPlayable, claimWasPurchased]); + }, [autoplay, viewFile, isFree, renderMode, isPlayable, claimWasPurchased, forceAutoplayParam]); /* once content is playing, let the appropriate take care of it... diff --git a/ui/component/viewers/videoViewer/index.js b/ui/component/viewers/videoViewer/index.js index 53900a88f..9bd755fab 100644 --- a/ui/component/viewers/videoViewer/index.js +++ b/ui/component/viewers/videoViewer/index.js @@ -8,7 +8,13 @@ import { makeSelectNextUrlForCollectionAndUrl, makeSelectPreviousUrlForCollectionAndUrl, } from 'lbry-redux'; -import { doChangeVolume, doChangeMute, doAnalyticsView, doAnalyticsBuffer } from 'redux/actions/app'; +import { + doChangeVolume, + doChangeMute, + doAnalyticsView, + doAnalyticsBuffer, + doAnaltyicsPurchaseEvent, +} from 'redux/actions/app'; import { selectVolume, selectMute } from 'redux/selectors/app'; import { savePosition, clearPosition, doPlayUri, doSetPlayingUri } from 'redux/actions/content'; import { @@ -78,8 +84,13 @@ const perform = (dispatch) => ({ toggleVideoTheaterMode: () => dispatch(toggleVideoTheaterMode()), toggleAutoplayNext: () => dispatch(toggleAutoplayNext()), setVideoPlaybackRate: (rate) => dispatch(doSetClientSetting(SETTINGS.VIDEO_PLAYBACK_RATE, rate)), - doPlayUri: (uri) => dispatch(doPlayUri(uri)), - doSetPlayingUri: (uri, collectionId) => dispatch(doSetPlayingUri({ uri, collectionId })), + doPlayUri: (uri, collectionId) => + dispatch( + doPlayUri(uri, false, false, (fileInfo) => { + dispatch(doAnaltyicsPurchaseEvent(fileInfo)); + dispatch(doSetPlayingUri({ uri, collectionId })); + }) + ), }); export default withRouter(connect(select, perform)(VideoViewer)); diff --git a/ui/component/viewers/videoViewer/view.jsx b/ui/component/viewers/videoViewer/view.jsx index 905187ded..16f120b58 100644 --- a/ui/component/viewers/videoViewer/view.jsx +++ b/ui/component/viewers/videoViewer/view.jsx @@ -25,8 +25,7 @@ import I18nMessage from 'component/i18nMessage'; import { useHistory } from 'react-router'; import { getAllIds } from 'util/buildHomepage'; import type { HomepageCat } from 'util/buildHomepage'; -import { formatLbryUrlForWeb } from 'util/url'; -import { COLLECTIONS_CONSTS } from 'lbry-redux'; +import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; const PLAY_TIMEOUT_ERROR = 'play_timeout_error'; const PLAY_TIMEOUT_LIMIT = 2000; @@ -60,8 +59,7 @@ type Props = { homepageData?: { [string]: HomepageCat }, shareTelemetry: boolean, isFloating: boolean, - doPlayUri: (string) => void, - doSetPlayingUri: (string, string) => void, + doPlayUri: (string, string) => void, collectionId: string, nextRecommendedUri: string, previousListUri: string, @@ -104,7 +102,6 @@ function VideoViewer(props: Props) { shareTelemetry, isFloating, doPlayUri, - doSetPlayingUri, collectionId, nextRecommendedUri, previousListUri, @@ -183,21 +180,20 @@ function VideoViewer(props: Props) { const doPlay = useCallback( (playUri) => { - let navigateUrl = formatLbryUrlForWeb(playUri); - if (collectionId) { - const collectionParams = new URLSearchParams(); - collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); - navigateUrl = navigateUrl + `?` + collectionParams.toString(); - clearPosition(playUri); - } - if (!isFloating) { - push(navigateUrl); - } - doPlayUri(playUri); - doSetPlayingUri(playUri, collectionId); setDoNavigate(false); + const navigateUrl = formatLbryUrlForWeb(playUri); + if (collectionId) clearPosition(playUri); + if (!isFloating) { + push({ + pathname: navigateUrl, + search: collectionId && generateListSearchUrlParams(collectionId), + state: { collectionId, forceAutoplay: true, hideFloatingPlayer: true }, + }); + } else { + doPlayUri(playUri, collectionId); + } }, - [clearPosition, collectionId, doPlayUri, doSetPlayingUri, isFloating, push] + [clearPosition, collectionId, doPlayUri, isFloating, push] ); useEffect(() => { @@ -397,7 +393,6 @@ function VideoViewer(props: Props) { > {showAutoplayCountdown && ( setDoNavigate(true)} doReplay={() => setReplay(true)} diff --git a/ui/util/url.js b/ui/util/url.js index 2c88d899d..ecae03ca6 100644 --- a/ui/util/url.js +++ b/ui/util/url.js @@ -156,3 +156,9 @@ export const generateRssUrl = (domain, channelClaim) => { const url = `${domain}/$/rss/${channelClaim.canonical_url.replace('lbry://', '').replace('#', ':')}`; return url; }; + +export const generateListSearchUrlParams = (collectionId) => { + const urlParams = new URLSearchParams(); + urlParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); + return `?` + urlParams.toString(); +}; -- 2.45.3 From bb7ea8f01b9c1d4507f17e02312205b54b8dfee4 Mon Sep 17 00:00:00 2001 From: saltrafael Date: Thu, 9 Sep 2021 09:26:38 -0300 Subject: [PATCH 3/4] Better handle paid content on playlists --- ui/component/autoplayCountdown/view.jsx | 53 +++++++++++---- ui/component/common/icon-custom.jsx | 6 ++ ui/component/fileRenderFloating/index.js | 26 +++++++- ui/component/fileRenderFloating/view.jsx | 78 +++++++++++++++++++++-- ui/component/fileRenderInitiator/index.js | 1 - ui/component/fileRenderInitiator/view.jsx | 12 ++-- ui/component/uriIndicator/view.jsx | 4 +- ui/component/viewers/videoViewer/index.js | 14 ++-- ui/component/viewers/videoViewer/view.jsx | 27 ++++++-- ui/constants/icons.js | 1 + ui/redux/actions/content.js | 5 +- 11 files changed, 185 insertions(+), 42 deletions(-) diff --git a/ui/component/autoplayCountdown/view.jsx b/ui/component/autoplayCountdown/view.jsx index 938f32851..f1fd4b78f 100644 --- a/ui/component/autoplayCountdown/view.jsx +++ b/ui/component/autoplayCountdown/view.jsx @@ -15,8 +15,11 @@ type Props = { nextRecommendedClaim: ?StreamClaim, nextRecommendedUri: string, modal: { id: string, modalProps: {} }, + skipPaid: boolean, doNavigate: () => void, doReplay: () => void, + doPrevious: () => void, + onCanceled: () => void, }; function AutoplayCountdown(props: Props) { @@ -25,8 +28,11 @@ function AutoplayCountdown(props: Props) { nextRecommendedClaim, history: { push }, modal, + skipPaid, doNavigate, doReplay, + doPrevious, + onCanceled, } = props; const nextTitle = nextRecommendedClaim && nextRecommendedClaim.value && nextRecommendedClaim.value.title; @@ -68,6 +74,7 @@ function AutoplayCountdown(props: Props) { interval = setInterval(() => { const newTime = timer - 1; if (newTime === 0) { + if (skipPaid) setTimer(countdownTime); doNavigate(); } else { setTimer(timer - 1); @@ -78,7 +85,7 @@ function AutoplayCountdown(props: Props) { return () => { clearInterval(interval); }; - }, [timer, doNavigate, push, timerCanceled, isTimerPaused, nextRecommendedUri]); + }, [timer, doNavigate, push, timerCanceled, isTimerPaused, nextRecommendedUri, skipPaid]); if (timerCanceled || !nextRecommendedUri) { return null; @@ -105,19 +112,41 @@ function AutoplayCountdown(props: Props) { )} {!isTimerPaused && (
- {__('Playing in %seconds_left% seconds...', { seconds_left: timer })}{' '} -
)} -