Skip to content

Commit

Permalink
Add setting for default playlist action (#3162)
Browse files Browse the repository at this point in the history
* Add setting for default playlist action

* Fix typo

---------

Co-authored-by: miko <[email protected]>
  • Loading branch information
keikari and miko authored Oct 14, 2024
1 parent f34095a commit ce707b0
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 13 deletions.
4 changes: 3 additions & 1 deletion static/app-strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2953,6 +2953,8 @@
"Receive 1 LBC for inviting a friend, an enemy, a frenemy, or an enefriend. Everyone needs content freedom.": "Receive 1 LBC for inviting a friend, an enemy, a frenemy, or an enefriend. Everyone needs content freedom.",
"Receive a credit of at least 0.05 LBC for watching cool stuff at least 3 days during the week.": "Receive a credit of at least 0.05 LBC for watching cool stuff at least 3 days during the week.",
"Are you a supermodel or rockstar that received a custom Credits code? Claim it here.": "Are you a supermodel or rockstar that received a custom Credits code? Claim it here.",

"Default action when clicking a playlist.": "Default action when clicking a playlist.",
"Default playlist action": "Default playlist action",

"--end--": "--end--"
}
3 changes: 3 additions & 0 deletions ui/component/claimMenuList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from 'redux/selectors/collections';
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
import * as COLLECTIONS_CONSTS from 'constants/collections';
import * as SETTINGS from 'constants/settings';
import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked';
import { doOpenModal } from 'redux/actions/app';
Expand All @@ -31,6 +32,7 @@ import { doToast } from 'redux/actions/notifications';
import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions';
import { selectIsSubscribedForUri } from 'redux/selectors/subscriptions';
import { selectIsProtectedContentLockedFromUserForId } from 'redux/selectors/memberships';
import { selectClientSetting } from 'redux/selectors/settings';
import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { makeSelectFileRenderModeForUri } from 'redux/selectors/content';
import { doEnableCollectionShuffle, doFetchUriAccessKey, doPlaylistAddAndAllowPlaying } from 'redux/actions/content';
Expand Down Expand Up @@ -97,6 +99,7 @@ const select = (state, props) => {
collectionEmpty: selectCollectionIsEmptyForId(state, collectionId),
isContentProtectedAndLocked:
contentClaim && selectIsProtectedContentLockedFromUserForId(state, contentClaim.claim_id),
defaultCollectionAction: selectClientSetting(state, SETTINGS.DEFAULT_COLLECTION_ACTION),
};
};

Expand Down
17 changes: 13 additions & 4 deletions ui/component/claimMenuList/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Props = {
collectionEmpty: boolean,
doPlaylistAddAndAllowPlaying: (params: { uri: string, collectionName: string, collectionId: string }) => void,
isContentProtectedAndLocked: boolean,
defaultCollectionAction: string,
doFetchUriAccessKey: (uri: string) => Promise<?UriAccessKey>,
};

Expand Down Expand Up @@ -120,6 +121,7 @@ function ClaimMenuList(props: Props) {
collectionEmpty,
doPlaylistAddAndAllowPlaying,
isContentProtectedAndLocked,
defaultCollectionAction,
doFetchUriAccessKey,
} = props;

Expand Down Expand Up @@ -432,10 +434,17 @@ function ClaimMenuList(props: Props) {
className="comment__menu-option"
onSelect={() => push(`/$/${PAGES.PLAYLIST}/${collectionId}`)}
>
<a className="menu__link" href={`/$/${PAGES.PLAYLIST}/${collectionId}`}>
<Icon aria-hidden icon={ICONS.VIEW} />
{__('View Playlist')}
</a>
{defaultCollectionAction !== COLLECTIONS_CONSTS.DEFAULT_ACTION_VIEW ? (
<a className="menu__link" href={`/$/${PAGES.PLAYLIST}/${collectionId}`}>
<Icon aria-hidden icon={ICONS.VIEW} />
{__('View Playlist')}
</a>
) : (
<a className="menu__link" href={`/$/${PAGES.PLAYLIST}/${collectionId}`}>
<Icon aria-hidden icon={ICONS.PLAY} />
{__('Play')}
</a>
)}
</MenuItem>
{!collectionEmpty && (
<MenuItem
Expand Down
4 changes: 3 additions & 1 deletion ui/component/claimPreview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ import { doResolveUri } from 'redux/actions/claims';
import { doFileGetForUri } from 'redux/actions/file';
import { selectBanStateForUri } from 'lbryinc';
import { selectIsActiveLivestreamForUri } from 'redux/selectors/livestream';
import { selectLanguage, selectShowMatureContent } from 'redux/selectors/settings';
import { selectLanguage, selectShowMatureContent, selectClientSetting } from 'redux/selectors/settings';
import { makeSelectHasVisitedUri } from 'redux/selectors/content';
import { selectIsSubscribedForUri } from 'redux/selectors/subscriptions';
import { isClaimNsfw, isStreamPlaceholderClaim } from 'util/claim';
import ClaimPreview from './view';
import formatMediaDuration from 'util/formatMediaDuration';
import { doClearContentHistoryUri, doPlayNextUri } from 'redux/actions/content';
import * as SETTINGS from 'constants/settings';

const select = (state, props) => {
const claim = props.uri && selectClaimForUri(state, props.uri);
Expand Down Expand Up @@ -57,6 +58,7 @@ const select = (state, props) => {
title: props.uri && selectTitleForUri(state, props.uri),
firstCollectionItemUrl: claim && isCollection && selectFirstItemUrlForCollection(state, claim.claim_id),
thumbnailFromClaim: selectThumbnailForUri(state, props.uri),
defaultCollectionAction: selectClientSetting(state, SETTINGS.DEFAULT_COLLECTION_ACTION),
};
};

Expand Down
10 changes: 8 additions & 2 deletions ui/component/claimPreview/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { lazyImport } from 'util/lazyImport';
import classnames from 'classnames';
import { isURIValid } from 'util/lbryURI';
import * as COLLECTIONS_CONSTS from 'constants/collections';
import * as PAGES from 'constants/pages';
import { COLLECTION_PAGE } from 'constants/urlParams';
import { isChannelClaim } from 'util/claim';
import { isClaimAllowedForCollection } from 'util/collections';
Expand Down Expand Up @@ -112,6 +113,7 @@ type Props = {
doPlayNextUri: (params: { uri: string }) => void,
doDisablePlayerDrag?: (disable: boolean) => void,
thumbnailFromClaim: string,
defaultCollectionAction: string,
};

const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
Expand Down Expand Up @@ -187,6 +189,7 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
doPlayNextUri,
doDisablePlayerDrag,
thumbnailFromClaim,
defaultCollectionAction,
} = props;

const isEmbed = React.useContext(EmbedContext);
Expand Down Expand Up @@ -257,9 +260,12 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {

const ariaLabelData = isChannelUri ? title : formatClaimPreviewTitle(title, channelTitle, date, mediaDuration);

const navigateUrl = formatLbryUrlForWeb((claim && claim.canonical_url) || uri || '/');
const navigateUrl =
listId && defaultCollectionAction === COLLECTIONS_CONSTS.DEFAULT_ACTION_VIEW
? `/$/${PAGES.PLAYLIST}/${listId}`
: formatLbryUrlForWeb((claim && claim.canonical_url) || uri || '/');
let navigateSearch = new URLSearchParams();
if (listId) {
if (listId && defaultCollectionAction !== COLLECTIONS_CONSTS.DEFAULT_ACTION_VIEW) {
navigateSearch.set(COLLECTIONS_CONSTS.COLLECTION_ID, listId);
}
if (searchParams) {
Expand Down
4 changes: 3 additions & 1 deletion ui/component/claimPreviewTile/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { connect } from 'react-redux';
import * as SETTINGS from 'constants/settings';
import {
selectClaimForUri,
selectIsUriResolving,
Expand All @@ -11,7 +12,7 @@ import { doFileGetForUri } from 'redux/actions/file';
import { selectViewCountForUri, selectBanStateForUri } from 'lbryinc';
import { selectStreamingUrlForUri } from 'redux/selectors/file_info';
import { selectIsActiveLivestreamForUri } from 'redux/selectors/livestream';
import { selectShowMatureContent } from 'redux/selectors/settings';
import { selectShowMatureContent, selectClientSetting } from 'redux/selectors/settings';
import { selectFirstItemUrlForCollection } from 'redux/selectors/collections';
import { isClaimNsfw, isStreamPlaceholderClaim } from 'util/claim';
import ClaimPreviewTile from './view';
Expand Down Expand Up @@ -41,6 +42,7 @@ const select = (state, props) => {
isLivestreamActive: isLivestream && selectIsActiveLivestreamForUri(state, props.uri),
viewCount: selectViewCountForUri(state, props.uri),
firstCollectionItemUrl: claim && isCollection && selectFirstItemUrlForCollection(state, claim.claim_id),
defaultCollectionAction: selectClientSetting(state, SETTINGS.DEFAULT_COLLECTION_ACTION),
};
};

Expand Down
14 changes: 10 additions & 4 deletions ui/component/claimPreviewTile/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import classnames from 'classnames';
import { NavLink, withRouter } from 'react-router-dom';
import { ChannelPageContext } from 'contexts/channel';
import * as COLLECTIONS from 'constants/collections';
import ClaimPreviewProgress from 'component/claimPreviewProgress';
import FileThumbnail from 'component/fileThumbnail';
import UriIndicator from 'component/uriIndicator';
Expand All @@ -24,6 +25,7 @@ import ClaimRepostAuthor from 'component/claimRepostAuthor';
import ClaimMenuList from 'component/claimMenuList';
import CollectionPreviewOverlay from 'component/collectionPreviewOverlay';
import { FYP_ID } from 'constants/urlParams';
import * as PAGES from 'constants/pages';
import { EmbedContext } from 'contexts/embed';

type Props = {
Expand Down Expand Up @@ -53,6 +55,7 @@ type Props = {
isLivestreamActive: boolean,
pulse?: boolean,
firstCollectionItemUrl: ?string,
defaultCollectionAction: string,
onlyThumb?: boolean,
onClickHandledByParent?: boolean,
};
Expand Down Expand Up @@ -86,6 +89,7 @@ function ClaimPreviewTile(props: Props) {
viewCount,
pulse,
firstCollectionItemUrl,
defaultCollectionAction,
onlyThumb,
onClickHandledByParent,
} = props;
Expand All @@ -102,11 +106,13 @@ function ClaimPreviewTile(props: Props) {
const thumbnailUrl = useGetThumbnail(uri, claim, streamingUrl, getFile, placeholder);
const canonicalUrl = claim && claim.canonical_url;
const repostedContentUri = claim && (claim.reposted_claim ? claim.reposted_claim.permanent_url : claim.permanent_url);
const listId = collectionId || collectionClaimId;
const listId = collectionId || collectionClaimId || '';
const navigateUrl =
formatLbryUrlForWeb(canonicalUrl || uri || '/') +
(listId ? generateListSearchUrlParams(listId) : '') +
(fypId ? `?${FYP_ID}=${fypId}` : ''); // sigh...
isCollection && defaultCollectionAction === COLLECTIONS.DEFAULT_ACTION_VIEW
? `/$/${PAGES.PLAYLIST}/${listId}`
: formatLbryUrlForWeb(canonicalUrl || uri || '/') +
(listId ? generateListSearchUrlParams(listId) : '') +
(fypId ? `?${FYP_ID}=${fypId}` : ''); // sigh...
const navLinkProps = {
to: navigateUrl,
onClick: (e) => {
Expand Down
1 change: 1 addition & 0 deletions ui/component/settingContent/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const select = (state, props) => ({
hideMembersOnlyContent: selectClientSetting(state, SETTINGS.HIDE_MEMBERS_ONLY_CONTENT),
hideReposts: selectClientSetting(state, SETTINGS.HIDE_REPOSTS),
hideShorts: selectClientSetting(state, SETTINGS.HIDE_SHORTS),
defaultCollectionAction: selectClientSetting(state, SETTINGS.DEFAULT_COLLECTION_ACTION),
showNsfw: selectShowMatureContent(state),
instantPurchaseEnabled: selectClientSetting(state, SETTINGS.INSTANT_PURCHASE_ENABLED),
instantPurchaseMax: selectClientSetting(state, SETTINGS.INSTANT_PURCHASE_MAX),
Expand Down
21 changes: 21 additions & 0 deletions ui/component/settingContent/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import React from 'react';
import * as SETTINGS from 'constants/settings';
import * as COLLECTIONS from 'constants/collections';
import { Lbryio } from 'lbryinc';
import { SIMPLE_SITE } from 'config';
import * as MODALS from 'constants/modal_types';
Expand All @@ -24,6 +25,7 @@ type Props = {
hideMembersOnlyContent: boolean,
hideReposts: ?boolean,
hideShorts: ?boolean,
defaultCollectionAction: string,
showNsfw: boolean,
instantPurchaseEnabled: boolean,
instantPurchaseMax: Price,
Expand All @@ -39,6 +41,7 @@ export default function SettingContent(props: Props) {
hideMembersOnlyContent,
hideReposts,
hideShorts,
defaultCollectionAction,
showNsfw,
instantPurchaseEnabled,
instantPurchaseMax,
Expand Down Expand Up @@ -89,6 +92,23 @@ export default function SettingContent(props: Props) {
/>
</SettingsRow>

<SettingsRow title={__('Default playlist action')} subtitle={__(HELP.DEFAULT_PLAYLIST_ACTION)}>
<fieldset-section>
<FormField
name="default_playlist_action_select"
type="select"
onChange={(e) => setClientSetting(SETTINGS.DEFAULT_COLLECTION_ACTION, e.target.value)}
value={defaultCollectionAction}
>
{COLLECTIONS.DEFAULT_COLLECTION_ACTIONS.map((action) => (
<option key={action} value={action}>
{action === COLLECTIONS.DEFAULT_ACTION_VIEW ? __('View') : __('Play')}
</option>
))}
</FormField>
</fieldset-section>
</SettingsRow>

{!SIMPLE_SITE && (
<>
<SettingsRow title={__('Show mature content')} subtitle={__(HELP.SHOW_MATURE)}>
Expand Down Expand Up @@ -181,6 +201,7 @@ const HELP = {
HIDE_MEMBERS_ONLY_CONTENT: 'You will not see content that requires a membership subscription.',
HIDE_REPOSTS: 'You will not see reposts by people you follow or receive email notifying about them.',
HIDE_SHORTS: 'You will not see content under 1min long. Also hides non-video/audio content.',
DEFAULT_PLAYLIST_ACTION: 'Default action when clicking a playlist.',
HIDE_FYP: 'You will not see the personal recommendations in the homepage.',
SHOW_MATURE: 'Mature content may include nudity, intense sexuality, profanity, or other adult content. By displaying mature content, you are affirming you are of legal age to view mature content in your country or jurisdiction. ',
MAX_PURCHASE_PRICE: 'This will prevent you from purchasing any content over a certain cost, as a safety measure.',
Expand Down
5 changes: 5 additions & 0 deletions ui/constants/collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,8 @@ export const SORT_VALUES = Object.freeze({
});

export const DEFAULT_SORT = { key: 'name', value: SORT_ORDER.ASC };

export const DEFAULT_ACTION_PLAY = 'defaultCollectionActionPlay';
export const DEFAULT_ACTION_VIEW = 'defaultCollectionActionView';

export const DEFAULT_COLLECTION_ACTIONS = [DEFAULT_ACTION_PLAY, DEFAULT_ACTION_VIEW];
1 change: 1 addition & 0 deletions ui/constants/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const HOMEPAGE_ORDER_APPLY_TO_SIDEBAR = 'homepage_order_apply_to_sidebar'
export const HIDE_MEMBERS_ONLY_CONTENT = 'hide_members_only_content';
export const HIDE_REPOSTS = 'hide_reposts';
export const HIDE_SHORTS = 'hide_shorts';
export const DEFAULT_COLLECTION_ACTION = 'default_collection_action';
export const SHORTS_DURATION_LIMIT = '61';
export const HIDE_SCHEDULED_LIVESTREAMS = 'hide_scheduled_livestreams';
export const SUPPORT_OPTION = 'support_option';
Expand Down
2 changes: 2 additions & 0 deletions ui/constants/shared_preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const CLIENT_SYNC_KEYS = [
SETTINGS.SHOW_MATURE,
SETTINGS.HIDE_MEMBERS_ONLY_CONTENT,
SETTINGS.HIDE_REPOSTS,
SETTINGS.HIDE_SHORTS,
SETTINGS.DEFAULT_COLLECTION_ACTION,
SETTINGS.HIDE_SCHEDULED_LIVESTREAMS,
SETTINGS.SHOW_ANONYMOUS,
SETTINGS.INSTANT_PURCHASE_ENABLED,
Expand Down
2 changes: 2 additions & 0 deletions ui/redux/reducers/settings.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import * as ACTIONS from 'constants/action_types';
import * as SETTINGS from 'constants/settings';
import * as COLLECTIONS from 'constants/collections';
import * as SHARED_PREFERENCES from 'constants/shared_preferences';
import moment from 'moment';
import { getSubsetFromKeysArray } from 'util/sync-settings';
Expand Down Expand Up @@ -71,6 +72,7 @@ const defaultState = {
[SETTINGS.AUTO_DOWNLOAD]: true,
[SETTINGS.HIDE_MEMBERS_ONLY_CONTENT]: false,
[SETTINGS.HIDE_REPOSTS]: false,
[SETTINGS.DEFAULT_COLLECTION_ACTION]: COLLECTIONS.DEFAULT_ACTION_VIEW,
[SETTINGS.HIDE_SCHEDULED_LIVESTREAMS]: false,
[SETTINGS.DEFAULT_VIDEO_QUALITY]: null,

Expand Down

0 comments on commit ce707b0

Please sign in to comment.