Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notification and filter. #5284

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions app/components-react/windows/go-live/CommonPlatformFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { TLayoutMode } from './platforms/PlatformSettingsLayout';
import { Services } from '../../service-provider';
import AiHighlighterToggle from './AiHighlighterToggle';
import { EAvailableFeatures } from 'services/incremental-rollout';
import * as remote from '@electron/remote';
import InfoBanner from 'components-react/shared/InfoBanner';
import { EDismissable } from 'services/dismissables';

interface ICommonPlatformSettings {
title: string;
Expand Down Expand Up @@ -68,8 +71,6 @@ export const CommonPlatformFields = InputComponent((rawProps: IProps) => {
? p.descriptionIsRequired
: p.platform === 'facebook';

const user = Services.UserService.views;

const hasDescription = p.platform
? view.supports('description', [p.platform as TPlatform])
: view.supports('description');
Expand All @@ -91,17 +92,15 @@ export const CommonPlatformFields = InputComponent((rawProps: IProps) => {
}

const titleTooltip = useMemo(() => {
if (enabledPlatforms.includes('tiktok')) {
return $t('Only 32 characters of your title will display on TikTok');
}

if (enabledPlatforms.length === 1 && p?.platform === 'kick') {
return $t('Edit your stream title on Kick after going live.');
}

return undefined;
}, [enabledPlatforms]);

const shouldShowTikTokWarning = Services.TikTokService.shouldShowTikTokWarning;

return (
<div>
{/* USE CUSTOM CHECKBOX */}
Expand Down Expand Up @@ -146,9 +145,28 @@ export const CommonPlatformFields = InputComponent((rawProps: IProps) => {
!enabledPlatforms.includes('twitch') && (
<AiHighlighterToggle game={undefined} cardIsExpanded={false} />
)}

{shouldShowTikTokWarning && <TikTokNoty />}
</div>
)}
</Animate>
</div>
);
});

function TikTokNoty() {
return (
<InfoBanner
id="tiktok-noty"
message={$t('Streaming to TikTok may not work due to ban in effect. Learn more here.')}
type="warning"
onClick={openConfirmation}
style={{ marginBottom: '15px', marginLeft: '20%', width: '80%' }}
dismissableKey={EDismissable.TikTokBanned}
/>
);
}

function openConfirmation() {
remote.shell.openExternal(Services.TikTokService.notificationUrl);
}
184 changes: 8 additions & 176 deletions app/components-react/windows/go-live/DestinationSwitchers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@ import React, { useRef, MouseEvent } from 'react';
import { getPlatformService, TPlatform } from '../../../services/platforms';
import cx from 'classnames';
import { $t } from '../../../services/i18n';
import * as remote from '@electron/remote';
import styles from './DestinationSwitchers.m.less';
import { ICustomStreamDestination } from '../../../services/settings/streaming';
import { Services } from '../../service-provider';
import { SwitchInput } from '../../shared/inputs';
import PlatformLogo from '../../shared/PlatformLogo';
import { useDebounce } from '../../hooks';
import { useGoLiveSettings } from './useGoLiveSettings';
import { alertAsync } from '../../modals';
import { ModalLayout } from 'components-react/shared/ModalLayout';
import { Button, Form, Modal } from 'antd';
import Translate from 'components-react/shared/Translate';

/**
* Allows enabling/disabling platforms and custom destinations for the stream
Expand All @@ -27,28 +22,23 @@ export function DestinationSwitchers(p: { showSelector?: boolean }) {
switchPlatforms,
switchCustomDestination,
isPrimaryPlatform,
isPlatformLinked,
isRestreamEnabled,
} = useGoLiveSettings();
// use these references to apply debounce
// for error handling and switch animation
const enabledPlatformsRef = useRef(enabledPlatforms);
enabledPlatformsRef.current = enabledPlatforms;

const enabledDestRef = useRef(enabledDestinations);
enabledDestRef.current = enabledDestinations;

// special handling for TikTok for non-ultra users
// to disable/enable platforms and open ultra link
const promptConnectTikTok = !isPlatformLinked('tiktok');

const shouldDisableCustomDestinationSwitchers = () => {
// Multistream users can always add destinations
if (isRestreamEnabled) {
return false;
}

// Otherwise, only a single platform and no custom destinations,
// TikTok should be handled by platform switching
// Otherwise, only a single platform and no custom destinations
return enabledPlatforms.length > 0;
};

Expand All @@ -66,48 +56,17 @@ export function DestinationSwitchers(p: { showSelector?: boolean }) {
if (typeof target === 'number') {
return enabledDestRef.current.includes(target);
} else {
if (target === 'tiktok' && promptConnectTikTok) {
return false;
}

return enabledPlatformsRef.current.includes(target);
}
}

function togglePlatform(platform: TPlatform, enabled: boolean) {
// On non multistream mode, switch the platform that was just selected while disabling all the others,
// allow TikTok to be added as an extra platform
if (!isRestreamEnabled) {
/*
* If TikTok is the platform being toggled:
* - Preserve the currently active platform so TikTok can be added to this list at the bottom of this function,
* we will have 2 active platforms and a Primary Chat switcher.
* - Remove TikTok from the list without removing the other active platform if we're disabling TikTok itself.
* Clearing this list ensures that when a new platform is selected, instead of enabling 2 platforms
* we switch to 1 enabled platforms that was just toggled.
*/
if (platform === 'tiktok') {
if (enabled) {
/*
* If we had two platforms, none of which were tiktok, we still need to limit
* that to 1 platform without restreaming.
* This could happen when coming from having dual output enabled to off.
* TODO: this might not be needed after #5244, keeping here for a while for extra care
*/
enabledPlatformsRef.current = enabledPlatformsRef.current.slice(0, 1);
} else {
enabledPlatformsRef.current = enabledPlatformsRef.current.filter(
platform => platform !== 'tiktok',
);
}
} else {
/*
* Clearing this list ensures that when a new platform is selected, instead of enabling 2 platforms
* we switch to 1 enabled platforms that was just toggled.
* We will also preserve TikTok as an active platform if it was before.
*/
enabledPlatformsRef.current = enabledPlatformsRef.current.includes('tiktok')
? ['tiktok']
: [];
}
enabledPlatformsRef.current = [];
} else {
enabledPlatformsRef.current = enabledPlatformsRef.current.filter(p => p !== platform);
}
Expand All @@ -124,18 +83,6 @@ export function DestinationSwitchers(p: { showSelector?: boolean }) {
emitSwitch();
}

function toggleDest(ind: number, enabled: boolean) {
enabledDestRef.current = enabledDestRef.current.filter(index => index !== ind);
if (enabled) {
enabledDestRef.current.push(ind);
}
emitSwitch(ind, enabled);
}

// TODO: find a cleaner way to do this
const isPrimary = (platform: TPlatform) =>
isPrimaryPlatform(platform) || linkedPlatforms.length === 1;

return (
<div className={cx(styles.switchWrapper, styles.columnPadding)}>
{linkedPlatforms.map(platform => (
Expand All @@ -144,21 +91,10 @@ export function DestinationSwitchers(p: { showSelector?: boolean }) {
destination={platform}
enabled={isEnabled(platform)}
onChange={enabled => togglePlatform(platform, enabled)}
promptConnectTikTok={platform === 'tiktok' && promptConnectTikTok}
isPrimary={isPrimaryPlatform(platform)}
/>
))}

{!linkedPlatforms.includes('tiktok') && (
<DestinationSwitcher
destination={'tiktok'}
enabled={isEnabled('tiktok')}
onChange={enabled => togglePlatform('tiktok', enabled)}
isPrimary={isPrimaryPlatform('tiktok')}
promptConnectTikTok={promptConnectTikTok}
/>
)}

{customDestinations?.map((dest, ind) => (
<DestinationSwitcher
key={ind}
Expand All @@ -177,7 +113,6 @@ interface IDestinationSwitcherProps {
enabled: boolean;
onChange: (enabled: boolean) => unknown;
isPrimary?: boolean;
promptConnectTikTok?: boolean;
disabled?: boolean;
}

Expand All @@ -191,23 +126,8 @@ const DestinationSwitcher = React.forwardRef<{}, IDestinationSwitcherProps>((p,
const switchInputRef = useRef<HTMLInputElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const platform = typeof p.destination === 'string' ? (p.destination as TPlatform) : null;
const { RestreamService, TikTokService, StreamingService } = Services;
const canEnableRestream = RestreamService.views.canEnableRestream;
const cannotDisableDestination = p.isPrimary && !canEnableRestream;
const showTikTokModal =
p.promptConnectTikTok || (platform === 'tiktok' && TikTokService.missingLiveAccess);

// Preserving old TikTok functionality, so they can't enable the toggle if TikTok is not
// connected.
// TODO: this kind of logic should belong on caller, but ideally we would refactor all this
const tiktokDisabled =
platform === 'tiktok' && !StreamingService.views.isPlatformLinked('tiktok');

function onClickHandler(ev: MouseEvent) {
if (showTikTokModal) {
renderTikTokModal(p.promptConnectTikTok);
}

// If we're disabling the switch we shouldn't be emitting anything past below
if (p.disabled) {
return;
Expand All @@ -218,43 +138,12 @@ const DestinationSwitcher = React.forwardRef<{}, IDestinationSwitcherProps>((p,
// always proxy the click to the SwitchInput
// so it can play a transition animation
switchInputRef.current?.click();

/*
* TODO:
* this causes inconsistent state when disabling primary platform
* after is being re-enabled. Not sure which animation is referring to.
*/
// switch the container class without re-rendering to not stop the animation
/*
if (enable) {
containerRef.current?.classList.remove(styles.platformDisabled);
} else {
containerRef.current?.classList.add(styles.platformDisabled);
}
*/
}

function addClass() {
containerRef.current?.classList.remove(styles.platformDisabled);
}

function removeClass() {
if (p.isPrimary) {
alertAsync(
$t(
'You cannot disable the platform you used to sign in to Streamlabs Desktop. Please sign in with a different platform to disable streaming to this destination.',
),
);
return;
}
p.onChange(false);
containerRef.current?.classList.add(styles.platformDisabled);
}

const { title, description, Switch, Logo } = (() => {
if (platform) {
// define slots for a platform switcher
const { UserService, StreamingService } = Services;
const { UserService } = Services;
const service = getPlatformService(platform);
const platformAuthData = UserService.state.auth?.platforms[platform];
const username = platformAuthData?.username ?? '';
Expand All @@ -266,13 +155,7 @@ const DestinationSwitcher = React.forwardRef<{}, IDestinationSwitcherProps>((p,
<PlatformLogo platform={platform} className={styles[`platform-logo-${platform}`]} />
),
Switch: () => (
<SwitchInput
inputRef={switchInputRef}
value={p.enabled}
name={platform}
disabled={tiktokDisabled}
uncontrolled
/>
<SwitchInput inputRef={switchInputRef} value={p.enabled} name={platform} uncontrolled />
),
};
} else {
Expand All @@ -299,7 +182,7 @@ const DestinationSwitcher = React.forwardRef<{}, IDestinationSwitcherProps>((p,
<div
ref={containerRef}
className={cx(styles.platformSwitcher, {
[styles.platformDisabled]: !p.enabled || p.promptConnectTikTok,
[styles.platformDisabled]: !p.enabled,
})}
onClick={onClickHandler}
>
Expand All @@ -320,54 +203,3 @@ const DestinationSwitcher = React.forwardRef<{}, IDestinationSwitcherProps>((p,
</div>
);
});

export function renderTikTokModal(promptConnectTikTok?: boolean) {
const { TikTokService } = Services;

const message = promptConnectTikTok
? $t('Connect your TikTok account to stream to TikTok and one additional platform for free.')
: $t(
"Connect your TikTok account to stream to TikTok and one other platform for free. Haven't applied to stream on TikTok Live yet? <link>Start the process here</link>.",
{ link: <a href={TikTokService.applicationUrl} /> },
);

function openApplicationInfoPage() {
remote.shell.openExternal(Services.TikTokService.applicationUrl);
}

alertAsync({
bodyStyle: { padding: '24px' },
className: styles.tiktokModal,
type: 'confirm',
title: $t('Connect your TikTok Account'),
content: (
<Translate message={message}>
<a slot="link" onClick={openApplicationInfoPage} style={{ textDecoration: 'underline' }} />
</Translate>
),
icon: <PlatformLogo platform="tiktok" className={styles.tiktokModalLogo} />,
closable: true,
maskClosable: true,
cancelButtonProps: { style: { display: 'none' } },
okButtonProps: { style: { display: 'none' } },
modalRender: node => <ModalLayout footer={<TikTokModalFooter />}>{node}</ModalLayout>,
width: 600,
});
}

function TikTokModalFooter() {
function connect() {
Modal.destroyAll();
Services.NavigationService.actions.navigate('PlatformMerge', { platform: 'tiktok' });
Services.WindowsService.actions.closeChildWindow();
}

return (
<Form layout={'inline'} className={styles.tiktokModalFooter}>
<Button onClick={Modal.destroyAll}>{$t('Skip')}</Button>
<Button type="primary" onClick={connect}>
{$t('Connect TikTok Account')}
</Button>
</Form>
);
}
Loading
Loading