Still learning to use Git. All files should be good now.

This commit is contained in:
dgarrett01 2022-11-27 18:05:40 -05:00
parent 121e22e17f
commit 63ccfc1304
9 changed files with 160 additions and 54 deletions

View file

@ -4,6 +4,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.53.8] - [2022-11-17] ## [0.53.8] - [2022-11-17]
### Added
- Added the ability for users to hide content they've already watched throughout the app via a checkbox ([#7645](https://github.com/lbryio/lbry-desktop/issues/7645))
### Fixed ### Fixed
- Selecting a large file in publish no longer crashes ([#7736](https://github.com/lbryio/lbry-desktop/pull/7736)) - Selecting a large file in publish no longer crashes ([#7736](https://github.com/lbryio/lbry-desktop/pull/7736))
- Unfollowing unpublished channels ([#7737](https://github.com/lbryio/lbry-desktop/pull/7737)) - Unfollowing unpublished channels ([#7737](https://github.com/lbryio/lbry-desktop/pull/7737))

View file

@ -106,6 +106,7 @@ function ChannelForm(props: Props) {
const languageParam = params.languages; const languageParam = params.languages;
const primaryLanguage = Array.isArray(languageParam) && languageParam.length && languageParam[0]; const primaryLanguage = Array.isArray(languageParam) && languageParam.length && languageParam[0];
const secondaryLanguage = Array.isArray(languageParam) && languageParam.length >= 2 && languageParam[1]; const secondaryLanguage = Array.isArray(languageParam) && languageParam.length >= 2 && languageParam[1];
const [hideWatched, setHideWatched] = usePersistedState('hideWatched', false);
const submitLabel = React.useMemo(() => { const submitLabel = React.useMemo(() => {
if (isClaimingInitialRewards) { if (isClaimingInitialRewards) {
return __('Claiming credits...'); return __('Claiming credits...');
@ -240,6 +241,22 @@ function ChannelForm(props: Props) {
errorMsg = __('Invalid %error_type%', { error_type: (thumbError && 'thumbnail') || (coverError && 'cover image') }); errorMsg = __('Invalid %error_type%', { error_type: (thumbError && 'thumbnail') || (coverError && 'cover image') });
} }
function getHideWatchedElem() {
return (
<div className={classnames(`card claim-search__menus`)}>
<FormField
label={__('Hide Watched')}
name="hide_watched"
type="checkbox"
checked={hideWatched}
onChange={() => {
setHideWatched((prev) => !prev);
}}
/>
</div>
);
}
React.useEffect(() => { React.useEffect(() => {
let nameError; let nameError;
if (!name && name !== undefined) { if (!name && name !== undefined) {
@ -526,6 +543,7 @@ function ChannelForm(props: Props) {
<ClaimAbandonButton uri={uri} abandonActionCallback={() => replace(`/$/${PAGES.CHANNELS}`)} /> <ClaimAbandonButton uri={uri} abandonActionCallback={() => replace(`/$/${PAGES.CHANNELS}`)} />
</div> </div>
)} )}
{getHideWatchedElem()}
</> </>
} }
/> />

View file

@ -67,6 +67,7 @@ function ClaimListHeader(props: Props) {
const [orderParamUser, setOrderParamUser] = usePersistedState(`orderUser-${location.pathname}`, CS.ORDER_BY_TRENDING); const [orderParamUser, setOrderParamUser] = usePersistedState(`orderUser-${location.pathname}`, CS.ORDER_BY_TRENDING);
const urlParams = new URLSearchParams(search); const urlParams = new URLSearchParams(search);
const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness; const freshnessParam = freshness || urlParams.get(CS.FRESH_KEY) || defaultFreshness;
const [hideWatched, setHideWatched] = usePersistedState('hideWatched', false);
const contentTypeParam = urlParams.get(CS.CONTENT_KEY); const contentTypeParam = urlParams.get(CS.CONTENT_KEY);
const streamTypeParam = const streamTypeParam =
streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null; streamType || (CS.FILE_TYPES.includes(contentTypeParam) && contentTypeParam) || defaultStreamType || null;

View file

@ -21,6 +21,7 @@ import { selectIsSubscribedForUri } from 'redux/selectors/subscriptions';
import { isClaimNsfw } from 'util/claim'; import { isClaimNsfw } from 'util/claim';
import ClaimPreview from './view'; import ClaimPreview from './view';
import formatMediaDuration from 'util/formatMediaDuration'; import formatMediaDuration from 'util/formatMediaDuration';
import { makeSelectContentWatchedPercentageForUri } from 'redux/selectors/content';
const select = (state, props) => { const select = (state, props) => {
const claim = props.uri && selectClaimForUri(state, props.uri); const claim = props.uri && selectClaimForUri(state, props.uri);
@ -46,6 +47,7 @@ const select = (state, props) => {
wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state), wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state),
isCollectionMine: makeSelectCollectionIsMine(props.collectionId)(state), isCollectionMine: makeSelectCollectionIsMine(props.collectionId)(state),
lang: selectLanguage(state), lang: selectLanguage(state),
isWatched: makeSelectContentWatchedPercentageForUri(props.uri)(state) > 80,
}; };
}; };

View file

@ -32,6 +32,7 @@ import ClaimPreviewNoContent from './claim-preview-no-content';
import CollectionEditButtons from 'component/collectionEditButtons'; import CollectionEditButtons from 'component/collectionEditButtons';
import { useIsMobile } from 'effects/use-screensize'; import { useIsMobile } from 'effects/use-screensize';
import AbandonedChannelPreview from 'component/abandonedChannelPreview'; import AbandonedChannelPreview from 'component/abandonedChannelPreview';
import usePersistedState from 'effects/use-persisted-state';
// preview images used on the landing page and on the channel page // preview images used on the landing page and on the channel page
type Props = { type Props = {
@ -82,6 +83,7 @@ type Props = {
showEdit?: boolean, showEdit?: boolean,
dragHandleProps?: any, dragHandleProps?: any,
unavailableUris?: Array<string>, unavailableUris?: Array<string>,
isWatched: boolean,
}; };
const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
@ -141,10 +143,11 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
showEdit, showEdit,
dragHandleProps, dragHandleProps,
unavailableUris, unavailableUris,
isWatched,
} = props; } = props;
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const [hideWatched, setHideWatched] = usePersistedState('hideWatched', false);
const isCollection = claim && claim.value_type === 'collection'; const isCollection = claim && claim.value_type === 'collection';
const collectionClaimId = isCollection && claim && claim.claim_id; const collectionClaimId = isCollection && claim && claim.claim_id;
const listId = collectionId || collectionClaimId; const listId = collectionId || collectionClaimId;
@ -278,6 +281,14 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
} }
}, [isValid, uri, isResolvingUri, shouldFetch, resolveUri]); }, [isValid, uri, isResolvingUri, shouldFetch, resolveUri]);
if (isWatched && hideWatched) {
shouldHide = true;
}
if (shouldHide) {
return null;
}
if (shouldHide && !showNullPlaceholder) { if (shouldHide && !showNullPlaceholder) {
return null; return null;
} }

View file

@ -10,6 +10,7 @@ import { doFileGet } from 'redux/actions/file';
import { doResolveUri } from 'redux/actions/claims'; import { doResolveUri } from 'redux/actions/claims';
import { selectViewCountForUri, selectBanStateForUri } from 'lbryinc'; import { selectViewCountForUri, selectBanStateForUri } from 'lbryinc';
import { selectShowMatureContent } from 'redux/selectors/settings'; import { selectShowMatureContent } from 'redux/selectors/settings';
import { makeSelectContentWatchedPercentageForUri } from 'redux/selectors/content';
import { isClaimNsfw } from 'util/claim'; import { isClaimNsfw } from 'util/claim';
import ClaimPreviewTile from './view'; import ClaimPreviewTile from './view';
import formatMediaDuration from 'util/formatMediaDuration'; import formatMediaDuration from 'util/formatMediaDuration';
@ -30,6 +31,7 @@ const select = (state, props) => {
showMature: selectShowMatureContent(state), showMature: selectShowMatureContent(state),
isMature: claim ? isClaimNsfw(claim) : false, isMature: claim ? isClaimNsfw(claim) : false,
viewCount: selectViewCountForUri(state, props.uri), viewCount: selectViewCountForUri(state, props.uri),
isWatched: makeSelectContentWatchedPercentageForUri(props.uri)(state) > 80,
}; };
}; };

View file

@ -20,6 +20,7 @@ import ClaimMenuList from 'component/claimMenuList';
import CollectionPreviewOverlay from 'component/collectionPreviewOverlay'; import CollectionPreviewOverlay from 'component/collectionPreviewOverlay';
// $FlowFixMe cannot resolve ... // $FlowFixMe cannot resolve ...
import PlaceholderTx from 'static/img/placeholderTx.gif'; import PlaceholderTx from 'static/img/placeholderTx.gif';
import usePersistedState from 'effects/use-persisted-state';
type Props = { type Props = {
uri: string, uri: string,
@ -42,6 +43,7 @@ type Props = {
collectionId?: string, collectionId?: string,
viewCount: string, viewCount: string,
swipeLayout: boolean, swipeLayout: boolean,
isWatched: boolean,
}; };
// preview image cards used in related video functionality, channel overview page and homepage // preview image cards used in related video functionality, channel overview page and homepage
@ -67,10 +69,12 @@ function ClaimPreviewTile(props: Props) {
mediaDuration, mediaDuration,
viewCount, viewCount,
swipeLayout = false, swipeLayout = false,
isWatched,
} = props; } = props;
const isRepost = claim && claim.repost_channel_url; const isRepost = claim && claim.repost_channel_url;
const isCollection = claim && claim.value_type === 'collection'; const isCollection = claim && claim.value_type === 'collection';
const isStream = claim && claim.value_type === 'stream'; const isStream = claim && claim.value_type === 'stream';
const [hideWatched, setHideWatched] = usePersistedState('hideWatched', false);
// $FlowFixMe // $FlowFixMe
const isPlayable = const isPlayable =
claim && claim &&
@ -126,6 +130,22 @@ function ClaimPreviewTile(props: Props) {
let shouldHide = false; let shouldHide = false;
if (isMature && !showMature) {
// Unfortunately needed until this is resolved
// https://github.com/lbryio/lbry-sdk/issues/2785
shouldHide = true;
} else {
shouldHide =
banState.blacklisted ||
banState.filtered ||
(!showHiddenByUser && (banState.muted || banState.blocked)) ||
(isWatched && hideWatched);
}
if (shouldHide) {
return null;
}
if (isMature && !showMature) { if (isMature && !showMature) {
// Unfortunately needed until this is resolved // Unfortunately needed until this is resolved
// https://github.com/lbryio/lbry-sdk/issues/2785 // https://github.com/lbryio/lbry-sdk/issues/2785

View file

@ -61,6 +61,8 @@ const SearchOptions = (props: Props) => {
delete TYPES_ADVANCED[SEARCH_OPTIONS.MEDIA_IMAGE]; delete TYPES_ADVANCED[SEARCH_OPTIONS.MEDIA_IMAGE];
} }
const [hideWatched, setHideWatched] = usePersistedState('hideWatched', false);
React.useEffect(() => { React.useEffect(() => {
// We no longer let the user set the search results count, but the value // We no longer let the user set the search results count, but the value
// will be in local storage for existing users. Override that. // will be in local storage for existing users. Override that.
@ -69,6 +71,30 @@ const SearchOptions = (props: Props) => {
} }
}, []); }, []);
function getHideWatchedElem() {
return (
<div className={`claim-search__checkbox_searchbox`}>
<FormField
name="hide_watched"
type="checkbox"
checked={hideWatched}
onChange={() => {
setHideWatched((prev) => !prev);
}}
/>
<Icon
className="icon--help"
icon={ICONS.HELP}
tooltip
size={16}
customTooltipText={__(
'Hide content you have already viewed from search results.'
)}
/>
</div>
);
}
function updateSearchOptions(option, value) { function updateSearchOptions(option, value) {
setSearchOption(option, value); setSearchOption(option, value);
if (onSearchOptionsChanged) { if (onSearchOptionsChanged) {
@ -149,7 +175,7 @@ const SearchOptions = (props: Props) => {
</> </>
); );
const otherOptionsElem = ( const exactMatchElem = (
<> <>
<div className="filter-values"> <div className="filter-values">
<FormField <FormField
@ -157,7 +183,6 @@ const SearchOptions = (props: Props) => {
name="exact-match" name="exact-match"
checked={options[SEARCH_OPTIONS.EXACT]} checked={options[SEARCH_OPTIONS.EXACT]}
onChange={() => updateSearchOptions(SEARCH_OPTIONS.EXACT, !options[SEARCH_OPTIONS.EXACT])} onChange={() => updateSearchOptions(SEARCH_OPTIONS.EXACT, !options[SEARCH_OPTIONS.EXACT])}
label={__('Exact match')}
/> />
<Icon <Icon
className="icon--help" className="icon--help"
@ -169,6 +194,7 @@ const SearchOptions = (props: Props) => {
)} )}
/> />
</div> </div>
</> </>
); );
@ -194,6 +220,12 @@ const SearchOptions = (props: Props) => {
</div> </div>
); );
const hideWatchedElem = (
<div>
{getHideWatchedElem()}
</div>
);
const sortByElem = ( const sortByElem = (
<div className="filter-values"> <div className="filter-values">
<FormField <FormField
@ -230,7 +262,8 @@ const SearchOptions = (props: Props) => {
{addRow(__('Type'), typeElem)} {addRow(__('Type'), typeElem)}
{addRow(uploadDateLabel, uploadDateElem)} {addRow(uploadDateLabel, uploadDateElem)}
{addRow(__('Sort By'), sortByElem)} {addRow(__('Sort By'), sortByElem)}
{addRow(__('Other Options'), otherOptionsElem)} {addRow(__('Exact Match'), exactMatchElem)}
{addRow(__('Hide Watched Content'), hideWatchedElem)}
</tbody> </tbody>
</table> </table>
</Form> </Form>

View file

@ -27,6 +27,22 @@
} }
} }
// UPDATE: Add style for checkbox
.claim-search__checkbox {
padding-left: 45%;
padding-top: 7%;
}
//UPDATE: Added style for checkbox on search page
.claim-search__checkbox_searchbox {
// Placeholder
}
// UPDATE: Add style for checkbox label
.checkbox-label {
padding-left: 10px;
}
.claim-search__dropdown { .claim-search__dropdown {
font-size: var(--font-body); font-size: var(--font-body);
background-color: var(--color-input-bg); background-color: var(--color-input-bg);