Add "Hide Repost" button in channel page (#1796)

* Re-organized per 'state->var->func->effect->return' structure.

* Add "Hide Repost" button in channel page

Ticket: 1762

## Change
For the placement of the button, putting it inside the expanded settings group feels the most natural, plus we then don't need to check whether the channel has reposts or not before displaying it (the expanded area is for stuff like this).

## Notes
The tricky part was making the code maintainable w.r.t to the global "Hide Repost" setting. Changed `forceShowReposts` to `hideRepostsOverride`, hopefully makes things more obvious.
- undefined = fallback to global setting
- true/false = use override
This commit is contained in:
infinite-persistence 2022-07-06 01:20:10 +08:00 committed by GitHub
parent 5638f64831
commit b0e88ff5d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 67 deletions

View file

@ -13,9 +13,11 @@ import Icon from 'component/common/icon';
import LivestreamLink from 'component/livestreamLink'; import LivestreamLink from 'component/livestreamLink';
import { Form, FormField } from 'component/common/form'; import { Form, FormField } from 'component/common/form';
import ScheduledStreams from 'component/scheduledStreams'; import ScheduledStreams from 'component/scheduledStreams';
import { ClaimSearchFilterContext } from 'contexts/claimSearchFilterContext';
import { SearchResults } from './internal/searchResults'; import { SearchResults } from './internal/searchResults';
import useFetchLiveStatus from 'effects/use-fetch-live'; import useFetchLiveStatus from 'effects/use-fetch-live';
import { useIsLargeScreen } from 'effects/use-screensize'; import { useIsLargeScreen } from 'effects/use-screensize';
import usePersistedState from 'effects/use-persisted-state';
const TYPES_TO_ALLOW_FILTER = ['stream', 'repost']; const TYPES_TO_ALLOW_FILTER = ['stream', 'repost'];
@ -74,6 +76,15 @@ function ChannelContent(props: Props) {
const { const {
location: { pathname, search }, location: { pathname, search },
} = useHistory(); } = useHistory();
// In Channel Page, ignore SETTINGS.HIDE_REPOSTS and show reposts by default:
const [hideReposts, setHideReposts] = usePersistedState('hideRepostsChannelPage');
const claimSearchFilterCtx = {
contentTypes: CS.CONTENT_TYPES,
repost: { hideReposts, setHideReposts },
};
const url = `${pathname}${search}`; const url = `${pathname}${search}`;
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
const isChannelEmpty = !claim || !claim.meta; const isChannelEmpty = !claim || !claim.meta;
@ -85,6 +96,10 @@ function ChannelContent(props: Props) {
const isLargeScreen = useIsLargeScreen(); const isLargeScreen = useIsLargeScreen();
const dynamicPageSize = isLargeScreen ? Math.ceil(defaultPageSize * 3) : defaultPageSize; const dynamicPageSize = isLargeScreen ? Math.ceil(defaultPageSize * 3) : defaultPageSize;
const isInitialized = Boolean(activeLivestreamForChannel) || activeLivestreamInitialized;
const isChannelBroadcasting = Boolean(activeLivestreamForChannel);
const showScheduledLiveStreams = claimType !== 'collection'; // ie. not on the playlist page.
function handleInputChange(e) { function handleInputChange(e) {
const { value } = e.target; const { value } = e.target;
setSearchQuery(value); setSearchQuery(value);
@ -94,13 +109,8 @@ function ChannelContent(props: Props) {
setSearchQuery(''); setSearchQuery('');
}, [url]); }, [url]);
const isInitialized = Boolean(activeLivestreamForChannel) || activeLivestreamInitialized;
const isChannelBroadcasting = Boolean(activeLivestreamForChannel);
useFetchLiveStatus(claimId, doFetchChannelLiveStatus, true); useFetchLiveStatus(claimId, doFetchChannelLiveStatus, true);
const showScheduledLiveStreams = claimType !== 'collection'; // ie. not on the playlist page.
return ( return (
<Fragment> <Fragment>
<GeoRestrictionInfo uri={uri} /> <GeoRestrictionInfo uri={uri} />
@ -146,64 +156,66 @@ function ChannelContent(props: Props) {
{!channelIsMine && claimsInChannel > 0 && <HiddenNsfwClaims uri={uri} />} {!channelIsMine && claimsInChannel > 0 && <HiddenNsfwClaims uri={uri} />}
{!fetching && ( {!fetching && (
<ClaimListDiscover <ClaimSearchFilterContext.Provider value={claimSearchFilterCtx}>
ignoreSearchInLanguage <ClaimListDiscover
hasSource ignoreSearchInLanguage
defaultFreshness={CS.FRESH_ALL} hasSource
showHiddenByUser={viewHiddenChannels} defaultFreshness={CS.FRESH_ALL}
forceShowReposts showHiddenByUser={viewHiddenChannels}
fetchViewCount hideRepostsOverride={hideReposts}
hideFilters={!showFilters} fetchViewCount
hideAdvancedFilter={!showFilters} hideFilters={!showFilters}
tileLayout={tileLayout} hideAdvancedFilter={!showFilters}
uris={isSearching ? [] : null} tileLayout={tileLayout}
streamType={SIMPLE_SITE ? CS.CONTENT_ALL : undefined} uris={isSearching ? [] : null}
channelIds={[claimId]} streamType={SIMPLE_SITE ? CS.CONTENT_ALL : undefined}
claimType={claimType} channelIds={[claimId]}
feeAmount={CS.FEE_AMOUNT_ANY} claimType={claimType}
defaultOrderBy={CS.ORDER_BY_NEW} feeAmount={CS.FEE_AMOUNT_ANY}
pageSize={dynamicPageSize} defaultOrderBy={CS.ORDER_BY_NEW}
infiniteScroll={defaultInfiniteScroll} pageSize={dynamicPageSize}
injectedItem={ infiniteScroll={defaultInfiniteScroll}
!hasPremiumPlus && { injectedItem={
node: (index, lastVisibleIndex, pageSize) => { !hasPremiumPlus && {
if (pageSize && index < pageSize) { node: (index, lastVisibleIndex, pageSize) => {
return index === lastVisibleIndex ? <Ads type="video" tileLayout={tileLayout} small /> : null; if (pageSize && index < pageSize) {
} else { return index === lastVisibleIndex ? <Ads type="video" tileLayout={tileLayout} small /> : null;
return index % (pageSize * 2) === 0 ? <Ads type="video" tileLayout={tileLayout} small /> : null; } else {
} return index % (pageSize * 2) === 0 ? <Ads type="video" tileLayout={tileLayout} small /> : null;
}, }
},
}
} }
} meta={
meta={ showFilters && (
showFilters && ( <Form onSubmit={() => {}} className="wunderbar--inline">
<Form onSubmit={() => {}} className="wunderbar--inline"> <Icon icon={ICONS.SEARCH} />
<Icon icon={ICONS.SEARCH} /> <FormField
<FormField name="channel_search"
name="channel_search" className="wunderbar__input--inline"
className="wunderbar__input--inline" value={searchQuery}
value={searchQuery} onChange={handleInputChange}
onChange={handleInputChange} type="text"
type="text" placeholder={__('Search')}
placeholder={__('Search')} />
/> </Form>
</Form> )
) }
} subSection={
subSection={ <SearchResults
<SearchResults searchQuery={searchQuery}
searchQuery={searchQuery} claimId={claimId}
claimId={claimId} showMature={showMature}
showMature={showMature} tileLayout={tileLayout}
tileLayout={tileLayout} onResults={(results) => setIsSearching(results !== null)}
onResults={(results) => setIsSearching(results !== null)} doResolveUris={doResolveUris}
doResolveUris={doResolveUris} />
/> }
} isChannel
isChannel channelIsMine={channelIsMine}
channelIsMine={channelIsMine} empty={isSearching ? ' ' : empty}
empty={isSearching ? ' ' : empty} />
/> </ClaimSearchFilterContext.Provider>
)} )}
</Fragment> </Fragment>
); );

View file

@ -31,7 +31,7 @@ type Props = {
pageSize?: number, pageSize?: number,
fetchViewCount?: boolean, fetchViewCount?: boolean,
forceShowReposts?: boolean, hideRepostsOverride?: boolean, // undefined = use SETTINGS.HIDE_REPOSTS; true/false: use this.
hasNoSource?: boolean, hasNoSource?: boolean,
hasSource?: boolean, hasSource?: boolean,
hideAdvancedFilter?: boolean, hideAdvancedFilter?: boolean,
@ -165,7 +165,7 @@ function ClaimListDiscover(props: Props) {
hideFilters = false, hideFilters = false,
claimIds, claimIds,
maxPages, maxPages,
forceShowReposts = false, hideRepostsOverride,
languageSetting, languageSetting,
searchLanguages, searchLanguages,
searchInLanguage, searchInLanguage,
@ -214,6 +214,7 @@ function ClaimListDiscover(props: Props) {
new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1])) new Set(mutedUris.concat(blockedUris).map((uri) => splitBySeparator(uri)[1]))
); );
const [hiddenBuffer, setHiddenBuffer] = React.useState([]); const [hiddenBuffer, setHiddenBuffer] = React.useState([]);
const hideRepostsEffective = resolveHideReposts(hideReposts, hideRepostsOverride);
const langParam = urlParams.get(CS.LANGUAGE_KEY) || null; const langParam = urlParams.get(CS.LANGUAGE_KEY) || null;
const searchInSelectedLang = searchInLanguage && !ignoreSearchInLanguage; const searchInSelectedLang = searchInLanguage && !ignoreSearchInLanguage;
@ -438,7 +439,7 @@ function ClaimListDiscover(props: Props) {
} }
} }
if (hideReposts && !options.reposted_claim_id && !forceShowReposts) { if (hideRepostsEffective && !options.reposted_claim_id) {
if (Array.isArray(options.claim_type)) { if (Array.isArray(options.claim_type)) {
if (options.claim_type.length > 1) { if (options.claim_type.length > 1) {
options.claim_type = options.claim_type.filter((claimType) => claimType !== 'repost'); options.claim_type = options.claim_type.filter((claimType) => claimType !== 'repost');
@ -602,6 +603,14 @@ function ClaimListDiscover(props: Props) {
} }
} }
function resolveHideReposts(hideRepostSetting, hideRepostOverride) {
if (hideRepostOverride === undefined || hideRepostOverride === null) {
return hideRepostSetting;
} else {
return hideRepostOverride;
}
}
function resolveOrderByOption(orderBy: string | Array<string>, sortBy: string | Array<string>) { function resolveOrderByOption(orderBy: string | Array<string>, sortBy: string | Array<string>) {
let order_by; let order_by;

View file

@ -88,7 +88,8 @@ function ClaimListHeader(props: Props) {
urlParams.get(CS.DURATION_KEY) || urlParams.get(CS.DURATION_KEY) ||
urlParams.get(CS.TAGS_KEY) || urlParams.get(CS.TAGS_KEY) ||
urlParams.get(CS.FEE_AMOUNT_KEY) || urlParams.get(CS.FEE_AMOUNT_KEY) ||
urlParams.get(CS.LANGUAGE_KEY) urlParams.get(CS.LANGUAGE_KEY) ||
filterCtx?.repost?.hideReposts
); );
const languageValue = searchInLanguage const languageValue = searchInLanguage
@ -103,6 +104,27 @@ function ClaimListHeader(props: Props) {
? languageParam !== languageSetting && languageParam !== null ? languageParam !== languageSetting && languageParam !== null
: languageParam !== CS.LANGUAGES_ALL && languageParam !== null; : languageParam !== CS.LANGUAGES_ALL && languageParam !== null;
function getHideRepostsElem(filterCtx, contentType) {
if (filterCtx?.repost) {
return (
<div className={classnames(`card claim-search__menus`)}>
<FormField
label={__('Hide reposts')}
name="hide_reposts"
type="checkbox"
checked={filterCtx.repost.hideReposts}
disabled={contentType === CS.CLAIM_REPOST}
onChange={() => {
filterCtx.repost.setHideReposts((prev) => !prev);
}}
/>
</div>
);
} else {
return null;
}
}
React.useEffect(() => { React.useEffect(() => {
if (action !== 'POP' && isFiltered()) { if (action !== 'POP' && isFiltered()) {
setExpanded(true); setExpanded(true);
@ -507,6 +529,7 @@ function ClaimListHeader(props: Props) {
</div> </div>
)} )}
</div> </div>
{getHideRepostsElem(filterCtx, contentTypeParam)}
</> </>
)} )}
</div> </div>

View file

@ -270,7 +270,7 @@ function DiscoverPage(props: Props) {
} }
meta={getMeta()} meta={getMeta()}
hasSource hasSource
forceShowReposts={dynamicRouteProps} hideRepostsOverride={dynamicRouteProps ? true : undefined}
searchLanguages={dynamicRouteProps?.options?.searchLanguages} searchLanguages={dynamicRouteProps?.options?.searchLanguages}
/> />
</ClaimSearchFilterContext.Provider> </ClaimSearchFilterContext.Provider>