Add a setting to hide scheduled livestreams from home/following (#626)

* Add a setting to hide scheduled livestreams from home/following

* Add a hide button in the scheduled stream header.

* Fix typo + make sure pref is synced
This commit is contained in:
Dan Peterson 2022-01-05 15:20:43 -06:00 committed by GitHub
parent 4624188a85
commit bbe68a3319
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 69 additions and 11 deletions

View file

@ -1,4 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ScheduledStreams from './view'; import ScheduledStreams from './view';
import { doSetClientSetting } from 'redux/actions/settings';
import { doToast } from 'redux/actions/notifications';
export default connect()(ScheduledStreams); const perform = (dispatch) => ({
setClientSetting: (key, value, pushPrefs) => dispatch(doSetClientSetting(key, value, pushPrefs)),
doShowSnackBar: (message) => dispatch(doToast({ isError: false, message })),
});
export default connect(null, perform)(ScheduledStreams);

View file

@ -9,16 +9,20 @@ import ClaimListDiscover from 'component/claimListDiscover';
import Button from 'component/button'; import Button from 'component/button';
import { LIVESTREAM_UPCOMING_BUFFER } from 'constants/livestream'; import { LIVESTREAM_UPCOMING_BUFFER } from 'constants/livestream';
// import { SCHEDULED_LIVESTREAM_TAG } from 'constants/tags'; // import { SCHEDULED_LIVESTREAM_TAG } from 'constants/tags';
import * as SETTINGS from 'constants/settings';
type Props = { type Props = {
channelIds: Array<string>, channelIds: Array<string>,
tileLayout: boolean, tileLayout: boolean,
liveUris: Array<string>, liveUris: Array<string>,
limitClaimsPerChannel?: number, limitClaimsPerChannel?: number,
// --- perform ---
setClientSetting: (string, boolean | string | number, boolean) => void,
doShowSnackBar: (string) => void,
}; };
const ScheduledStreams = (props: Props) => { const ScheduledStreams = (props: Props) => {
const { channelIds, tileLayout, liveUris = [], limitClaimsPerChannel } = props; const { channelIds, tileLayout, liveUris = [], limitClaimsPerChannel, setClientSetting, doShowSnackBar } = props;
const isMediumScreen = useIsMediumScreen(); const isMediumScreen = useIsMediumScreen();
const isLargeScreen = useIsLargeScreen(); const isLargeScreen = useIsLargeScreen();
@ -38,6 +42,20 @@ const ScheduledStreams = (props: Props) => {
setTotalUpcomingLivestreams(total); setTotalUpcomingLivestreams(total);
}; };
const hideScheduledStreams = () => {
setClientSetting(SETTINGS.HIDE_SCHEDULED_LIVESTREAMS, true, true);
doShowSnackBar(__('Scheduled streams hidden, you can re-enable them in settings.'));
};
const Header = () => {
return (
<div>
{__('Upcoming Livestreams')}
<Button button="link" label={__('Hide')} onClick={hideScheduledStreams} className={'ml-s text-s'} />
</div>
);
};
return ( return (
<div className={'mb-xl'} style={{ display: showUpcomingLivestreams ? 'block' : 'none' }}> <div className={'mb-xl'} style={{ display: showUpcomingLivestreams ? 'block' : 'none' }}>
<ClaimListDiscover <ClaimListDiscover
@ -55,7 +73,7 @@ const ScheduledStreams = (props: Props) => {
infiniteScroll={false} infiniteScroll={false}
showNoSourceClaims showNoSourceClaims
hideLayoutButton hideLayoutButton
header={__('Upcoming Livestreams')} header={<Header />}
maxClaimRender={upcomingMax} maxClaimRender={upcomingMax}
excludeUris={liveUris} excludeUris={liveUris}
loadedCallback={loadedCallback} loadedCallback={loadedCallback}

View file

@ -15,6 +15,7 @@ const select = (state) => ({
autoplayMedia: selectClientSetting(state, SETTINGS.AUTOPLAY_MEDIA), autoplayMedia: selectClientSetting(state, SETTINGS.AUTOPLAY_MEDIA),
autoplayNext: selectClientSetting(state, SETTINGS.AUTOPLAY_NEXT), autoplayNext: selectClientSetting(state, SETTINGS.AUTOPLAY_NEXT),
hideReposts: selectClientSetting(state, SETTINGS.HIDE_REPOSTS), hideReposts: selectClientSetting(state, SETTINGS.HIDE_REPOSTS),
hideScheduledLivestreams: selectClientSetting(state, SETTINGS.HIDE_SCHEDULED_LIVESTREAMS),
showNsfw: selectShowMatureContent(state), showNsfw: selectShowMatureContent(state),
myChannelUrls: selectMyChannelUrls(state), myChannelUrls: selectMyChannelUrls(state),
instantPurchaseEnabled: selectClientSetting(state, SETTINGS.INSTANT_PURCHASE_ENABLED), instantPurchaseEnabled: selectClientSetting(state, SETTINGS.INSTANT_PURCHASE_ENABLED),

View file

@ -26,6 +26,7 @@ type Props = {
autoplayNext: boolean, autoplayNext: boolean,
hideReposts: ?boolean, hideReposts: ?boolean,
showNsfw: boolean, showNsfw: boolean,
hideScheduledLivestreams: boolean,
myChannelUrls: ?Array<string>, myChannelUrls: ?Array<string>,
instantPurchaseEnabled: boolean, instantPurchaseEnabled: boolean,
instantPurchaseMax: Price, instantPurchaseMax: Price,
@ -44,6 +45,7 @@ export default function SettingContent(props: Props) {
autoplayNext, autoplayNext,
hideReposts, hideReposts,
showNsfw, showNsfw,
hideScheduledLivestreams,
myChannelUrls, myChannelUrls,
instantPurchaseEnabled, instantPurchaseEnabled,
instantPurchaseMax, instantPurchaseMax,
@ -108,6 +110,15 @@ export default function SettingContent(props: Props) {
/> />
</SettingsRow> </SettingsRow>
<SettingsRow title={__('Hide Scheduled Livestreams')} subtitle={__(HELP.HIDE_SCHEDULED_LIVESTREAMS)}>
<FormField
type="checkbox"
name="hide_scheduled_livestreams"
onChange={() => setClientSetting(SETTINGS.HIDE_SCHEDULED_LIVESTREAMS, !hideScheduledLivestreams)}
checked={hideScheduledLivestreams}
/>
</SettingsRow>
{!SIMPLE_SITE && ( {!SIMPLE_SITE && (
<> <>
{/* {/*
@ -223,6 +234,7 @@ const HELP = {
AUTOPLAY_MEDIA: 'Autoplay video and audio files when navigating to a file.', AUTOPLAY_MEDIA: 'Autoplay video and audio files when navigating to a file.',
AUTOPLAY_NEXT: 'Autoplay the next related item when a file (video or audio) finishes playing.', AUTOPLAY_NEXT: 'Autoplay the next related item when a file (video or audio) finishes playing.',
HIDE_REPOSTS: 'You will not see reposts by people you follow or receive email notifying about them.', HIDE_REPOSTS: 'You will not see reposts by people you follow or receive email notifying about them.',
HIDE_SCHEDULED_LIVESTREAMS: 'You will not see scheduled livestreams by people you follow on the home or following page.',
SHOW_MATURE: 'Mature content may include nudity, intense sexuality, profanity, or other adult content. By displaying mature content, you are affirming you are of legal age to view mature content in your country or jurisdiction. ', SHOW_MATURE: 'Mature content may include nudity, intense sexuality, profanity, or other adult content. By displaying mature content, you are affirming you are of legal age to view mature content in your country or jurisdiction. ',
MAX_PURCHASE_PRICE: 'This will prevent you from purchasing any content over a certain cost, as a safety measure.', MAX_PURCHASE_PRICE: 'This will prevent you from purchasing any content over a certain cost, as a safety measure.',
ONLY_CONFIRM_OVER_AMOUNT: '', // [feel redundant. Disable for now] "When this option is chosen, LBRY won't ask you to confirm purchases or tips below your chosen amount.", ONLY_CONFIRM_OVER_AMOUNT: '', // [feel redundant. Disable for now] "When this option is chosen, LBRY won't ask you to confirm purchases or tips below your chosen amount.",

View file

@ -35,6 +35,7 @@ export const REWARDS_ACKNOWLEDGED = 'rewards_acknowledged';
export const SEARCH_IN_LANGUAGE = 'search_in_language'; export const SEARCH_IN_LANGUAGE = 'search_in_language';
export const HOMEPAGE = 'homepage'; export const HOMEPAGE = 'homepage';
export const HIDE_REPOSTS = 'hide_reposts'; export const HIDE_REPOSTS = 'hide_reposts';
export const HIDE_SCHEDULED_LIVESTREAMS = 'hide_scheduled_livestreams';
export const SUPPORT_OPTION = 'support_option'; export const SUPPORT_OPTION = 'support_option';
export const TILE_LAYOUT = 'tile_layout'; export const TILE_LAYOUT = 'tile_layout';
export const VIDEO_THEATER_MODE = 'video_theater_mode'; export const VIDEO_THEATER_MODE = 'video_theater_mode';

View file

@ -17,6 +17,7 @@ export const SDK_SYNC_KEYS = [DAEMON_SETTINGS.LBRYUM_SERVERS, DAEMON_SETTINGS.SH
export const CLIENT_SYNC_KEYS = [ export const CLIENT_SYNC_KEYS = [
SETTINGS.SHOW_MATURE, SETTINGS.SHOW_MATURE,
SETTINGS.HIDE_REPOSTS, SETTINGS.HIDE_REPOSTS,
SETTINGS.HIDE_SCHEDULED_LIVESTREAMS,
SETTINGS.SHOW_ANONYMOUS, SETTINGS.SHOW_ANONYMOUS,
SETTINGS.INSTANT_PURCHASE_ENABLED, SETTINGS.INSTANT_PURCHASE_ENABLED,
SETTINGS.INSTANT_PURCHASE_MAX, SETTINGS.INSTANT_PURCHASE_MAX,

View file

@ -12,6 +12,7 @@ const select = (state) => ({
tileLayout: selectClientSetting(state, SETTINGS.TILE_LAYOUT), tileLayout: selectClientSetting(state, SETTINGS.TILE_LAYOUT),
activeLivestreams: selectActiveLivestreams(state), activeLivestreams: selectActiveLivestreams(state),
fetchingActiveLivestreams: selectFetchingActiveLivestreams(state), fetchingActiveLivestreams: selectFetchingActiveLivestreams(state),
hideScheduledLivestreams: selectClientSetting(state, SETTINGS.HIDE_SCHEDULED_LIVESTREAMS),
}); });
export default connect(select, { export default connect(select, {

View file

@ -19,6 +19,7 @@ type Props = {
activeLivestreams: ?LivestreamInfo, activeLivestreams: ?LivestreamInfo,
doFetchActiveLivestreams: () => void, doFetchActiveLivestreams: () => void,
fetchingActiveLivestreams: boolean, fetchingActiveLivestreams: boolean,
hideScheduledLivestreams: boolean,
}; };
function ChannelsFollowingPage(props: Props) { function ChannelsFollowingPage(props: Props) {
@ -28,6 +29,7 @@ function ChannelsFollowingPage(props: Props) {
activeLivestreams, activeLivestreams,
doFetchActiveLivestreams, doFetchActiveLivestreams,
fetchingActiveLivestreams, fetchingActiveLivestreams,
hideScheduledLivestreams,
} = props; } = props;
const hasSubscribedChannels = subscribedChannels.length > 0; const hasSubscribedChannels = subscribedChannels.length > 0;
@ -43,12 +45,14 @@ function ChannelsFollowingPage(props: Props) {
<Page noFooter fullWidthPage={tileLayout}> <Page noFooter fullWidthPage={tileLayout}>
{!fetchingActiveLivestreams && ( {!fetchingActiveLivestreams && (
<> <>
<ScheduledStreams {!hideScheduledLivestreams && (
channelIds={channelIds} <ScheduledStreams
tileLayout={tileLayout} channelIds={channelIds}
liveUris={getLivestreamUris(activeLivestreams, channelIds)} tileLayout={tileLayout}
limitClaimsPerChannel={2} liveUris={getLivestreamUris(activeLivestreams, channelIds)}
/> limitClaimsPerChannel={2}
/>
)}
<ClaimListDiscover <ClaimListDiscover
prefixUris={getLivestreamUris(activeLivestreams, channelIds)} prefixUris={getLivestreamUris(activeLivestreams, channelIds)}

View file

@ -1,10 +1,11 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as SETTINGS from 'constants/settings';
import { doFetchActiveLivestreams } from 'redux/actions/livestream'; import { doFetchActiveLivestreams } from 'redux/actions/livestream';
import { selectActiveLivestreams, selectFetchingActiveLivestreams } from 'redux/selectors/livestream'; import { selectActiveLivestreams, selectFetchingActiveLivestreams } from 'redux/selectors/livestream';
import { selectFollowedTags } from 'redux/selectors/tags'; import { selectFollowedTags } from 'redux/selectors/tags';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions } from 'redux/selectors/subscriptions';
import { selectShowMatureContent, selectHomepageData } from 'redux/selectors/settings'; import { selectShowMatureContent, selectHomepageData, selectClientSetting } from 'redux/selectors/settings';
import DiscoverPage from './view'; import DiscoverPage from './view';
@ -16,6 +17,7 @@ const select = (state) => ({
homepageData: selectHomepageData(state), homepageData: selectHomepageData(state),
activeLivestreams: selectActiveLivestreams(state), activeLivestreams: selectActiveLivestreams(state),
fetchingActiveLivestreams: selectFetchingActiveLivestreams(state), fetchingActiveLivestreams: selectFetchingActiveLivestreams(state),
hideScheduledLivestreams: selectClientSetting(state, SETTINGS.HIDE_SCHEDULED_LIVESTREAMS),
}); });
const perform = (dispatch) => ({ const perform = (dispatch) => ({

View file

@ -30,6 +30,7 @@ type Props = {
activeLivestreams: any, activeLivestreams: any,
doFetchActiveLivestreams: () => void, doFetchActiveLivestreams: () => void,
fetchingActiveLivestreams: boolean, fetchingActiveLivestreams: boolean,
hideScheduledLivestreams: boolean,
}; };
function HomePage(props: Props) { function HomePage(props: Props) {
@ -42,6 +43,7 @@ function HomePage(props: Props) {
activeLivestreams, activeLivestreams,
doFetchActiveLivestreams, doFetchActiveLivestreams,
fetchingActiveLivestreams, fetchingActiveLivestreams,
hideScheduledLivestreams,
} = props; } = props;
const showPersonalizedChannels = (authenticated || !IS_WEB) && subscribedChannels && subscribedChannels.length > 0; const showPersonalizedChannels = (authenticated || !IS_WEB) && subscribedChannels && subscribedChannels.length > 0;
const showPersonalizedTags = (authenticated || !IS_WEB) && followedTags && followedTags.length > 0; const showPersonalizedTags = (authenticated || !IS_WEB) && followedTags && followedTags.length > 0;
@ -150,7 +152,7 @@ function HomePage(props: Props) {
{!fetchingActiveLivestreams && ( {!fetchingActiveLivestreams && (
<> <>
{authenticated && channelIds.length > 0 && ( {authenticated && channelIds.length > 0 && !hideScheduledLivestreams && (
<ScheduledStreams <ScheduledStreams
channelIds={channelIds} channelIds={channelIds}
tileLayout tileLayout

View file

@ -74,6 +74,7 @@ const defaultState = {
[SETTINGS.FLOATING_PLAYER]: true, [SETTINGS.FLOATING_PLAYER]: true,
[SETTINGS.AUTO_DOWNLOAD]: true, [SETTINGS.AUTO_DOWNLOAD]: true,
[SETTINGS.HIDE_REPOSTS]: false, [SETTINGS.HIDE_REPOSTS]: false,
[SETTINGS.HIDE_SCHEDULED_LIVESTREAMS]: false,
// OS // OS
[SETTINGS.AUTO_LAUNCH]: true, [SETTINGS.AUTO_LAUNCH]: true,

View file

@ -41,6 +41,10 @@
margin-bottom: var(--spacing-xl); margin-bottom: var(--spacing-xl);
} }
.ml-s {
margin-left: var(--spacing-s);
}
.ml-m { .ml-m {
margin-left: var(--spacing-m); margin-left: var(--spacing-m);
} }
@ -53,6 +57,10 @@
margin-bottom: 0; margin-bottom: 0;
} }
.text-s {
font-size: var(--font-small);
}
@media (min-width: $breakpoint-small) { @media (min-width: $breakpoint-small) {
.md\:items-center { .md\:items-center {
align-items: center; align-items: center;