From ca116ba0104ecd86b8b01c40091c264a18b7785b Mon Sep 17 00:00:00 2001 From: zeppi Date: Sat, 6 Feb 2021 02:03:51 -0500 Subject: [PATCH] wip wip wip - everything but publish, autoplay, and styling collection publishing add channel to collection publish cleanup wip bump clear mass add after success move collection item management controls redirect replace to published collection id bump playlist selector on create bump use new collection add ui element bump wip gitignore add content json wip bump context add to playlist basic collections page style pass wip wip: edits, buttons, styles... change fileAuthor to claimAuthor update, pending bugfixes, delete modal progress, collection header, other bugfixes bump cleaning show page bugfix builtin collection headers no playlists, no grid title wip style tweaks use normal looking claim previews for collection tiles add collection changes style library previews collection menulist for delete/view on library delete modal works for unpublished rearrange collection publish tabs clean up collection publishing and items show on odysee begin collectoin edit header and css renaming better thumbnails bump fix collection publish redirect view collection in menu does something copy and thumbs list previews, pending, context menus, list page enter to add collection, lists page empty state playable lists only, delete feature, bump put fileListDownloaded back better collection titles improve collection claim details fix horiz more icon fix up channel page style, copy, bump refactor preview overlay properties, fix reposts showing as floppydisk add watch later toast, small overlay properties on wunderbar results, fix collection actions buttons bump cleanup cleaning, refactoring bump preview thumb styling, cleanup support discover page lists search sync, bump bump, fix sync more enforce builtin order for now new lists page empty state try to indicate unpublished edits in lists bump fix autoplay and linting consts, fix autoplay bugs fixes cleanup fix, bump lists experimental ui, fixes refactor listIndex out hack in collection fallback thumb bump --- .gitignore | 4 + package.json | 2 +- static/app-strings.json | 30 ++ ui/component/app/index.js | 3 +- ui/component/app/view.jsx | 5 +- ui/component/autoplayCountdown/index.js | 19 +- ui/component/autoplayCountdown/view.jsx | 15 +- ui/component/channelContent/view.jsx | 28 +- ui/component/claimAbandonButton/view.jsx | 15 +- .../{fileAuthor => claimAuthor}/index.js | 4 +- .../{fileAuthor => claimAuthor}/view.jsx | 4 +- ui/component/claimCollectionAdd/index.js | 23 + ui/component/claimCollectionAdd/view.jsx | 133 ++++++ .../claimCollectionAddButton/index.js | 12 + .../claimCollectionAddButton/view.jsx | 40 ++ ui/component/claimList/index.js | 4 +- ui/component/claimList/view.jsx | 4 + ui/component/claimListHeader/view.jsx | 51 +- ui/component/claimMenuList/index.js | 42 +- ui/component/claimMenuList/view.jsx | 112 ++++- ui/component/claimPreview/index.js | 8 + ui/component/claimPreview/view.jsx | 115 ++++- ui/component/claimPreviewTile/view.jsx | 40 +- .../index.js | 7 +- ui/component/claimProperties/view.jsx | 38 ++ ui/component/claimTags/view.jsx | 2 +- ui/component/claimType/index.js | 10 + ui/component/claimType/view.jsx | 29 ++ ui/component/collectionActions/index.js | 30 ++ ui/component/collectionActions/view.jsx | 130 ++++++ .../collectionContentSidebar/index.js | 24 + .../collectionContentSidebar/view.jsx | 42 ++ ui/component/collectionEdit/index.js | 53 +++ ui/component/collectionEdit/view.jsx | 441 ++++++++++++++++++ ui/component/collectionMenuList/index.js | 16 + ui/component/collectionMenuList/view.jsx | 59 +++ .../collectionPreviewOverlay/index.js | 30 ++ .../collectionPreviewOverlay/view.jsx | 42 ++ .../collectionPreviewTile/collectionCount.jsx | 19 + .../collectionPrivate.jsx | 14 + ui/component/collectionPreviewTile/index.js | 58 +++ ui/component/collectionPreviewTile/view.jsx | 174 +++++++ ui/component/collectionSelectItem/index.js | 24 + ui/component/collectionSelectItem/view.jsx | 59 +++ ui/component/collectionsListMine/index.js | 17 + ui/component/collectionsListMine/view.jsx | 91 ++++ ui/component/common/card.jsx | 2 +- ui/component/common/icon-custom.jsx | 69 ++- ui/component/common/icon.jsx | 2 +- ui/component/fileActions/index.js | 3 + ui/component/fileActions/view.jsx | 4 + ui/component/fileDescription/view.jsx | 19 +- ui/component/fileDetails/view.jsx | 4 +- ui/component/fileProperties/view.jsx | 44 -- ui/component/fileReactions/view.jsx | 10 +- ui/component/fileRenderInitiator/index.js | 6 +- ui/component/fileThumbnail/view.jsx | 13 + ui/component/fileTitleSection/view.jsx | 4 +- ui/component/fileType/view.jsx | 13 +- ui/component/inviteNew/index.js | 6 +- ui/component/postViewer/view.jsx | 4 +- .../previewOverlayProperties/index.js | 23 + .../previewOverlayProperties/view.jsx | 75 +++ ui/component/router/view.jsx | 4 + ui/component/selectAsset/view.jsx | 145 +++--- ui/component/sideNavigation/index.js | 4 +- ui/component/sideNavigation/view.jsx | 24 +- ui/component/socialShare/view.jsx | 4 +- ui/component/thumbnailPicker/index.js | 13 + .../thumbnailPicker/thumbnail-broken.png | Bin 0 -> 6680 bytes .../thumbnailPicker/thumbnail-missing.png | Bin 0 -> 2791 bytes ui/component/thumbnailPicker/view.jsx | 116 +++++ ui/component/transactionListTable/view.jsx | 2 +- ui/component/wunderbarSuggestion/view.jsx | 21 +- ui/constants/claim_search.js | 5 +- ui/constants/collections.js | 2 + ui/constants/icons.js | 2 + ui/constants/modal_types.js | 2 + ui/constants/pages.js | 2 + ui/constants/user.js | 26 ++ ui/effects/use-get-thumbnail.js | 3 + ui/modal/modalClaimCollectionAdd/index.js | 11 + ui/modal/modalClaimCollectionAdd/view.jsx | 19 + ui/modal/modalRemoveCollection/index.js | 29 ++ ui/modal/modalRemoveCollection/view.jsx | 65 +++ ui/modal/modalRouter/view.jsx | 6 + ui/page/channel/view.jsx | 46 +- ui/page/collection/index.js | 57 +++ ui/page/collection/view.jsx | 175 +++++++ ui/page/file/index.js | 5 + ui/page/file/view.jsx | 20 +- ui/page/fileListDownloaded/view.jsx | 2 +- ui/page/lists/index.js | 31 ++ ui/page/lists/view.jsx | 22 + ui/page/show/index.js | 22 +- ui/page/show/view.jsx | 37 +- ui/reducers.js | 3 +- ui/redux/actions/app.js | 2 + ui/redux/selectors/user.js | 96 ++-- ui/scss/all.scss | 1 + ui/scss/component/_button.scss | 31 +- ui/scss/component/_card.scss | 31 +- ui/scss/component/_claim-list.scss | 98 ++++ ui/scss/component/_collection.scss | 133 ++++++ ui/scss/component/_icon.scss | 4 + ui/scss/component/section.scss | 4 + ui/scss/init/_gui.scss | 34 ++ ui/store.js | 11 + ui/util/publish.js | 21 + web/src/routes.js | 22 +- yarn.lock | 4 +- 111 files changed, 3504 insertions(+), 336 deletions(-) rename ui/component/{fileAuthor => claimAuthor}/index.js (71%) rename ui/component/{fileAuthor => claimAuthor}/view.jsx (87%) create mode 100644 ui/component/claimCollectionAdd/index.js create mode 100644 ui/component/claimCollectionAdd/view.jsx create mode 100644 ui/component/claimCollectionAddButton/index.js create mode 100644 ui/component/claimCollectionAddButton/view.jsx rename ui/component/{fileProperties => claimProperties}/index.js (54%) create mode 100644 ui/component/claimProperties/view.jsx create mode 100644 ui/component/claimType/index.js create mode 100644 ui/component/claimType/view.jsx create mode 100644 ui/component/collectionActions/index.js create mode 100644 ui/component/collectionActions/view.jsx create mode 100644 ui/component/collectionContentSidebar/index.js create mode 100644 ui/component/collectionContentSidebar/view.jsx create mode 100644 ui/component/collectionEdit/index.js create mode 100644 ui/component/collectionEdit/view.jsx create mode 100644 ui/component/collectionMenuList/index.js create mode 100644 ui/component/collectionMenuList/view.jsx create mode 100644 ui/component/collectionPreviewOverlay/index.js create mode 100644 ui/component/collectionPreviewOverlay/view.jsx create mode 100644 ui/component/collectionPreviewTile/collectionCount.jsx create mode 100644 ui/component/collectionPreviewTile/collectionPrivate.jsx create mode 100644 ui/component/collectionPreviewTile/index.js create mode 100644 ui/component/collectionPreviewTile/view.jsx create mode 100644 ui/component/collectionSelectItem/index.js create mode 100644 ui/component/collectionSelectItem/view.jsx create mode 100644 ui/component/collectionsListMine/index.js create mode 100644 ui/component/collectionsListMine/view.jsx delete mode 100644 ui/component/fileProperties/view.jsx create mode 100644 ui/component/previewOverlayProperties/index.js create mode 100644 ui/component/previewOverlayProperties/view.jsx create mode 100644 ui/component/thumbnailPicker/index.js create mode 100644 ui/component/thumbnailPicker/thumbnail-broken.png create mode 100644 ui/component/thumbnailPicker/thumbnail-missing.png create mode 100644 ui/component/thumbnailPicker/view.jsx create mode 100644 ui/constants/collections.js create mode 100644 ui/constants/user.js create mode 100644 ui/modal/modalClaimCollectionAdd/index.js create mode 100644 ui/modal/modalClaimCollectionAdd/view.jsx create mode 100644 ui/modal/modalRemoveCollection/index.js create mode 100644 ui/modal/modalRemoveCollection/view.jsx create mode 100644 ui/page/collection/index.js create mode 100644 ui/page/collection/view.jsx create mode 100644 ui/page/lists/index.js create mode 100644 ui/page/lists/view.jsx create mode 100644 ui/scss/component/_collection.scss create mode 100644 ui/util/publish.js diff --git a/.gitignore b/.gitignore index c7c46d6fb..0c609ba47 100644 --- a/.gitignore +++ b/.gitignore @@ -23,8 +23,12 @@ package-lock.json /web/.env.defaults /custom/* /custom/homepages/* +/custom/content/* +!/custom/content/default.json +!/custom/content/test.json !/custom/homepages/.gitkeep !/custom/homepages +!/custom/content !/custom/homepage.example.js !/custom/robots.disallowall !/custom/robots.allowall diff --git a/package.json b/package.json index 95ed3570b..e1e3abab0 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "imagesloaded": "^4.1.4", "json-loader": "^0.5.4", "lbry-format": "https://github.com/lbryio/lbry-format.git", - "lbry-redux": "lbryio/lbry-redux#ecfcc95bebbdbe303b3ea065134457a5e168fb89", + "lbry-redux": "lbryio/lbry-redux#5cd9e7601cdc1c81b8d0e2d2f02e9b9d2fb86575", "lbryinc": "lbryio/lbryinc#8f9a58bfc8312a65614fd7327661cdcc502c4e59", "lint-staged": "^7.0.2", "localforage": "^1.7.1", diff --git a/static/app-strings.json b/static/app-strings.json index f97094da7..b6dafae38 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -1917,5 +1917,35 @@ "Set to current date and time": "Set to current date and time", "Remove custom release date": "Remove custom release date", "%SITE_NAME% login": "%SITE_NAME% login", + "Lists": "Lists", + "Watch Later": "Watch Later", + "Add to Lists": "Add to Lists", + "Nothing in %collection_name%": "Nothing in %collection_name%", + "Playlists": "Playlists", + "Edit List": "Edit List", + "Delete List": "Delete List", + "Private": "Private", + "View List": "View List", + "Delete Collection": "Delete Collection", + "Info": "Info", + "Publishes": "Publishes", + "Add To...": "Add To...", + "Unpublished Edits": "Unpublished Edits", + "Report channel": "Report channel", + "List": "List", + "Items": "Items", + "Credits": "Credits", + "MyAwesomeCollection": "MyAwesomeCollection", + "My Awesome Collection": "My Awesome Collection", + "This collection has no items.": "This collection has no items.", + "Select File": "Select File", + "File Selected": "File Selected", + "Url": "Url", + "URL Selected": "URL Selected", + "Keep": "Keep", + "Add this claim to a list": "Add this claim to a list", + "List is Empty": "List is Empty", + "Confirm Collection Unpublish": "Confirm Collection Unpublish", + "This will permanently delete the list.": "This will permanently delete the list.", "--end--": "--end--" } diff --git a/ui/component/app/index.js b/ui/component/app/index.js index 84b62c9f9..16b0cd288 100644 --- a/ui/component/app/index.js +++ b/ui/component/app/index.js @@ -5,7 +5,7 @@ import { selectGetSyncErrorMessage, selectSyncFatalError } from 'redux/selectors import { doFetchAccessToken, doUserSetReferrer } from 'redux/actions/user'; import { selectUser, selectAccessToken, selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUnclaimedRewards } from 'redux/selectors/rewards'; -import { doFetchChannelListMine, selectMyChannelUrls, SETTINGS } from 'lbry-redux'; +import { doFetchChannelListMine, doFetchCollectionListMine, SETTINGS, selectMyChannelUrls } from 'lbry-redux'; import { makeSelectClientSetting, selectLanguage, @@ -52,6 +52,7 @@ const select = (state) => ({ const perform = (dispatch) => ({ fetchAccessToken: () => dispatch(doFetchAccessToken()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()), + fetchCollectionListMine: () => dispatch(doFetchCollectionListMine()), setLanguage: (language) => dispatch(doSetLanguage(language)), signIn: () => dispatch(doSignIn()), requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index c7ecf9475..e4ff246cf 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -61,6 +61,7 @@ type Props = { }, fetchAccessToken: () => void, fetchChannelListMine: () => void, + fetchCollectionListMine: () => void, signIn: () => void, requestDownloadUpgrade: () => void, onSignedIn: () => void, @@ -94,6 +95,7 @@ function App(props: Props) { user, fetchAccessToken, fetchChannelListMine, + fetchCollectionListMine, signIn, autoUpdateDownloaded, isUpgradeAvailable, @@ -233,8 +235,9 @@ function App(props: Props) { // @if TARGET='app' fetchChannelListMine(); // This is fetched after a user is signed in on web + fetchCollectionListMine(); // @endif - }, [appRef, fetchAccessToken, fetchChannelListMine]); + }, [appRef, fetchAccessToken, fetchChannelListMine, fetchCollectionListMine]); useEffect(() => { // $FlowFixMe diff --git a/ui/component/autoplayCountdown/index.js b/ui/component/autoplayCountdown/index.js index 68fdcf135..19134e904 100644 --- a/ui/component/autoplayCountdown/index.js +++ b/ui/component/autoplayCountdown/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri, SETTINGS } from 'lbry-redux'; +import { makeSelectClaimForUri, SETTINGS, COLLECTIONS_CONSTS, makeSelectNextUrlForCollectionAndUrl } from 'lbry-redux'; import { withRouter } from 'react-router'; import { makeSelectIsPlayerFloating, makeSelectNextUnplayedRecommended } from 'redux/selectors/content'; import { makeSelectClientSetting } from 'redux/selectors/settings'; @@ -8,11 +8,24 @@ import AutoplayCountdown from './view'; import { selectModal } from 'redux/selectors/app'; /* -AutoplayCountdown does not fetch it's own next content to play, it relies on being rendered. This is dumb but I'm just the guy who noticed + AutoplayCountdown does not fetch it's own next content to play, it relies on being rendered. + This is dumb but I'm just the guy who noticed -kj */ const select = (state, props) => { - const nextRecommendedUri = makeSelectNextUnplayedRecommended(props.uri)(state); + const { location } = props; + const { search } = location; + const urlParams = new URLSearchParams(search); + const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID); + + let nextRecommendedUri; + if (collectionId) { + nextRecommendedUri = makeSelectNextUrlForCollectionAndUrl(collectionId, props.uri)(state); + } else { + nextRecommendedUri = makeSelectNextUnplayedRecommended(props.uri)(state); + } + return { + collectionId, nextRecommendedUri, nextRecommendedClaim: makeSelectClaimForUri(nextRecommendedUri)(state), isFloating: makeSelectIsPlayerFloating(props.location)(state), diff --git a/ui/component/autoplayCountdown/view.jsx b/ui/component/autoplayCountdown/view.jsx index 587520c1b..5b8df4bd3 100644 --- a/ui/component/autoplayCountdown/view.jsx +++ b/ui/component/autoplayCountdown/view.jsx @@ -6,18 +6,19 @@ import I18nMessage from 'component/i18nMessage'; import { formatLbryUrlForWeb } from 'util/url'; import { withRouter } from 'react-router'; import debounce from 'util/debounce'; - +import { COLLECTIONS_CONSTS } from 'lbry-redux'; const DEBOUNCE_SCROLL_HANDLER_MS = 150; const CLASSNAME_AUTOPLAY_COUNTDOWN = 'autoplay-countdown'; type Props = { - history: { push: string => void }, + history: { push: (string) => void }, nextRecommendedClaim: ?StreamClaim, nextRecommendedUri: string, isFloating: boolean, doSetPlayingUri: ({ uri: ?string }) => void, - doPlayUri: string => void, + doPlayUri: (string) => void, modal: { id: string, modalProps: {} }, + collectionId?: string, }; function AutoplayCountdown(props: Props) { @@ -29,6 +30,7 @@ function AutoplayCountdown(props: Props) { isFloating, history: { push }, modal, + collectionId, } = props; const nextTitle = nextRecommendedClaim && nextRecommendedClaim.value && nextRecommendedClaim.value.title; @@ -44,6 +46,11 @@ function AutoplayCountdown(props: Props) { let navigateUrl; if (nextTitle) { navigateUrl = formatLbryUrlForWeb(nextRecommendedUri); + if (collectionId) { + const collectionParams = new URLSearchParams(); + collectionParams.set(COLLECTIONS_CONSTS.COLLECTION_ID, collectionId); + navigateUrl = navigateUrl + `?` + collectionParams.toString(); + } } const doNavigate = useCallback(() => { @@ -71,7 +78,7 @@ function AutoplayCountdown(props: Props) { // Ensure correct 'setTimerPaused' on initial render. setTimerPaused(shouldPauseAutoplay()); - const handleScroll = debounce(e => { + const handleScroll = debounce((e) => { setTimerPaused(shouldPauseAutoplay()); }, DEBOUNCE_SCROLL_HANDLER_MS); diff --git a/ui/component/channelContent/view.jsx b/ui/component/channelContent/view.jsx index 10494a9a8..109804984 100644 --- a/ui/component/channelContent/view.jsx +++ b/ui/component/channelContent/view.jsx @@ -32,6 +32,7 @@ type Props = { tileLayout: boolean, viewHiddenChannels: boolean, doResolveUris: (Array, boolean) => void, + claimType: string, }; function ChannelContent(props: Props) { @@ -49,6 +50,7 @@ function ChannelContent(props: Props) { tileLayout, viewHiddenChannels, doResolveUris, + claimType, } = props; const claimsInChannel = (claim && claim.meta.claims_in_channel) || 0; const [searchQuery, setSearchQuery] = React.useState(''); @@ -58,6 +60,7 @@ function ChannelContent(props: Props) { } = useHistory(); const url = `${pathname}${search}`; const claimId = claim && claim.claim_id; + const showFilters = !claimType || claimType === 'stream'; function handleInputChange(e) { const { value } = e.target; @@ -134,25 +137,30 @@ function ChannelContent(props: Props) { } meta={ -
{}} className="wunderbar--inline"> - - - + showFilters && ( +
{}} className="wunderbar--inline"> + + + + ) } isChannel channelIsMine={channelIsMine} diff --git a/ui/component/claimAbandonButton/view.jsx b/ui/component/claimAbandonButton/view.jsx index 469771495..b7ce4291d 100644 --- a/ui/component/claimAbandonButton/view.jsx +++ b/ui/component/claimAbandonButton/view.jsx @@ -6,13 +6,22 @@ import Button from 'component/button'; type Props = { doOpenModal: (string, {}) => void, - claim: StreamClaim, - abandonActionCallback: any => void, + claim: Claim, + abandonActionCallback: (any) => void, iconSize: number, }; export default function ClaimAbandonButton(props: Props) { const { doOpenModal, claim, abandonActionCallback } = props; + const { value_type } = claim || {}; + let buttonLabel; + if (value_type === 'channel') { + buttonLabel = __('Delete Channel'); + } else if (value_type === 'collection') { + buttonLabel = __('Delete List'); + } else if (value_type === 'stream') { + buttonLabel = __('Delete Publish'); + } function abandonClaim() { doOpenModal(MODALS.CONFIRM_CLAIM_REVOKE, { claim: claim, cb: abandonActionCallback }); @@ -21,7 +30,7 @@ export default function ClaimAbandonButton(props: Props) { return (