lbry-desktop/ui/redux/selectors/collections.js

282 lines
9.6 KiB
JavaScript
Raw Normal View History

// @flow
import fromEntries from '@ungap/from-entries';
import { createSelector } from 'reselect';
import { selectMyCollectionIds, makeSelectClaimForUri } from 'redux/selectors/claims';
import { parseURI } from 'util/lbryURI';
import { isClaimPlayable } from 'util/claim';
const selectState = (state: { collections: CollectionState }) => state.collections;
export const selectSavedCollectionIds = createSelector(selectState, (collectionState) => collectionState.saved);
export const selectBuiltinCollections = createSelector(selectState, (state) => state.builtin);
export const selectResolvedCollections = createSelector(selectState, (state) => state.resolved);
export const selectMyUnpublishedCollections = createSelector(selectState, (state) => state.unpublished);
export const selectMyEditedCollections = createSelector(selectState, (state) => state.edited);
export const selectPendingCollections = createSelector(selectState, (state) => state.pending);
export const selectLastUsedCollection = createSelector(selectState, (state) => state.lastUsedCollection);
export const makeSelectEditedCollectionForId = (id: string) =>
createSelector(selectMyEditedCollections, (eLists) => eLists[id]);
export const makeSelectPendingCollectionForId = (id: string) =>
createSelector(selectPendingCollections, (pending) => pending[id]);
export const makeSelectPublishedCollectionForId = (id: string) =>
createSelector(selectResolvedCollections, (rLists) => rLists[id]);
export const makeSelectUnpublishedCollectionForId = (id: string) =>
createSelector(selectMyUnpublishedCollections, (rLists) => rLists[id]);
export const makeSelectCollectionIsMine = (id: string) =>
createSelector(
selectMyCollectionIds,
selectMyUnpublishedCollections,
selectBuiltinCollections,
(publicIds, privateIds, builtinIds) => {
return Boolean(publicIds.includes(id) || privateIds[id] || builtinIds[id]);
}
);
export const selectMyPublishedCollections = createSelector(
selectResolvedCollections,
selectPendingCollections,
selectMyEditedCollections,
selectMyCollectionIds,
(resolved, pending, edited, myIds) => {
// all resolved in myIds, plus those in pending and edited
const myPublishedCollections = fromEntries(
Object.entries(pending).concat(
Object.entries(resolved).filter(
([key, val]) =>
myIds.includes(key) &&
// $FlowFixMe
!pending[key]
)
)
);
// now add in edited:
Object.entries(edited).forEach(([id, item]) => {
myPublishedCollections[id] = item;
});
return myPublishedCollections;
}
);
export const selectMyPublishedMixedCollections = createSelector(selectMyPublishedCollections, (published) => {
const myCollections = fromEntries(
// $FlowFixMe
Object.entries(published).filter(([key, collection]) => {
// $FlowFixMe
return collection.type === 'collection';
})
);
return myCollections;
});
export const selectMyPublishedPlaylistCollections = createSelector(selectMyPublishedCollections, (published) => {
const myCollections = fromEntries(
// $FlowFixMe
Object.entries(published).filter(([key, collection]) => {
// $FlowFixMe
return collection.type === 'playlist';
})
);
return myCollections;
});
export const makeSelectMyPublishedCollectionForId = (id: string) =>
createSelector(selectMyPublishedCollections, (myPublishedCollections) => myPublishedCollections[id]);
// export const selectSavedCollections = createSelector(
// selectResolvedCollections,
// selectSavedCollectionIds,
// (resolved, myIds) => {
// const mySavedCollections = fromEntries(
// Object.entries(resolved).filter(([key, val]) => myIds.includes(key))
// );
// return mySavedCollections;
// }
// );
export const makeSelectIsResolvingCollectionForId = (id: string) =>
createSelector(selectState, (state) => {
return state.isResolvingCollectionById[id];
});
export const makeSelectCollectionForId = (id: string) =>
createSelector(
selectBuiltinCollections,
selectResolvedCollections,
selectMyUnpublishedCollections,
selectMyEditedCollections,
selectPendingCollections,
(bLists, rLists, uLists, eLists, pLists) => {
const collection = bLists[id] || uLists[id] || eLists[id] || pLists[id] || rLists[id];
return collection;
}
);
export const makeSelectClaimUrlInCollection = (url: string) =>
createSelector(
selectBuiltinCollections,
selectMyPublishedCollections,
selectMyUnpublishedCollections,
selectMyEditedCollections,
selectPendingCollections,
(bLists, myRLists, uLists, eLists, pLists) => {
const collections = [bLists, uLists, eLists, myRLists, pLists];
const itemsInCollections = [];
collections.map((list) => {
Object.entries(list).forEach(([key, value]) => {
// $FlowFixMe
value.items.map((item) => {
itemsInCollections.push(item);
});
});
});
return itemsInCollections.includes(url);
}
);
export const makeSelectCollectionForIdHasClaimUrl = (id: string, url: string) =>
createSelector(makeSelectCollectionForId(id), (collection) => collection && collection.items.includes(url));
export const makeSelectUrlsForCollectionId = (id: string) =>
createSelector(makeSelectCollectionForId(id), (collection) => collection && collection.items);
export const makeSelectClaimIdsForCollectionId = (id: string) =>
createSelector(makeSelectCollectionForId(id), (collection) => {
const items = (collection && collection.items) || [];
const ids = items.map((item) => {
const { claimId } = parseURI(item);
return claimId;
});
return ids;
});
Playlistorder (#7442) * Add horizontal layout (#636) * Test out a horizontal scroll for upcoming (tile only for now) * - add support for list layout - add following label on home page - clan up css and naming conventions * Update header type + show only if scheduled streams are showing * [Playlist] Pull in sorting changes from desktop + Add Drag-n-Drop + Handle unavailable/deleted claims (#641) * Add ordering Icons * Refactor doCollectionEdit - It required claims as parameter, when only uris are used to populate the collection, so that was changed to pass down the uris instead. - There were unused and mostly unnecessary functions inside, for example the parameter claimIds was never used so it would never enter the claimSearch function which again would be used to generate uris, so it's better to just use uris as parameter * Add List Reordering changes * Add toggle button for list editing * Add toggle on content page collection sidebar * Enable drag-n-drop to re-order list items https://www.youtube.com/watch?v=aYZRRyukuIw * Allow removing all unavailable claims from a List * Fix <g> on icons * Fix section buttons positioning * Move preventDefault and stopPropagation to buttons div instead of each button, preventing clicking even if disabled opening the claim * Change dragging cursor * Fix sizing * Fix dragging component * Restrict dragging to vertical axis * Ignore shuffle state for ordering * Fix console errors * Mobile fixes * Fix sidebar spacing * Fix grey on mobile after click * cleanup Co-authored-by: Dan Peterson <dan@dan-peterson.ca> Co-authored-by: saltrafael <76502841+saltrafael@users.noreply.github.com>
2022-01-27 16:20:21 +01:00
export const makeSelectIndexForUrlInCollection = (url: string, id: string, ignoreShuffle?: boolean) =>
createSelector(
(state) => state.content.shuffleList,
makeSelectUrlsForCollectionId(id),
makeSelectClaimForUri(url),
(shuffleState, urls, claim) => {
Playlistorder (#7442) * Add horizontal layout (#636) * Test out a horizontal scroll for upcoming (tile only for now) * - add support for list layout - add following label on home page - clan up css and naming conventions * Update header type + show only if scheduled streams are showing * [Playlist] Pull in sorting changes from desktop + Add Drag-n-Drop + Handle unavailable/deleted claims (#641) * Add ordering Icons * Refactor doCollectionEdit - It required claims as parameter, when only uris are used to populate the collection, so that was changed to pass down the uris instead. - There were unused and mostly unnecessary functions inside, for example the parameter claimIds was never used so it would never enter the claimSearch function which again would be used to generate uris, so it's better to just use uris as parameter * Add List Reordering changes * Add toggle button for list editing * Add toggle on content page collection sidebar * Enable drag-n-drop to re-order list items https://www.youtube.com/watch?v=aYZRRyukuIw * Allow removing all unavailable claims from a List * Fix <g> on icons * Fix section buttons positioning * Move preventDefault and stopPropagation to buttons div instead of each button, preventing clicking even if disabled opening the claim * Change dragging cursor * Fix sizing * Fix dragging component * Restrict dragging to vertical axis * Ignore shuffle state for ordering * Fix console errors * Mobile fixes * Fix sidebar spacing * Fix grey on mobile after click * cleanup Co-authored-by: Dan Peterson <dan@dan-peterson.ca> Co-authored-by: saltrafael <76502841+saltrafael@users.noreply.github.com>
2022-01-27 16:20:21 +01:00
const shuffleUrls = !ignoreShuffle && shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
const listUrls = shuffleUrls || urls;
const index = listUrls && listUrls.findIndex((u) => u === url);
if (index > -1) {
return index;
} else if (claim) {
const index = listUrls && listUrls.findIndex((u) => u === claim.permanent_url);
if (index > -1) return index;
return claim;
}
return null;
}
);
export const makeSelectPreviousUrlForCollectionAndUrl = (id: string, url: string) =>
createSelector(
(state) => state.content.shuffleList,
(state) => state.content.loopList,
makeSelectIndexForUrlInCollection(url, id),
makeSelectUrlsForCollectionId(id),
(shuffleState, loopState, index, urls) => {
const loopList = loopState && loopState.collectionId === id && loopState.loop;
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
if (index > -1) {
const listUrls = shuffleUrls || urls;
let nextUrl;
if (index === 0 && loopList) {
nextUrl = listUrls[listUrls.length - 1];
} else {
nextUrl = listUrls[index - 1];
}
return nextUrl || null;
} else {
return null;
}
}
);
export const makeSelectNextUrlForCollectionAndUrl = (id: string, url: string) =>
createSelector(
(state) => state.content.shuffleList,
(state) => state.content.loopList,
makeSelectIndexForUrlInCollection(url, id),
makeSelectUrlsForCollectionId(id),
(shuffleState, loopState, index, urls) => {
const loopList = loopState && loopState.collectionId === id && loopState.loop;
const shuffleUrls = shuffleState && shuffleState.collectionId === id && shuffleState.newUrls;
if (index > -1) {
const listUrls = shuffleUrls || urls;
// We'll get the next playable url
let remainingUrls = listUrls.slice(index + 1);
if (!remainingUrls.length && loopList) {
remainingUrls = listUrls.slice(0);
}
const nextUrl = remainingUrls && remainingUrls[0];
return nextUrl || null;
} else {
return null;
}
}
);
export const makeSelectPrevPlayableUrlFromCollectionAndUrl = (collectionId: string, url: string) =>
createSelector(
(state) => state,
(state) => {
let prevUrl = url;
let prevPlayableClaim;
do {
prevUrl = makeSelectPreviousUrlForCollectionAndUrl(collectionId, prevUrl)(state);
prevPlayableClaim = makeSelectClaimForUri(prevUrl)(state);
} while (prevUrl && !isClaimPlayable(prevPlayableClaim));
return prevUrl;
}
);
export const makeSelectNextPlayableUrlFromCollectionAndUrl = (collectionId: string, url: string) =>
createSelector(
(state) => state,
(state) => {
let nextUrl = url;
let nextPlayableClaim;
do {
nextUrl = makeSelectNextUrlForCollectionAndUrl(collectionId, nextUrl)(state);
nextPlayableClaim = makeSelectClaimForUri(nextUrl)(state);
} while (nextUrl && !isClaimPlayable(nextPlayableClaim));
return nextUrl;
}
);
export const makeSelectNameForCollectionId = (id: string) =>
createSelector(makeSelectCollectionForId(id), (collection) => {
return (collection && collection.name) || '';
});
export const makeSelectCountForCollectionId = (id: string) =>
createSelector(makeSelectCollectionForId(id), (collection) => {
if (collection) {
if (collection.itemCount !== undefined) {
return collection.itemCount;
}
let itemCount = 0;
collection.items.map((item) => {
if (item) {
itemCount += 1;
}
});
return itemCount;
}
return null;
});