Add Shuffle Play Option on List Page and Menus
This commit is contained in:
parent
3376986c26
commit
6ec25b0f71
10 changed files with 216 additions and 62 deletions
|
@ -30,6 +30,8 @@ import { doToast } from 'redux/actions/notifications';
|
||||||
import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions';
|
import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions';
|
||||||
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
||||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
|
import { selectListShuffle } from 'redux/selectors/content';
|
||||||
|
import { doSetPlayingUri, doToggleShuffleList } from 'redux/actions/content';
|
||||||
import ClaimPreview from './view';
|
import ClaimPreview from './view';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
|
||||||
|
@ -42,6 +44,9 @@ const select = (state, props) => {
|
||||||
const contentSigningChannel = contentClaim && contentClaim.signing_channel;
|
const contentSigningChannel = contentClaim && contentClaim.signing_channel;
|
||||||
const contentPermanentUri = contentClaim && contentClaim.permanent_url;
|
const contentPermanentUri = contentClaim && contentClaim.permanent_url;
|
||||||
const contentChannelUri = (contentSigningChannel && contentSigningChannel.permanent_url) || contentPermanentUri;
|
const contentChannelUri = (contentSigningChannel && contentSigningChannel.permanent_url) || contentPermanentUri;
|
||||||
|
const shuffleList = selectListShuffle(state);
|
||||||
|
const shuffle = shuffleList && shuffleList.collectionId === collectionId && shuffleList.newUrls;
|
||||||
|
const playNextUri = shuffle && shuffle[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
claim,
|
claim,
|
||||||
|
@ -69,6 +74,7 @@ const select = (state, props) => {
|
||||||
editedCollection: makeSelectEditedCollectionForId(collectionId)(state),
|
editedCollection: makeSelectEditedCollectionForId(collectionId)(state),
|
||||||
isAuthenticated: Boolean(selectUserVerifiedEmail(state)),
|
isAuthenticated: Boolean(selectUserVerifiedEmail(state)),
|
||||||
resolvedList,
|
resolvedList,
|
||||||
|
playNextUri,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,6 +102,8 @@ const perform = (dispatch) => ({
|
||||||
doChannelUnsubscribe: (subscription) => dispatch(doChannelUnsubscribe(subscription)),
|
doChannelUnsubscribe: (subscription) => dispatch(doChannelUnsubscribe(subscription)),
|
||||||
doCollectionEdit: (collection, props) => dispatch(doCollectionEdit(collection, props)),
|
doCollectionEdit: (collection, props) => dispatch(doCollectionEdit(collection, props)),
|
||||||
fetchCollectionItems: (collectionId) => dispatch(doFetchItemsInCollection({ collectionId })),
|
fetchCollectionItems: (collectionId) => dispatch(doFetchItemsInCollection({ collectionId })),
|
||||||
|
doSetPlayingUri: (uri) => dispatch(doSetPlayingUri({ uri })),
|
||||||
|
doToggleShuffleList: (collectionId) => dispatch(doToggleShuffleList(undefined, collectionId, true, true)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ClaimPreview);
|
export default connect(select, perform)(ClaimPreview);
|
||||||
|
|
|
@ -58,6 +58,9 @@ type Props = {
|
||||||
isAuthenticated: boolean,
|
isAuthenticated: boolean,
|
||||||
fetchCollectionItems: (string) => void,
|
fetchCollectionItems: (string) => void,
|
||||||
resolvedList: boolean,
|
resolvedList: boolean,
|
||||||
|
playNextUri: string,
|
||||||
|
doSetPlayingUri: (string) => void,
|
||||||
|
doToggleShuffleList: (string) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
function ClaimMenuList(props: Props) {
|
function ClaimMenuList(props: Props) {
|
||||||
|
@ -97,7 +100,11 @@ function ClaimMenuList(props: Props) {
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
fetchCollectionItems,
|
fetchCollectionItems,
|
||||||
resolvedList,
|
resolvedList,
|
||||||
|
playNextUri,
|
||||||
|
doSetPlayingUri,
|
||||||
|
doToggleShuffleList,
|
||||||
} = props;
|
} = props;
|
||||||
|
const [doShuffle, setDoShuffle] = React.useState(false);
|
||||||
const incognitoClaim = contentChannelUri && !contentChannelUri.includes('@');
|
const incognitoClaim = contentChannelUri && !contentChannelUri.includes('@');
|
||||||
const isChannel = !incognitoClaim && !contentSigningChannel;
|
const isChannel = !incognitoClaim && !contentSigningChannel;
|
||||||
const { channelName } = parseURI(contentChannelUri);
|
const { channelName } = parseURI(contentChannelUri);
|
||||||
|
@ -118,6 +125,20 @@ function ClaimMenuList(props: Props) {
|
||||||
}
|
}
|
||||||
}, [collectionId, fetchCollectionItems]);
|
}, [collectionId, fetchCollectionItems]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (resolvedList && doShuffle) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [playNextUri, doShuffle, resolvedList, doToggleShuffleList, collectionId, doSetPlayingUri, push]);
|
||||||
|
|
||||||
if (!claim) {
|
if (!claim) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -268,6 +289,18 @@ function ClaimMenuList(props: Props) {
|
||||||
{__('View List')}
|
{__('View List')}
|
||||||
</a>
|
</a>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
className="comment__menu-option"
|
||||||
|
onSelect={() => {
|
||||||
|
if (!resolvedList) fetchItems();
|
||||||
|
setDoShuffle(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="menu__link">
|
||||||
|
<Icon aria-hidden icon={ICONS.SHUFFLE} />
|
||||||
|
{__('Shuffle Play')}
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
{isMyCollection && (
|
{isMyCollection && (
|
||||||
<>
|
<>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|
|
@ -10,21 +10,33 @@ import {
|
||||||
import { makeSelectCostInfoForUri } from 'lbryinc';
|
import { makeSelectCostInfoForUri } from 'lbryinc';
|
||||||
import { doToast } from 'redux/actions/notifications';
|
import { doToast } from 'redux/actions/notifications';
|
||||||
import { doOpenModal } from 'redux/actions/app';
|
import { doOpenModal } from 'redux/actions/app';
|
||||||
|
import { selectListShuffle } from 'redux/selectors/content';
|
||||||
|
import { doSetPlayingUri, doToggleShuffleList } from 'redux/actions/content';
|
||||||
import CollectionActions from './view';
|
import CollectionActions from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => {
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
const collectionId = props.collectionId;
|
||||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
const shuffleList = selectListShuffle(state);
|
||||||
costInfo: makeSelectCostInfoForUri(props.uri)(state),
|
const shuffle = shuffleList && shuffleList.collectionId === collectionId && shuffleList.newUrls;
|
||||||
myChannels: selectMyChannelClaims(state),
|
const playNextUri = shuffle && shuffle[0];
|
||||||
claimIsPending: makeSelectClaimIsPending(props.uri)(state),
|
|
||||||
isMyCollection: makeSelectCollectionIsMine(props.collectionId)(state),
|
return {
|
||||||
collectionHasEdits: Boolean(makeSelectEditedCollectionForId(props.collectionId)(state)),
|
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(props.collectionId)(state),
|
||||||
|
collectionHasEdits: Boolean(makeSelectEditedCollectionForId(props.collectionId)(state)),
|
||||||
|
playNextUri,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
openModal: (modal, props) => dispatch(doOpenModal(modal, props)),
|
||||||
doToast: (options) => dispatch(doToast(options)),
|
doToast: (options) => dispatch(doToast(options)),
|
||||||
|
doSetPlayingUri: (uri) => dispatch(doSetPlayingUri({ uri })),
|
||||||
|
doToggleShuffleList: (collectionId) => dispatch(doToggleShuffleList(undefined, collectionId, true, true)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(CollectionActions);
|
export default connect(select, perform)(CollectionActions);
|
||||||
|
|
|
@ -11,6 +11,8 @@ import { useHistory } from 'react-router';
|
||||||
import { EDIT_PAGE, PAGE_VIEW_QUERY } from 'page/collection/view';
|
import { EDIT_PAGE, PAGE_VIEW_QUERY } from 'page/collection/view';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { ENABLE_FILE_REACTIONS } from 'config';
|
import { ENABLE_FILE_REACTIONS } from 'config';
|
||||||
|
import { COLLECTIONS_CONSTS } from 'lbry-redux';
|
||||||
|
import { formatLbryUrlForWeb } from 'util/url';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
|
@ -24,6 +26,10 @@ type Props = {
|
||||||
showInfo: boolean,
|
showInfo: boolean,
|
||||||
setShowInfo: (boolean) => void,
|
setShowInfo: (boolean) => void,
|
||||||
collectionHasEdits: boolean,
|
collectionHasEdits: boolean,
|
||||||
|
doToggleShuffleList: (string) => void,
|
||||||
|
playNextUri: string,
|
||||||
|
doSetPlayingUri: (string) => void,
|
||||||
|
isBuiltin: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function CollectionActions(props: Props) {
|
function CollectionActions(props: Props) {
|
||||||
|
@ -37,61 +43,92 @@ function CollectionActions(props: Props) {
|
||||||
showInfo,
|
showInfo,
|
||||||
setShowInfo,
|
setShowInfo,
|
||||||
collectionHasEdits,
|
collectionHasEdits,
|
||||||
|
doToggleShuffleList,
|
||||||
|
playNextUri,
|
||||||
|
doSetPlayingUri,
|
||||||
|
isBuiltin,
|
||||||
} = props;
|
} = props;
|
||||||
|
const [doShuffle, setDoShuffle] = React.useState(false);
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const claimId = claim && claim.claim_id;
|
const claimId = claim && claim.claim_id;
|
||||||
const webShareable = true; // collections have cost?
|
const webShareable = true; // collections have cost?
|
||||||
|
|
||||||
|
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(playNextUri);
|
||||||
|
push(navigateUrl);
|
||||||
|
}
|
||||||
|
}, [push, doSetPlayingUri, collectionId, playNextUri, doShuffle]);
|
||||||
|
|
||||||
const lhsSection = (
|
const lhsSection = (
|
||||||
<>
|
<>
|
||||||
{ENABLE_FILE_REACTIONS && uri && <FileReactions uri={uri} />}
|
<Button
|
||||||
{uri && <ClaimSupportButton uri={uri} fileAction />}
|
className="button--file-action"
|
||||||
{/* TODO Add ClaimRepostButton component */}
|
icon={ICONS.SHUFFLE}
|
||||||
{uri && (
|
label={__('Shuffle Play')}
|
||||||
<Button
|
title={__('Shuffle Play')}
|
||||||
className="button--file-action"
|
onClick={() => {
|
||||||
icon={ICONS.SHARE}
|
doToggleShuffleList(collectionId);
|
||||||
label={__('Share')}
|
setDoShuffle(true);
|
||||||
title={__('Share')}
|
}}
|
||||||
onClick={() => openModal(MODALS.SOCIAL_SHARE, { uri, webShareable })}
|
/>
|
||||||
/>
|
{!isBuiltin && (
|
||||||
|
<>
|
||||||
|
{ENABLE_FILE_REACTIONS && uri && <FileReactions uri={uri} />}
|
||||||
|
{uri && <ClaimSupportButton uri={uri} fileAction />}
|
||||||
|
{/* TODO Add ClaimRepostButton component */}
|
||||||
|
{uri && (
|
||||||
|
<Button
|
||||||
|
className="button--file-action"
|
||||||
|
icon={ICONS.SHARE}
|
||||||
|
label={__('Share')}
|
||||||
|
title={__('Share')}
|
||||||
|
onClick={() => openModal(MODALS.SOCIAL_SHARE, { uri, webShareable })}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const rhsSection = (
|
const rhsSection = (
|
||||||
<>
|
<>
|
||||||
{isMyCollection && (
|
{!isBuiltin &&
|
||||||
<Button
|
(isMyCollection ? (
|
||||||
title={uri ? __('Update') : __('Publish')}
|
<>
|
||||||
label={uri ? __('Update') : __('Publish')}
|
<Button
|
||||||
className={classnames('button--file-action')}
|
title={uri ? __('Update') : __('Publish')}
|
||||||
onClick={() => push(`?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`)}
|
label={uri ? __('Update') : __('Publish')}
|
||||||
icon={ICONS.PUBLISH}
|
className={classnames('button--file-action')}
|
||||||
iconColor={collectionHasEdits && 'red'}
|
onClick={() => push(`?${PAGE_VIEW_QUERY}=${EDIT_PAGE}`)}
|
||||||
iconSize={18}
|
icon={ICONS.PUBLISH}
|
||||||
disabled={claimIsPending}
|
iconColor={collectionHasEdits && 'red'}
|
||||||
/>
|
iconSize={18}
|
||||||
)}
|
disabled={claimIsPending}
|
||||||
{isMyCollection && (
|
/>
|
||||||
<Button
|
<Button
|
||||||
className={classnames('button--file-action')}
|
className={classnames('button--file-action')}
|
||||||
title={__('Delete List')}
|
title={__('Delete List')}
|
||||||
onClick={() => openModal(MODALS.COLLECTION_DELETE, { uri, collectionId, redirect: `/$/${PAGES.LISTS}` })}
|
onClick={() => openModal(MODALS.COLLECTION_DELETE, { uri, collectionId, redirect: `/$/${PAGES.LISTS}` })}
|
||||||
icon={ICONS.DELETE}
|
icon={ICONS.DELETE}
|
||||||
iconSize={18}
|
iconSize={18}
|
||||||
description={__('Delete List')}
|
description={__('Delete List')}
|
||||||
disabled={claimIsPending}
|
disabled={claimIsPending}
|
||||||
/>
|
/>
|
||||||
)}
|
</>
|
||||||
{!isMyCollection && (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
title={__('Report content')}
|
title={__('Report content')}
|
||||||
className="button--file-action"
|
className="button--file-action"
|
||||||
icon={ICONS.REPORT}
|
icon={ICONS.REPORT}
|
||||||
navigate={`/$/${PAGES.REPORT_CONTENT}?claimId=${claimId}`}
|
navigate={`/$/${PAGES.REPORT_CONTENT}?claimId=${claimId}`}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ type Props = {
|
||||||
loop: boolean,
|
loop: boolean,
|
||||||
shuffle: boolean,
|
shuffle: boolean,
|
||||||
doToggleLoopList: (string, boolean) => void,
|
doToggleLoopList: (string, boolean) => void,
|
||||||
doToggleShuffleList: (string, boolean) => void,
|
doToggleShuffleList: (string, string, boolean) => void,
|
||||||
createUnpublishedCollection: (string, Array<any>, ?string) => void,
|
createUnpublishedCollection: (string, Array<any>, ?string) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ export default function CollectionContent(props: Props) {
|
||||||
icon={ICONS.SHUFFLE}
|
icon={ICONS.SHUFFLE}
|
||||||
iconColor={shuffle && 'blue'}
|
iconColor={shuffle && 'blue'}
|
||||||
className="button--file-action"
|
className="button--file-action"
|
||||||
onClick={() => doToggleShuffleList(id, !shuffle)}
|
onClick={() => doToggleShuffleList(url, id, !shuffle)}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doCollectionEdit, makeSelectNameForCollectionId, doCollectionDelete } from 'lbry-redux';
|
import { doCollectionEdit, makeSelectNameForCollectionId, doCollectionDelete } from 'lbry-redux';
|
||||||
import { doOpenModal } from 'redux/actions/app';
|
import { doOpenModal } from 'redux/actions/app';
|
||||||
|
import { selectListShuffle } from 'redux/selectors/content';
|
||||||
|
import { doSetPlayingUri, doToggleShuffleList } from 'redux/actions/content';
|
||||||
import CollectionMenuList from './view';
|
import CollectionMenuList from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
|
const collectionId = props.collectionId;
|
||||||
|
const shuffleList = selectListShuffle(state);
|
||||||
|
const shuffle = shuffleList && shuffleList.collectionId === collectionId && shuffleList.newUrls;
|
||||||
|
const playNextUri = shuffle && shuffle[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
collectionName: makeSelectNameForCollectionId(props.collectionId)(state),
|
collectionName: makeSelectNameForCollectionId(props.collectionId)(state),
|
||||||
|
playNextUri,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,4 +21,6 @@ export default connect(select, {
|
||||||
doCollectionEdit,
|
doCollectionEdit,
|
||||||
doOpenModal,
|
doOpenModal,
|
||||||
doCollectionDelete,
|
doCollectionDelete,
|
||||||
|
doSetPlayingUri,
|
||||||
|
doToggleShuffleList,
|
||||||
})(CollectionMenuList);
|
})(CollectionMenuList);
|
||||||
|
|
|
@ -7,19 +7,44 @@ import { Menu, MenuButton, MenuList, MenuItem } from '@reach/menu-button';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
|
import { formatLbryUrlForWeb } from 'util/url';
|
||||||
|
import { COLLECTIONS_CONSTS } from 'lbry-redux';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
inline?: boolean,
|
inline?: boolean,
|
||||||
doOpenModal: (string, {}) => void,
|
doOpenModal: (string, {}) => void,
|
||||||
collectionName?: string,
|
collectionName?: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
|
playNextUri: string,
|
||||||
|
doSetPlayingUri: ({ uri: ?string }) => void,
|
||||||
|
doToggleShuffleList: (string, string, boolean, boolean) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
function CollectionMenuList(props: Props) {
|
function CollectionMenuList(props: Props) {
|
||||||
const { inline = false, collectionId, collectionName, doOpenModal } = props;
|
const {
|
||||||
|
inline = false,
|
||||||
|
collectionId,
|
||||||
|
collectionName,
|
||||||
|
doOpenModal,
|
||||||
|
playNextUri,
|
||||||
|
doSetPlayingUri,
|
||||||
|
doToggleShuffleList,
|
||||||
|
} = props;
|
||||||
|
const [doShuffle, setDoShuffle] = React.useState(false);
|
||||||
|
|
||||||
const { push } = useHistory();
|
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);
|
||||||
|
}
|
||||||
|
}, [push, doSetPlayingUri, collectionId, playNextUri, doShuffle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
|
@ -40,6 +65,18 @@ function CollectionMenuList(props: Props) {
|
||||||
{__('View List')}
|
{__('View List')}
|
||||||
</a>
|
</a>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
className="comment__menu-option"
|
||||||
|
onSelect={() => {
|
||||||
|
doToggleShuffleList('', collectionId, true, true);
|
||||||
|
setDoShuffle(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="menu__link">
|
||||||
|
<Icon aria-hidden icon={ICONS.SHUFFLE} />
|
||||||
|
{__('Shuffle Play')}
|
||||||
|
</div>
|
||||||
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className="comment__menu-option"
|
className="comment__menu-option"
|
||||||
onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}?view=edit`)}
|
onSelect={() => push(`/$/${PAGES.LIST}/${collectionId}?view=edit`)}
|
||||||
|
|
|
@ -112,18 +112,26 @@ export default function CollectionPage(props: Props) {
|
||||||
title={
|
title={
|
||||||
<span>
|
<span>
|
||||||
<Icon
|
<Icon
|
||||||
icon={(collectionId === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) ||
|
icon={
|
||||||
(collectionId === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) || ICONS.STACK}
|
(collectionId === COLLECTIONS_CONSTS.WATCH_LATER_ID && ICONS.TIME) ||
|
||||||
className="icon--margin-right" />
|
(collectionId === COLLECTIONS_CONSTS.FAVORITES_ID && ICONS.STAR) ||
|
||||||
|
ICONS.STACK
|
||||||
|
}
|
||||||
|
className="icon--margin-right"
|
||||||
|
/>
|
||||||
{claim ? claim.value.title || claim.name : collection && collection.name}
|
{claim ? claim.value.title || claim.name : collection && collection.name}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
titleActions={titleActions}
|
titleActions={titleActions}
|
||||||
subtitle={subTitle}
|
subtitle={subTitle}
|
||||||
body={
|
body={
|
||||||
!isBuiltin && (
|
<CollectionActions
|
||||||
<CollectionActions uri={uri} collectionId={collectionId} setShowInfo={setShowInfo} showInfo={showInfo} />
|
uri={uri}
|
||||||
)
|
collectionId={collectionId}
|
||||||
|
setShowInfo={setShowInfo}
|
||||||
|
showInfo={showInfo}
|
||||||
|
isBuiltin={isBuiltin}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
actions={
|
actions={
|
||||||
showInfo &&
|
showInfo &&
|
||||||
|
|
|
@ -298,17 +298,25 @@ export function doToggleLoopList(collectionId: string, loop: boolean, hideToast:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doToggleShuffleList(collectionId: string, shuffle: boolean, hideToast: boolean) {
|
export function doToggleShuffleList(currentUri: string, collectionId: string, shuffle: boolean, hideToast: boolean) {
|
||||||
return (dispatch: Dispatch, getState: () => any) => {
|
return (dispatch: Dispatch, getState: () => any) => {
|
||||||
if (shuffle) {
|
if (shuffle) {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const urls = makeSelectUrlsForCollectionId(collectionId)(state);
|
const urls = makeSelectUrlsForCollectionId(collectionId)(state);
|
||||||
|
|
||||||
const newUrls = urls
|
let newUrls = urls
|
||||||
.map((item) => ({ item, sort: Math.random() }))
|
.map((item) => ({ item, sort: Math.random() }))
|
||||||
.sort((a, b) => a.sort - b.sort)
|
.sort((a, b) => a.sort - b.sort)
|
||||||
.map(({ item }) => item);
|
.map(({ item }) => item);
|
||||||
|
|
||||||
|
// the currently playing URI should be first in list or else
|
||||||
|
// can get in strange position where it might be in the middle or last
|
||||||
|
// and the shuffled list ends before scrolling through all entries
|
||||||
|
if (currentUri && currentUri !== '') {
|
||||||
|
newUrls.splice(newUrls.indexOf(currentUri), 1);
|
||||||
|
newUrls.splice(0, 0, currentUri);
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.TOGGLE_SHUFFLE_LIST,
|
type: ACTIONS.TOGGLE_SHUFFLE_LIST,
|
||||||
data: { collectionId, newUrls },
|
data: { collectionId, newUrls },
|
||||||
|
|
|
@ -314,6 +314,7 @@ $thumbnailWidthSmall: 1rem;
|
||||||
font-size: var(--font-xsmall);
|
font-size: var(--font-xsmall);
|
||||||
|
|
||||||
.menu__link {
|
.menu__link {
|
||||||
|
color: var(--color-text);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue