Autoplay #1453
14 changed files with 108 additions and 11 deletions
|
@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* New dark mode ([#1269](https://github.com/lbryio/lbry-app/pull/1269))
|
* New dark mode ([#1269](https://github.com/lbryio/lbry-app/pull/1269))
|
||||||
* Pre-fill publish URL after clicking "Put something here" link ([#1303](https://github.com/lbryio/lbry-app/pull/1303))
|
* Pre-fill publish URL after clicking "Put something here" link ([#1303](https://github.com/lbryio/lbry-app/pull/1303))
|
||||||
* Add Danger JS to automate code reviews ([#1289](https://github.com/lbryio/lbry-app/pull/1289))
|
* Add Danger JS to automate code reviews ([#1289](https://github.com/lbryio/lbry-app/pull/1289))
|
||||||
|
* Autoplay downloaded and free media ([#584](https://github.com/lbryio/lbry-app/pull/1453))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
|
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
|
||||||
|
|
|
@ -9,6 +9,7 @@ type Props = {
|
||||||
padded?: boolean,
|
padded?: boolean,
|
||||||
verticallyCentered?: boolean,
|
verticallyCentered?: boolean,
|
||||||
stretch?: boolean,
|
stretch?: boolean,
|
||||||
|
alignRight?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormRow extends React.PureComponent<Props> {
|
export class FormRow extends React.PureComponent<Props> {
|
||||||
|
@ -17,7 +18,7 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { centered, children, padded, verticallyCentered, stretch } = this.props;
|
const { centered, children, padded, verticallyCentered, stretch, alignRight } = this.props;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('form-row', {
|
className={classnames('form-row', {
|
||||||
|
@ -25,6 +26,7 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
'form-row--padded': padded,
|
'form-row--padded': padded,
|
||||||
'form-row--vertically-centered': verticallyCentered,
|
'form-row--vertically-centered': verticallyCentered,
|
||||||
'form-row--stretch': stretch,
|
'form-row--stretch': stretch,
|
||||||
|
'form-row--right': alignRight,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import * as settings from 'constants/settings';
|
||||||
import { doChangeVolume } from 'redux/actions/app';
|
import { doChangeVolume } from 'redux/actions/app';
|
||||||
import { selectVolume } from 'redux/selectors/app';
|
import { selectVolume } from 'redux/selectors/app';
|
||||||
import { doPlayUri, doSetPlayingUri } from 'redux/actions/content';
|
import { doPlayUri, doSetPlayingUri, doLoadVideo } from 'redux/actions/content';
|
||||||
import { doPlay, doPause, savePosition } from 'redux/actions/media';
|
import { doPlay, doPause, savePosition } from 'redux/actions/media';
|
||||||
import {
|
import {
|
||||||
makeSelectMetadataForUri,
|
makeSelectMetadataForUri,
|
||||||
|
@ -12,7 +13,10 @@ import {
|
||||||
makeSelectLoadingForUri,
|
makeSelectLoadingForUri,
|
||||||
makeSelectDownloadingForUri,
|
makeSelectDownloadingForUri,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import {
|
||||||
|
makeSelectClientSetting,
|
||||||
|
selectShowNsfw
|
||||||
|
} from 'redux/selectors/settings';
|
||||||
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
||||||
import { selectPlayingUri } from 'redux/selectors/content';
|
import { selectPlayingUri } from 'redux/selectors/content';
|
||||||
import Video from './view';
|
import Video from './view';
|
||||||
|
@ -30,10 +34,12 @@ const select = (state, props) => ({
|
||||||
volume: selectVolume(state),
|
volume: selectVolume(state),
|
||||||
mediaPaused: selectMediaPaused(state),
|
mediaPaused: selectMediaPaused(state),
|
||||||
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
||||||
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state)
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
play: uri => dispatch(doPlayUri(uri)),
|
play: uri => dispatch(doPlayUri(uri)),
|
||||||
|
load: uri => dispatch(doLoadVideo(uri)),
|
||||||
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
||||||
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
||||||
doPlay: () => dispatch(doPlay()),
|
doPlay: () => dispatch(doPlay()),
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Props = {
|
||||||
nsfw: boolean,
|
nsfw: boolean,
|
||||||
thumbnail: string,
|
thumbnail: string,
|
||||||
},
|
},
|
||||||
|
autoplay: boolean,
|
||||||
isLoading: boolean,
|
isLoading: boolean,
|
||||||
isDownloading: boolean,
|
isDownloading: boolean,
|
||||||
playingUri: ?string,
|
playingUri: ?string,
|
||||||
|
@ -38,10 +39,38 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class Video extends React.PureComponent<Props> {
|
class Video extends React.PureComponent<Props> {
|
||||||
|
componentDidMount() {
|
||||||
|
this.handleAutoplay(this.props);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps: Props) {
|
||||||
|
if (
|
||||||
|
this.props.autoplay !== nextProps.autoplay ||
|
||||||
|
this.props.fileInfo !== nextProps.fileInfo ||
|
||||||
|
this.props.isDownloading !== nextProps.isDownloading ||
|
||||||
|
this.props.playingUri !== nextProps.playingUri
|
||||||
|
) {
|
||||||
|
this.handleAutoplay(nextProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.cancelPlay();
|
this.props.cancelPlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAutoplay(props: Props) {
|
||||||
|
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, load, play, metadata } = props;
|
||||||
|
|
||||||
|
const playable = autoplay && playingUri !== uri && metadata && !metadata.nsfw;
|
||||||
|
|
||||||
|
if (playable && costInfo && costInfo.cost === 0 && !fileInfo && !isDownloading) {
|
||||||
|
load(uri);
|
||||||
|
play(uri);
|
||||||
|
} else if (playable && fileInfo && fileInfo.blobs_completed > 0) {
|
||||||
|
play(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isMediaSame(nextProps: Props) {
|
isMediaSame(nextProps: Props) {
|
||||||
return (
|
return (
|
||||||
this.props.fileInfo &&
|
this.props.fileInfo &&
|
||||||
|
@ -90,13 +119,18 @@ class Video extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const poster = metadata && metadata.thumbnail;
|
const poster = metadata && metadata.thumbnail;
|
||||||
|
const layoverClass = classnames('content__cover', { 'card__media--nsfw': shouldObscureNsfw });
|
||||||
|
const layoverStyle =
|
||||||
|
!shouldObscureNsfw && poster ? { backgroundImage: `url("${poster}")` } : {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('video', {}, className)}>
|
<div className={classnames('video', {}, className)}>
|
||||||
{isPlaying && (
|
{isPlaying && (
|
||||||
<div className="content__view">
|
<div className="content__view">
|
||||||
{!isReadyToPlay ? (
|
{!isReadyToPlay ? (
|
||||||
<LoadingScreen status={loadStatusMessage} />
|
<div className={layoverClass} style={layoverStyle}>
|
||||||
|
<LoadingScreen status={loadStatusMessage} />
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<VideoPlayer
|
<VideoPlayer
|
||||||
filename={fileInfo.file_name}
|
filename={fileInfo.file_name}
|
||||||
|
@ -119,10 +153,7 @@ class Video extends React.PureComponent<Props> {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isPlaying && (
|
{!isPlaying && (
|
||||||
<div
|
<div className={layoverClass} style={layoverStyle}>
|
||||||
className={classnames('content__cover', { 'card__media--nsfw': shouldObscureNsfw })}
|
|
||||||
style={!shouldObscureNsfw && poster ? { backgroundImage: `url("${poster}")` } : {}}
|
|
||||||
>
|
|
||||||
<VideoPlayButton
|
<VideoPlayButton
|
||||||
play={play}
|
play={play}
|
||||||
fileInfo={fileInfo}
|
fileInfo={fileInfo}
|
||||||
|
|
|
@ -24,3 +24,4 @@ export const PHONE = 'Phone';
|
||||||
export const CHECK = 'CheckCircle';
|
export const CHECK = 'CheckCircle';
|
||||||
export const HEART = 'Heart';
|
export const HEART = 'Heart';
|
||||||
export const UNLOCK = 'Unlock';
|
export const UNLOCK = 'Unlock';
|
||||||
|
export const CHECK_SIMPLE = 'Check';
|
||||||
|
|
|
@ -12,3 +12,4 @@ export const INSTANT_PURCHASE_MAX = 'instantPurchaseMax';
|
||||||
export const THEME = 'theme';
|
export const THEME = 'theme';
|
||||||
export const THEMES = 'themes';
|
export const THEMES = 'themes';
|
||||||
export const AUTOMATIC_DARK_MODE_ENABLED = 'automaticDarkModeEnabled';
|
export const AUTOMATIC_DARK_MODE_ENABLED = 'automaticDarkModeEnabled';
|
||||||
|
export const AUTOPLAY = 'autoplay';
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import * as settings from 'constants/settings';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
|
import { selectRewardContentClaimIds, selectPlayingUri } from 'redux/selectors/content';
|
||||||
import { doCheckSubscription } from 'redux/actions/subscriptions';
|
import { doCheckSubscription } from 'redux/actions/subscriptions';
|
||||||
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
import {
|
import {
|
||||||
doFetchFileInfo,
|
doFetchFileInfo,
|
||||||
doFetchCostInfoForUri,
|
doFetchCostInfoForUri,
|
||||||
|
@ -13,7 +15,7 @@ import {
|
||||||
makeSelectMetadataForUri,
|
makeSelectMetadataForUri,
|
||||||
doNotify,
|
doNotify,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import { selectShowNsfw, makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||||
import { selectMediaPaused } from 'redux/selectors/media';
|
import { selectMediaPaused } from 'redux/selectors/media';
|
||||||
import { doPrepareEdit } from 'redux/actions/publish';
|
import { doPrepareEdit } from 'redux/actions/publish';
|
||||||
|
@ -31,6 +33,7 @@ const select = (state, props) => ({
|
||||||
playingUri: selectPlayingUri(state),
|
playingUri: selectPlayingUri(state),
|
||||||
isPaused: selectMediaPaused(state),
|
isPaused: selectMediaPaused(state),
|
||||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||||
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state)
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
@ -40,6 +43,7 @@ const perform = dispatch => ({
|
||||||
checkSubscription: subscription => dispatch(doCheckSubscription(subscription)),
|
checkSubscription: subscription => dispatch(doCheckSubscription(subscription)),
|
||||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||||
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
|
prepareEdit: (publishData, uri) => dispatch(doPrepareEdit(publishData, uri)),
|
||||||
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(FilePage);
|
export default connect(select, perform)(FilePage);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import FilePrice from 'component/filePrice';
|
||||||
import FileDetails from 'component/fileDetails';
|
import FileDetails from 'component/fileDetails';
|
||||||
import FileActions from 'component/fileActions';
|
import FileActions from 'component/fileActions';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
|
import { FormField, FormRow } from 'component/common/form';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import DateTime from 'component/dateTime';
|
import DateTime from 'component/dateTime';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
@ -14,6 +15,7 @@ import Button from 'component/button';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
|
import * as settings from 'constants/settings';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: {
|
claim: {
|
||||||
|
@ -39,15 +41,25 @@ type Props = {
|
||||||
playingUri: ?string,
|
playingUri: ?string,
|
||||||
isPaused: boolean,
|
isPaused: boolean,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
|
autoplay: boolean,
|
||||||
costInfo: ?{},
|
costInfo: ?{},
|
||||||
navigate: (string, ?{}) => void,
|
navigate: (string, ?{}) => void,
|
||||||
openModal: ({ id: string }, { uri: string }) => void,
|
openModal: ({ id: string }, { uri: string }) => void,
|
||||||
fetchFileInfo: string => void,
|
fetchFileInfo: string => void,
|
||||||
fetchCostInfo: string => void,
|
fetchCostInfo: string => void,
|
||||||
prepareEdit: ({}) => void,
|
prepareEdit: ({}) => void,
|
||||||
|
setClientSetting: (string, boolean | string) => void,
|
||||||
|
checkSubscription: ({ channelName: string, uri: string }) => void,
|
||||||
|
subscriptions: Array<{}>,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilePage extends React.Component<Props> {
|
class FilePage extends React.Component<Props> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { uri, fileInfo, fetchFileInfo, costInfo, fetchCostInfo } = this.props;
|
const { uri, fileInfo, fetchFileInfo, costInfo, fetchCostInfo } = this.props;
|
||||||
|
|
||||||
|
@ -69,8 +81,13 @@ class FilePage extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAutoplayChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.props.setClientSetting(settings.AUTOPLAY, event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
checkSubscription = (props: Props) => {
|
checkSubscription = (props: Props) => {
|
||||||
if (
|
if (
|
||||||
|
props.claim.value.publisherSignature &&
|
||||||
props.subscriptions
|
props.subscriptions
|
||||||
.map(subscription => subscription.channelName)
|
.map(subscription => subscription.channelName)
|
||||||
.indexOf(props.claim.channel_name) !== -1
|
.indexOf(props.claim.channel_name) !== -1
|
||||||
|
@ -102,6 +119,7 @@ class FilePage extends React.Component<Props> {
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
prepareEdit,
|
prepareEdit,
|
||||||
navigate,
|
navigate,
|
||||||
|
autoplay,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// File info
|
// File info
|
||||||
|
@ -177,6 +195,15 @@ class FilePage extends React.Component<Props> {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<FormRow alignRight>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="autoplay"
|
||||||
|
onChange={this.onAutoplayChange}
|
||||||
|
checked={autoplay}
|
||||||
|
postfix={__('Autoplay')}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
|
|
|
@ -26,6 +26,7 @@ const select = state => ({
|
||||||
language: selectCurrentLanguage(state),
|
language: selectCurrentLanguage(state),
|
||||||
languages: selectLanguages(state),
|
languages: selectLanguages(state),
|
||||||
automaticDarkModeEnabled: makeSelectClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED)(state),
|
automaticDarkModeEnabled: makeSelectClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED)(state),
|
||||||
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state)
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Props = {
|
||||||
currentTheme: string,
|
currentTheme: string,
|
||||||
themes: Array<string>,
|
themes: Array<string>,
|
||||||
automaticDarkModeEnabled: boolean,
|
automaticDarkModeEnabled: boolean,
|
||||||
|
autoplay: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -53,6 +54,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
(this: any).onShareDataChange = this.onShareDataChange.bind(this);
|
(this: any).onShareDataChange = this.onShareDataChange.bind(this);
|
||||||
(this: any).onThemeChange = this.onThemeChange.bind(this);
|
(this: any).onThemeChange = this.onThemeChange.bind(this);
|
||||||
(this: any).onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this);
|
(this: any).onAutomaticDarkModeChange = this.onAutomaticDarkModeChange.bind(this);
|
||||||
|
(this: any).onAutoplayChange = this.onAutoplayChange.bind(this);
|
||||||
(this: any).clearCache = this.clearCache.bind(this);
|
(this: any).clearCache = this.clearCache.bind(this);
|
||||||
// (this: any).onLanguageChange = this.onLanguageChange.bind(this)
|
// (this: any).onLanguageChange = this.onLanguageChange.bind(this)
|
||||||
}
|
}
|
||||||
|
@ -95,6 +97,10 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
this.props.setClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED, value);
|
this.props.setClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAutoplayChange(event: SyntheticInputEvent<*>) {
|
||||||
|
this.props.setClientSetting(settings.AUTOPLAY, event.target.checked);
|
||||||
|
}
|
||||||
|
|
||||||
onInstantPurchaseEnabledChange(enabled: boolean) {
|
onInstantPurchaseEnabledChange(enabled: boolean) {
|
||||||
this.props.setClientSetting(settings.INSTANT_PURCHASE_ENABLED, enabled);
|
this.props.setClientSetting(settings.INSTANT_PURCHASE_ENABLED, enabled);
|
||||||
}
|
}
|
||||||
|
@ -138,6 +144,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
currentTheme,
|
currentTheme,
|
||||||
themes,
|
themes,
|
||||||
automaticDarkModeEnabled,
|
automaticDarkModeEnabled,
|
||||||
|
autoplay
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||||
|
@ -239,6 +246,13 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
</section>
|
</section>
|
||||||
<section className="card card--section">
|
<section className="card card--section">
|
||||||
<div className="card__title">{__('Content Settings')}</div>
|
<div className="card__title">{__('Content Settings')}</div>
|
||||||
|
<FormField
|
||||||
|
type="checkbox"
|
||||||
|
name="autoplay"
|
||||||
|
onChange={this.onAutoplayChange}
|
||||||
|
checked={autoplay}
|
||||||
|
postfix={__('Autoplay media files')}
|
||||||
|
/>
|
||||||
<FormField
|
<FormField
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="show_unavailable"
|
name="show_unavailable"
|
||||||
|
|
|
@ -24,6 +24,7 @@ const defaultState = {
|
||||||
theme: getLocalStorageSetting(SETTINGS.THEME, 'light'),
|
theme: getLocalStorageSetting(SETTINGS.THEME, 'light'),
|
||||||
themes: getLocalStorageSetting(SETTINGS.THEMES, []),
|
themes: getLocalStorageSetting(SETTINGS.THEMES, []),
|
||||||
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
||||||
|
autoplay: getLocalStorageSetting(SETTINGS.AUTOPLAY, false)
|
||||||
},
|
},
|
||||||
isNight: false,
|
isNight: false,
|
||||||
languages: {},
|
languages: {},
|
||||||
|
|
|
@ -168,12 +168,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: $spacing-width 0;
|
padding: $spacing-width 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__channel-info--large {
|
.card__channel-info--large {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
padding-bottom: $spacing-width;
|
padding-bottom: $spacing-vertical * 2/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__content {
|
.card__content {
|
||||||
|
|
|
@ -59,7 +59,11 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content__loading-text {
|
.content__loading-text {
|
||||||
|
|
|
@ -23,6 +23,10 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.form-row--right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
.form-field.form-field--stretch {
|
.form-field.form-field--stretch {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue