Skip to content

Commit

Permalink
Playlists v2: Refactors, touch ups + Queue Mode (#1604)
Browse files Browse the repository at this point in the history
* Playlists v2

* Style pass

* Change playlist items arrange icon

* Playlist card body open by default

* Refactor collectionEdit components

* Paginate & Refactor bid field

* Collection page changes

* Add Thumbnail optional

* Replace extra info for description on collection page

* Playlist card right below video on medium screen

* Allow editing private collections

* Add edit option to menus

* Allow deleting a public playlist but keeping a private version

* Add queue to Save menu, remove edit option from Builtin pages, show queue on playlists page

* Fix scroll to recent persisting on medium screen

* Fix adding to queue from menu

* Fixes for delete

* PublishList: delay mounting Items tab to prevent lock-up (#1783)

For a large list, the playlist publish form is unusable (super-slow typing) due to the entire list being mounted despite the tab is not active.
The full solution is still to paginate it, but for now, don't mount the tab until it is selected. Add a spinner to indicate something is loading. It's not prefect, but it's throwaway code anyway. At least we can fill in the fields properly now.

* Batch-resolve private collections (#1782)

* makeSelectClaimForClaimId --> selectClaimForClaimId

Move away from the problematic `makeSelect*`, especially in large loops.

* Batch-resolve private collections
1758

This alleviates the lock-up that is caused by large number of invidual resolves. There will still be some minor stutter due to the large DOM that React needs to handle -- that is logged in 1758 and will be handled separately.

At least the stutter is short (1-2s) and the app is still usable.
Private list items are being resolve individually, super slow if the list is large (>100). Published lists doesn't have this issue.
doFetchItemsInCollections contains most of the useful logic, but it isn't called for private/built-in lists because it's not an actual claim.
Tweaked doFetchItemsInCollections to handle private (UUID-based) collections.

* Use persisted state for floating player playlist card body
- I find it annoying being open everytime

* Fix removing edits from published playlist

* Fix scroll on mobile

* Allow going editing items from toast

* Fix ClaimShareButton

* Prevent edit/publish of builtin

* Fix async inside forEach

* Fix sync on queue edit

* Fix autoplayCountdown replay

* Fix deleting an item scrolling the playlist

* CreatedAt fixes

* Remove repost for now

* Anon publish fixes

* Fix mature case on floating

Co-authored-by: infinite-persistence <[email protected]>
  • Loading branch information
rafael-xmr and infinite-persistence authored Jul 13, 2022
1 parent 5863ea8 commit 83dbe8e
Show file tree
Hide file tree
Showing 240 changed files with 8,225 additions and 3,939 deletions.
31 changes: 16 additions & 15 deletions extras/lbryinc/redux/actions/cost_info.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,33 @@ import { selectClaimForUri } from 'redux/selectors/claims';

// eslint-disable-next-line import/prefer-default-export
export function doFetchCostInfoForUri(uri: string) {
return (dispatch: Dispatch, getState: GetState) => {
return async (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const claim = selectClaimForUri(state, uri);

if (!claim) return;

function resolve(costInfo) {
dispatch({
type: ACTIONS.FETCH_COST_INFO_COMPLETED,
data: {
uri,
costInfo,
},
});
}

const fee = claim.value ? claim.value.fee : undefined;

let costInfo;
if (fee === undefined) {
resolve({ cost: 0, includesData: true });
costInfo = { cost: 0, includesData: true };
} else if (fee.currency === 'LBC') {
resolve({ cost: fee.amount, includesData: true });
costInfo = { cost: fee.amount, includesData: true };
} else {
Lbryio.getExchangeRates().then(({ LBC_USD }) => {
resolve({ cost: fee.amount / LBC_USD, includesData: true });
await Lbryio.getExchangeRates().then(({ LBC_USD }) => {
costInfo = { cost: fee.amount / LBC_USD, includesData: true };
});
}

dispatch({
type: ACTIONS.FETCH_COST_INFO_COMPLETED,
data: {
uri,
costInfo,
},
});

return costInfo;
};
}
34 changes: 32 additions & 2 deletions flow-typed/Collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ declare type Collection = {
id: string,
items: Array<?string>,
name: string,
description?: string,
thumbnail?: {
url?: string,
},
type: string,
createdAt?: ?number,
updatedAt: number,
totalItems?: number,
itemCount?: number,
editsCleared?: boolean,
sourceId?: string, // if copied, claimId of original collection
};

Expand All @@ -17,11 +24,25 @@ declare type CollectionState = {
saved: Array<string>,
isResolvingCollectionById: { [string]: boolean },
error?: string | null,
queue: Collection,
};

declare type CollectionGroup = {
[string]: Collection,
}
};

declare type CollectionList = Array<Collection>;

declare type CollectionCreateParams = {
name: string,
description?: string,
thumbnail?: {
url?: string,
},
items: ?Array<string>,
type: string,
sourceId?: string, // if copied, claimId of original collection
};

declare type CollectionEditParams = {
uris?: Array<string>,
Expand All @@ -30,4 +51,13 @@ declare type CollectionEditParams = {
order?: { from: number, to: number },
type?: string,
name?: string,
}
description?: string,
thumbnail?: {
url?: string,
},
};

declare type CollectionFetchParams = {
collectionId: string,
pageSize?: number,
};
19 changes: 11 additions & 8 deletions flow-typed/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

declare type ContentState = {
primaryUri: ?string,
playingUri: { uri?: string },
playingUri: {
uri?: string,
collection: PlayingCollection,
},
positions: { [string]: { [string]: number } }, // claimId: { outpoint: position }
history: Array<WatchHistory>,
recommendationId: { [string]: string }, // claimId: recommendationId
recommendationParentId: { [string]: string }, // claimId: referrerId
recommendationUrls: { [string]: Array<string> }, // claimId: [lbryUrls...]
recommendationClicks: { [string]: Array<number> }, // "claimId": [clicked indices...]
loopList?: { collectionId: string, loop: boolean },
shuffleList?: { collectionId: string, newUrls: Array<string> | boolean },
// TODO: it's confusing for newUrls to be a boolean --------- ^^^
// It can/should be '?Array<string>` instead -- set it to null, then clients
// can cast it to a boolean. That, or rename the variable to `shuffle` if you
// don't care about the URLs.
lastViewedAnnouncement: ?string, // undefined = not seen in wallet.
recsysEntries: { [ClaimId]: RecsysEntry }, // Persistent shadow copy. The main one resides in RecSys.
};
Expand All @@ -29,6 +26,12 @@ declare type PlayingUri = {
primaryUri?: string,
pathname?: string,
commentId?: string,
collectionId?: ?string,
collection: PlayingCollection,
source?: string,
};

declare type PlayingCollection = {
collectionId?: ?string,
loop?: ?boolean,
shuffle?: ?{ newUrls: Array<string> },
};
4 changes: 4 additions & 0 deletions flow-typed/notification.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ declare type ToastParams = {
linkTarget?: string,
isError?: boolean,
duration?: 'default' | 'long',
actionText?: string,
action?: () => void,
secondaryActionText?: string,
secondaryAction?: () => void,
};

declare type Toast = {
Expand Down
46 changes: 40 additions & 6 deletions static/app-strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,24 @@
"Tags": "Tags",
"Share": "Share",
"Play": "Play",
"Play All": "Play All",
"Start Playing": "Start Playing",
"Shuffle Play": "Shuffle Play",
"Shuffle": "Shuffle",
"Play in Shuffle mode": "Play in Shuffle mode",
"Loop": "Loop",
"Playlist": "Playlist",
"Visibility": "Visibility",
"Video Count": "Video Count",
"Last updated at": "Last updated at",
"You can add videos to your Playlists": "You can add videos to your Playlists",
"Do you want to find some content to save for later, or create a brand new playlist?": "Do you want to find some content to save for later, or create a brand new playlist?",
"Explore!": "Explore!",
"New Playlist": "New Playlist",
"Showing %filtered% results of %total%": "Showing %filtered% results of %total%",
"%playlist_item_count% item": "%playlist_item_count% item",
"%playlist_item_count% items": "%playlist_item_count% items",
"Published as: %playlist_channel%": "Published as: %playlist_channel%",
"Report content": "Report content",
"Report Content": "Report Content",
"Report comment": "Report comment",
Expand Down Expand Up @@ -1173,6 +1188,7 @@
"Paid": "Paid",
"Start at": "Start at",
"Include List ID": "Include List ID",
"Include Playlist ID": "Include Playlist ID",
"Links": "Links",
"Download Link": "Download Link",
"Mature content is not supported.": "Mature content is not supported.",
Expand Down Expand Up @@ -1775,6 +1791,8 @@
"How does this work?": "How does this work?",
"Introducing Lists": "Introducing Lists",
"You have no lists yet. Better start hoarding!": "You have no lists yet. Better start hoarding!",
"You have no Playlists yet. Better start hoarding!": "You have no Playlists yet. Better start hoarding!",
"Create a Playlist": "Create a Playlist",
"Update your livestream": "Update your livestream",
"Prepare an upcoming livestream": "Prepare an upcoming livestream",
"Edit your post": "Edit your post",
Expand Down Expand Up @@ -1958,15 +1976,17 @@
"Lists": "Lists",
"Watch Later": "Watch Later",
"Favorites": "Favorites",
"New List": "New List",
"New List Title": "New List Title",
"Add to Lists": "Add to Lists",
"Add to Playlist": "Add to Playlist",
"Playlists": "Playlists",
"Edit List": "Edit List",
"Edit Playlist": "Edit Playlist",
"Delete List": "Delete List",
"Delete Playlist": "Delete Playlist",
"Private": "Private",
"Public": "Public",
"View List": "View List",
"View Playlist": "View Playlist",
"Publish List": "Publish List",
"Info": "Info",
"Publishes": "Publishes",
Expand All @@ -1979,7 +1999,7 @@
"Credits": "Credits",
"Cannot publish empty list": "Cannot publish empty list",
"MyAwesomeList": "MyAwesomeList",
"My Awesome List": "My Awesome List",
"My Awesome Playlist": "My Awesome Playlist",
"This list has no items.": "This list has no items.",
"1 item": "1 item",
"%collectionCount% items": "%collectionCount% items",
Expand All @@ -1989,6 +2009,7 @@
"URL Selected": "URL Selected",
"Keep": "Keep",
"Add this claim to a list": "Add this claim to a list",
"Add this video to a playlist": "Add this video to a playlist",
"List is Empty": "List is Empty",
"Confirm List Unpublish": "Confirm List Unpublish",
"This will permanently delete the list.": "This will permanently delete the list.",
Expand All @@ -2003,8 +2024,8 @@
"Remove from Watch Later": "Remove from Watch Later",
"Add to Watch Later": "Add to Watch Later",
"Added": "Added",
"Item removed from %name%": "Item removed from %name%",
"Item added to %name%": "Item added to %name%",
"Item removed from %playlist_name%": "Item removed from %playlist_name%",
"Item added to %playlist_name%": "Item added to %playlist_name%",
"Item added to Watch Later": "Item added to Watch Later",
"Item removed from Watch Later": "Item removed from Watch Later",
"Item added to Favorites": "Item added to Favorites",
Expand Down Expand Up @@ -2135,7 +2156,6 @@
"Sending...": "Sending...",
"Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8": "Enter the full channel name or URL to search.\n\nExamples:\n - @channel\n - @channel#3\n - https://odysee.com/@Odysee:8\n - lbry://@Odysee#8",
"Choose %asset%": "Choose %asset%",
"Showing %filtered% results of %total%": "Showing %filtered% results of %total%",
"filtered": "filtered",
"Failed to synchronize settings. Wait a while before retrying.": "Failed to synchronize settings. Wait a while before retrying.",
"You are offline. Check your internet connection.": "You are offline. Check your internet connection.",
Expand Down Expand Up @@ -2307,5 +2327,19 @@
"Latest Content Link": "Latest Content Link",
"Current Livestream Link": "Current Livestream Link",
"Back to Odysee Premium": "Back to Odysee Premium",
"Add to Queue": "Add to Queue",
"Queue Mode": "Queue Mode",
"Item added to Queue": "Item added to Queue",
"In Queue": "In Queue",
"Now playing: --[Which Playlist is currently playing]--": "Now playing:",
"Private %lock_icon%": "Private %lock_icon%",
"Playlist is Empty": "Playlist is Empty",
"Queue": "Queue",
"Your Playlists": "Your Playlists",
"Default Playlists": "Default Playlists",
"Open": "Open",
"Support this content": "Support this content",
"Repost this content": "Repost this content",
"Share this content": "Share this content",
"--end--": "--end--"
}
11 changes: 8 additions & 3 deletions ui/component/autoplayCountdown/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { connect } from 'react-redux';
import { makeSelectClaimForUri } from 'redux/selectors/claims';
import { withRouter } from 'react-router';
import { makeSelectClaimForUri, selectClaimIsNsfwForUri } from 'redux/selectors/claims';
import AutoplayCountdown from './view';
import { selectModal } from 'redux/selectors/app';
import { doOpenModal } from 'redux/actions/app';

/*
AutoplayCountdown does not fetch it's own next content to play, it relies on <RecommendedContent> being rendered.
Expand All @@ -11,6 +11,11 @@ import { selectModal } from 'redux/selectors/app';
const select = (state, props) => ({
nextRecommendedClaim: makeSelectClaimForUri(props.nextRecommendedUri)(state),
modal: selectModal(state),
isMature: selectClaimIsNsfwForUri(state, props.uri),
});

export default withRouter(connect(select, null)(AutoplayCountdown));
const perform = {
doOpenModal,
};

export default connect(select, perform)(AutoplayCountdown);
Loading

0 comments on commit 83dbe8e

Please sign in to comment.