diff --git a/CHANGELOG.md b/CHANGELOG.md index b6272a75c..7970ae03a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix Paid embed warning overlay redirection button now links to odysee _community pr!_ ([#6819](https://github.com/lbryio/lbry-desktop/pull/6819)) - Fix comment section redirection to create channel _community pr!_ ([#6557](https://github.com/lbryio/lbry-desktop/pull/6557)) - Clicking on the title of a floating player will take you back to the list ([#6921](https://github.com/lbryio/lbry-desktop/pull/6921)) +- Fix floating player stopping on markdown or image files ([#7073](https://github.com/lbryio/lbry-desktop/pull/7073)) ## [0.51.1] - [2021-06-26] diff --git a/flow-typed/content.js b/flow-typed/content.js index 6246a7c95..e32f6188f 100644 --- a/flow-typed/content.js +++ b/flow-typed/content.js @@ -2,6 +2,7 @@ declare type PlayingUri = { uri: string, + primaryUri: string, pathname: string, commentId?: string, source?: string, diff --git a/ui/component/claimListDiscover/view.jsx b/ui/component/claimListDiscover/view.jsx index 423d7bee3..39f705500 100644 --- a/ui/component/claimListDiscover/view.jsx +++ b/ui/component/claimListDiscover/view.jsx @@ -18,79 +18,68 @@ import { getLivestreamOnlyOptions } from 'util/search'; type Props = { uris: Array, - name?: string, - type: string, - pageSize?: number, - - fetchViewCount?: boolean, - forceShowReposts?: boolean, - hasNoSource?: boolean, - hasSource?: boolean, - hideAdvancedFilter?: boolean, - hideFilters?: boolean, - includeSupportAction?: boolean, - infiniteScroll?: Boolean, - isChannel?: boolean, - liveLivestreamsFirst?: boolean, - personalView: boolean, showHeader: boolean, - showHiddenByUser?: boolean, - showNoSourceClaims?: boolean, - tileLayout: boolean, - + type: string, + subscribedChannels: Array, + doClaimSearch: ({}) => void, + loading: boolean, + personalView: boolean, + doToggleTagFollowDesktop: (string) => void, + meta?: Node, + showNsfw: boolean, + hideReposts: boolean, + fetchViewCount?: boolean, + history: { action: string, push: (string) => void, replace: (string) => void }, + location: { search: string, pathname: string }, + claimSearchByQuery: { + [string]: Array, + }, + claimSearchByQueryLastPageReached: { [string]: boolean }, + mutedUris: Array, + blockedUris: Array, + hiddenNsfwMessage?: Node, + channelIds?: Array, + claimIds?: Array, + tags: string, // these are just going to be string. pass a CSV if you want multi + defaultTags: string, orderBy?: Array, defaultOrderBy?: string, freshness?: string, defaultFreshness?: string, - - tags: string, // these are just going to be string. pass a CSV if you want multi - defaultTags: string, - - claimType?: string | Array, - defaultClaimType?: Array, - - streamType?: string | Array, - defaultStreamType?: string | Array, - - empty?: string, - feeAmount?: string, - releaseTime?: string, - repostedClaimId?: string, - scrollAnchor?: string, - maxPages?: number, - limitClaimsPerChannel?: number, - - channelIds?: Array, - claimIds?: Array, - subscribedChannels: Array, - livestreamMap?: { [string]: any }, - header?: Node, headerLabel?: string | Node, - hiddenNsfwMessage?: Node, - injectedItem: ?Node, - meta?: Node, + name?: string, + hideAdvancedFilter?: boolean, + claimType?: string | Array, + defaultClaimType?: Array, + streamType?: string | Array, + defaultStreamType?: string | Array, renderProperties?: (Claim) => Node, - - history: { action: string, push: (string) => void, replace: (string) => void }, - location: { search: string, pathname: string }, - - // --- select --- + includeSupportAction?: boolean, + repostedClaimId?: string, + pageSize?: number, followedTags?: Array, - claimSearchByQuery: { [string]: Array }, - claimSearchByQueryLastPageReached: { [string]: boolean }, - claimsByUri: { [string]: any }, - loading: boolean, - showNsfw: boolean, - hideReposts: boolean, + injectedItem: ?Node, + infiniteScroll?: Boolean, + feeAmount?: string, + tileLayout: boolean, + hideFilters?: boolean, + maxPages?: number, + forceShowReposts?: boolean, languageSetting: string, - mutedUris: Array, - blockedUris: Array, searchInLanguage: boolean, - - // --- perform --- - doClaimSearch: ({}) => void, - doToggleTagFollowDesktop: (string) => void, + scrollAnchor?: string, + showHiddenByUser?: boolean, + liveLivestreamsFirst?: boolean, + livestreamMap?: { [string]: any }, + hasSource?: boolean, + hasNoSource?: boolean, + limitClaimsPerChannel?: number, + releaseTime?: string, + showNoSourceClaims?: boolean, + isChannel?: boolean, + empty?: string, + claimsByUri: { [string]: any }, doFetchViewCount: (claimIdCsv: string) => void, }; diff --git a/ui/component/embedPlayButton/view.jsx b/ui/component/embedPlayButton/view.jsx index 9a796478d..57d66fa2b 100644 --- a/ui/component/embedPlayButton/view.jsx +++ b/ui/component/embedPlayButton/view.jsx @@ -12,12 +12,12 @@ type Props = { uri: string, thumbnail: string, claim: ?Claim, - doResolveUri: string => void, - doFetchCostInfoForUri: string => void, + doResolveUri: (string) => void, + doFetchCostInfoForUri: (string) => void, costInfo: ?{ cost: number }, floatingPlayerEnabled: boolean, doPlayUri: (string, ?boolean, ?boolean, (GetResponse) => void) => void, - doAnaltyicsPurchaseEvent: GetResponse => void, + doAnaltyicsPurchaseEvent: (GetResponse) => void, parentCommentId?: string, isMarkdownPost: boolean, doSetPlayingUri: ({}) => void, @@ -69,8 +69,8 @@ export default function EmbedPlayButton(props: Props) { const formattedUrl = formatLbryUrlForWeb(uri); push(formattedUrl); } else { - doPlayUri(uri, undefined, undefined, fileInfo => { - let playingOptions: PlayingUri = { uri, pathname }; + doPlayUri(uri, undefined, undefined, (fileInfo) => { + let playingOptions = { uri, pathname, source: undefined, commentId: undefined }; if (parentCommentId) { playingOptions.source = 'comment'; playingOptions.commentId = parentCommentId; diff --git a/ui/component/fileRenderFloating/view.jsx b/ui/component/fileRenderFloating/view.jsx index 02fa9e6fc..911e50987 100644 --- a/ui/component/fileRenderFloating/view.jsx +++ b/ui/component/fileRenderFloating/view.jsx @@ -69,7 +69,7 @@ export default function FileRenderFloating(props: Props) { const { location, push } = useHistory(); const hideFloatingPlayer = location.state && location.state.hideFloatingPlayer; const isMobile = useIsMobile(); - const mainFilePlaying = playingUri && isURIEqual(playingUri.uri, primaryUri); + const mainFilePlaying = !isFloating && isURIEqual(uri, primaryUri); const [fileViewerRect, setFileViewerRect] = useState(); const [desktopPlayStartTime, setDesktopPlayStartTime] = useState(); const [wasDragging, setWasDragging] = useState(false); @@ -85,7 +85,8 @@ export default function FileRenderFloating(props: Props) { y: 0, }); - const navigateUrl = uri + (collectionId ? generateListSearchUrlParams(collectionId) : ''); + const navigateUrl = + playingUri && playingUri.primaryUri + (collectionId ? generateListSearchUrlParams(collectionId) : ''); const isFree = costInfo && costInfo.cost === 0; const canViewFile = isFree || claimWasPurchased; @@ -154,7 +155,7 @@ export default function FileRenderFloating(props: Props) { // Listen to main-window resizing and adjust the fp position accordingly: useEffect(() => { - const handleMainWindowResize = debounce((e) => { + const handleMainWindowResize = debounce(() => { let newPos = { x: Math.round(relativePos.x * getScreenWidth()), y: Math.round(relativePos.y * getScreenHeight()), @@ -175,13 +176,11 @@ export default function FileRenderFloating(props: Props) { ? document.querySelector(`.${PRIMARY_PLAYER_WRAPPER_CLASS}`) : document.querySelector(`.${INLINE_PLAYER_WRAPPER_CLASS}`); - if (!element) { - return; - } + if (!element) return; const rect = element.getBoundingClientRect(); - // getBoundingCLientRect returns a DomRect, not an object + // getBoundingClientRect returns a DomRect, not an object const objectRect = { top: rect.top, right: rect.right, @@ -198,11 +197,11 @@ export default function FileRenderFloating(props: Props) { }, [mainFilePlaying]); useEffect(() => { - if (streamingUrl) { + if (playingUri && playingUri.primaryUri) { handleResize(); setCountdownCanceled(false); } - }, [handleResize, streamingUrl, videoTheaterMode]); + }, [handleResize, playingUri, videoTheaterMode]); useEffect(() => { handleResize(); @@ -270,7 +269,7 @@ export default function FileRenderFloating(props: Props) { return null; } - function handleDragStart(e, ui) { + function handleDragStart() { // Not really necessary, but reset just in case 'handleStop' didn't fire. setWasDragging(false); } @@ -286,7 +285,7 @@ export default function FileRenderFloating(props: Props) { }); } - function handleDragStop(e, ui) { + function handleDragStop(e) { if (wasDragging) { e.stopPropagation(); setWasDragging(false); diff --git a/ui/component/fileRenderInitiator/index.js b/ui/component/fileRenderInitiator/index.js index efa2f28c9..2a9765ce1 100644 --- a/ui/component/fileRenderInitiator/index.js +++ b/ui/component/fileRenderInitiator/index.js @@ -4,7 +4,6 @@ import { makeSelectFileInfoForUri, makeSelectThumbnailForUri, makeSelectClaimForUri, - makeSelectStreamingUrlForUri, makeSelectClaimWasPurchased, SETTINGS, COLLECTIONS_CONSTS, @@ -16,7 +15,6 @@ import { withRouter } from 'react-router'; import { makeSelectIsPlaying, makeSelectShouldObscurePreview, - selectPlayingUri, makeSelectInsufficientCreditsForUri, makeSelectFileRenderModeForUri, } from 'redux/selectors/content'; @@ -33,9 +31,7 @@ const select = (state, props) => { fileInfo: makeSelectFileInfoForUri(props.uri)(state), obscurePreview: makeSelectShouldObscurePreview(props.uri)(state), isPlaying: makeSelectIsPlaying(props.uri)(state), - playingUri: selectPlayingUri(state), insufficientCredits: makeSelectInsufficientCreditsForUri(props.uri)(state), - streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), autoplay: makeSelectClientSetting(SETTINGS.AUTOPLAY_MEDIA)(state), costInfo: makeSelectCostInfoForUri(props.uri)(state), renderMode: makeSelectFileRenderModeForUri(props.uri)(state), @@ -47,9 +43,9 @@ const select = (state, props) => { }; const perform = (dispatch) => ({ - play: (uri, collectionId) => { + play: (uri, collectionId, isPlayable) => { dispatch(doSetPrimaryUri(uri)); - dispatch(doSetPlayingUri({ uri, collectionId })); + if (isPlayable) dispatch(doSetPlayingUri({ uri, collectionId })); dispatch(doPlayUri(uri, undefined, undefined, (fileInfo) => dispatch(doAnaltyicsPurchaseEvent(fileInfo)))); }, }); diff --git a/ui/component/fileRenderInitiator/view.jsx b/ui/component/fileRenderInitiator/view.jsx index aac98c99d..a654ee967 100644 --- a/ui/component/fileRenderInitiator/view.jsx +++ b/ui/component/fileRenderInitiator/view.jsx @@ -16,8 +16,7 @@ import Nag from 'component/common/nag'; import FileRenderPlaceholder from 'static/img/fileRenderPlaceholder.png'; type Props = { - play: (string, string) => void, - isLoading: boolean, + play: (string, string, boolean) => void, isPlaying: boolean, fileInfo: FileListItem, uri: string, @@ -104,9 +103,9 @@ export default function FileRenderInitiator(props: Props) { e.stopPropagation(); } - play(uri, collectionId); + play(uri, collectionId, isPlayable); }, - [play, uri, collectionId] + [play, uri, isPlayable, collectionId] ); useEffect(() => { diff --git a/ui/component/settingLanguage/view.jsx b/ui/component/settingLanguage/view.jsx index 74c2d5491..515970d6e 100644 --- a/ui/component/settingLanguage/view.jsx +++ b/ui/component/settingLanguage/view.jsx @@ -35,22 +35,20 @@ function SettingLanguage(props: Props) { return ( - {!previousLanguage && ( - - {sortLanguageMap(SUPPORTED_LANGUAGES).map(([langKey, langName]) => ( - - ))} - - )} - {previousLanguage && } + + + {sortLanguageMap(SUPPORTED_LANGUAGES).map(([langKey, langName]) => ( + + ))} + ); } diff --git a/ui/component/settingsSideNavigation/view.jsx b/ui/component/settingsSideNavigation/view.jsx index 5acb442c6..e791e7ffb 100644 --- a/ui/component/settingsSideNavigation/view.jsx +++ b/ui/component/settingsSideNavigation/view.jsx @@ -56,11 +56,7 @@ export default function SettingsSideNavigation() { const TOP_MARGIN_PX = 20; const element = document.getElementById(section); if (element) { - window.scrollTo({ - top: element.offsetTop - TOP_MARGIN_PX, - left: 0, - behavior: 'smooth', - }); + window.scrollTo(0, element.offsetTop - TOP_MARGIN_PX); } } diff --git a/ui/component/viewers/videoViewer/index.js b/ui/component/viewers/videoViewer/index.js index 36ebd422b..2ca09af22 100644 --- a/ui/component/viewers/videoViewer/index.js +++ b/ui/component/viewers/videoViewer/index.js @@ -1,7 +1,6 @@ import { connect } from 'react-redux'; import { makeSelectClaimForUri, - makeSelectFileInfoForUri, makeSelectThumbnailForUri, SETTINGS, COLLECTIONS_CONSTS, @@ -40,6 +39,7 @@ const select = (state, props) => { const userId = selectUser(state) && selectUser(state).id; const playingUri = selectPlayingUri(state); const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (playingUri && playingUri.collectionId); + const isMarkdownOrComment = playingUri && (playingUri.source === 'markdown' || playingUri.source === 'comment'); let nextRecommendedUri; let previousListUri; @@ -51,24 +51,23 @@ const select = (state, props) => { } return { + position, + userId, + collectionId, + nextRecommendedUri, + previousListUri, + isMarkdownOrComment, autoplayIfEmbedded: Boolean(autoplay), - autoplayMedia: Boolean(makeSelectClientSetting(SETTINGS.AUTOPLAY_MEDIA)(state)), - autoplayNext: Boolean(makeSelectClientSetting(SETTINGS.AUTOPLAY_NEXT)(state)), + autoplayNext: makeSelectClientSetting(SETTINGS.AUTOPLAY_NEXT)(state), volume: selectVolume(state), muted: selectMute(state), videoPlaybackRate: makeSelectClientSetting(SETTINGS.VIDEO_PLAYBACK_RATE)(state), - position: position, - hasFileInfo: Boolean(makeSelectFileInfoForUri(uri)(state)), thumbnail: makeSelectThumbnailForUri(uri)(state), claim: makeSelectClaimForUri(uri)(state), homepageData: selectHomepageData(state), authenticated: selectUserVerifiedEmail(state), - userId: userId, shareTelemetry: IS_WEB || selectDaemonSettings(state).share_usage_data, isFloating: makeSelectIsPlayerFloating(props.location)(state), - collectionId, - nextRecommendedUri, - previousListUri, videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state), }; }; diff --git a/ui/component/viewers/videoViewer/view.jsx b/ui/component/viewers/videoViewer/view.jsx index 2f5764bac..efe534dd1 100644 --- a/ui/component/viewers/videoViewer/view.jsx +++ b/ui/component/viewers/videoViewer/view.jsx @@ -42,7 +42,6 @@ type Props = { videoPlaybackRate: number, volume: number, uri: string, - autoplayMedia: boolean, autoplayNext: boolean, autoplayIfEmbedded: boolean, desktopPlayStartTime?: number, @@ -64,6 +63,7 @@ type Props = { nextRecommendedUri: string, previousListUri: string, videoTheaterMode: boolean, + isMarkdownOrComment: boolean, }; /* @@ -84,7 +84,6 @@ function VideoViewer(props: Props) { uri, muted, volume, - autoplayMedia, autoplayNext, autoplayIfEmbedded, doAnalyticsView, @@ -106,6 +105,7 @@ function VideoViewer(props: Props) { nextRecommendedUri, previousListUri, videoTheaterMode, + isMarkdownOrComment, } = props; const permanentUrl = claim && claim.permanent_url; const adApprovedChannelIds = homepageData ? getAllIds(homepageData) : []; @@ -196,32 +196,32 @@ function VideoViewer(props: Props) { ); useEffect(() => { - if (doNavigate) { - if (playNextUrl) { - if (permanentUrl !== nextRecommendedUri) { - if (nextRecommendedUri) { - if (collectionId) clearPosition(permanentUrl); - doPlay(nextRecommendedUri); - } - } else { - setReplay(true); + if (!doNavigate) return; + + if (playNextUrl) { + if (permanentUrl !== nextRecommendedUri) { + if (nextRecommendedUri) { + if (collectionId) clearPosition(permanentUrl); + doPlay(nextRecommendedUri); } } else { - if (videoNode) { - const currentTime = videoNode.currentTime; - - if (currentTime <= 5) { - if (previousListUri && permanentUrl !== previousListUri) doPlay(previousListUri); - } else { - videoNode.currentTime = 0; - } - setDoNavigate(false); - } + setReplay(true); + } + } else { + if (videoNode) { + const currentTime = videoNode.currentTime; + + if (currentTime <= 5) { + if (previousListUri && permanentUrl !== previousListUri) doPlay(previousListUri); + } else { + videoNode.currentTime = 0; + } + setDoNavigate(false); } - if (!ended) setDoNavigate(false); - setEnded(false); - setPlayNextUrl(true); } + if (!ended) setDoNavigate(false); + setEnded(false); + setPlayNextUrl(true); }, [ clearPosition, collectionId, @@ -236,37 +236,25 @@ function VideoViewer(props: Props) { ]); React.useEffect(() => { - if (ended) { - analytics.videoIsPlaying(false); + if (!ended) return; - if (adUrl) { - setAdUrl(null); - return; - } + analytics.videoIsPlaying(false); - if (embedded) { - setIsEndedEmbed(true); - } else if (!collectionId && autoplayNext) { - setShowAutoplayCountdown(true); - } else if (collectionId) { - setDoNavigate(true); - } - - clearPosition(uri); + if (adUrl) { + setAdUrl(null); + return; } - }, [ - embedded, - setIsEndedEmbed, - autoplayMedia, - setShowAutoplayCountdown, - adUrl, - setAdUrl, - clearPosition, - uri, - ended, - collectionId, - autoplayNext, - ]); + + if (embedded) { + setIsEndedEmbed(true); + } else if (!collectionId && autoplayNext) { + setShowAutoplayCountdown(true); + } else if (collectionId) { + setDoNavigate(true); + } + + clearPosition(uri); + }, [adUrl, autoplayNext, clearPosition, collectionId, embedded, ended, setAdUrl, uri]); function onPlay(player) { setEnded(false); @@ -321,12 +309,14 @@ function VideoViewer(props: Props) { player.muted(muted); player.volume(volume); player.playbackRate(videoPlaybackRate); - addTheaterModeButton(player, toggleVideoTheaterMode); - if (collectionId) { - addPlayNextButton(player, doPlayNext); - addPlayPreviousButton(player, doPlayPrevious); - } else { - addAutoplayNextButton(player, toggleAutoplayNext, autoplayNext); + if (!isMarkdownOrComment) { + addTheaterModeButton(player, toggleVideoTheaterMode); + if (collectionId) { + addPlayNextButton(player, doPlayNext); + addPlayPreviousButton(player, doPlayPrevious); + } else { + addAutoplayNextButton(player, toggleAutoplayNext, autoplayNext); + } } } diff --git a/ui/redux/selectors/content.js b/ui/redux/selectors/content.js index 208b9818b..736904f0b 100644 --- a/ui/redux/selectors/content.js +++ b/ui/redux/selectors/content.js @@ -34,14 +34,14 @@ export const makeSelectIsPlaying = (uri: string) => createSelector(selectPrimaryUri, (primaryUri) => primaryUri === uri); export const makeSelectIsPlayerFloating = (location: UrlLocation) => - createSelector(selectPrimaryUri, selectPlayingUri, selectClaimsByUri, (primaryUri, playingUri, claimsByUri) => { + createSelector(selectPrimaryUri, selectPlayingUri, (primaryUri, playingUri) => { const isInlineSecondaryPlayer = playingUri && playingUri.uri !== primaryUri && location.pathname === playingUri.pathname && (playingUri.source === 'comment' || playingUri.source === 'markdown'); - if ((playingUri && playingUri.uri === primaryUri) || isInlineSecondaryPlayer) { + if ((playingUri && playingUri.primaryUri === primaryUri) || isInlineSecondaryPlayer) { return false; }