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

Highlighter: ui updates installing - uninstalling highlighter #5282

Merged
merged 17 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 13 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
4 changes: 2 additions & 2 deletions app/components-react/highlighter/ClipsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function ClipsView({
emitSetView: (data: IViewState) => void;
}) {
const { HighlighterService, UsageStatisticsService, IncrementalRolloutService } = Services;
const aiHighlighterEnabled = IncrementalRolloutService.views.featureIsEnabled(
const aiHighlighterFeatureEnabled = IncrementalRolloutService.views.featureIsEnabled(
EAvailableFeatures.aiHighlighter,
);
const clipsAmount = useVuex(() => HighlighterService.views.clips.length);
Expand Down Expand Up @@ -215,7 +215,7 @@ export default function ClipsView({
}}
/>
{streamId &&
aiHighlighterEnabled &&
aiHighlighterFeatureEnabled &&
HighlighterService.getClips(HighlighterService.views.clips, props.id)
.filter(clip => clip.source === 'AiClip')
.every(clip => (clip as IAiClip).aiInfo.metadata?.round) && (
Expand Down
35 changes: 25 additions & 10 deletions app/components-react/highlighter/SettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function SettingsView({
HighlighterService,
IncrementalRolloutService,
} = Services;
const aiHighlighterEnabled = IncrementalRolloutService.views.featureIsEnabled(
const aiHighlighterFeatureEnabled = IncrementalRolloutService.views.featureIsEnabled(
EAvailableFeatures.aiHighlighter,
);
const [hotkey, setHotkey] = useState<IHotkey | null>(null);
Expand All @@ -38,6 +38,7 @@ export default function SettingsView({
settingsValues: SettingsService.views.values,
isStreaming: StreamingService.isStreaming,
useAiHighlighter: HighlighterService.views.useAiHighlighter,
highlighterVersion: HighlighterService.views.highlighterVersion,
}));

const correctlyConfigured =
Expand Down Expand Up @@ -124,7 +125,7 @@ export default function SettingsView({
</p>
</div>
<div style={{ display: 'flex', gap: '16px' }}>
{aiHighlighterEnabled && (
{aiHighlighterFeatureEnabled && (
<Button type="primary" onClick={() => emitSetView({ view: EHighlighterView.STREAM })}>
{$t('Stream Highlights')}
</Button>
Expand All @@ -139,7 +140,7 @@ export default function SettingsView({
<Scrollable style={{ flexGrow: 1, padding: '20px 20px 20px 20px', width: '100%' }}>
<div className={styles.innerScrollWrapper}>
<div className={styles.cardWrapper}>
{aiHighlighterEnabled && (
{aiHighlighterFeatureEnabled && (
<div className={styles.highlighterCard}>
<div className={styles.cardHeaderbarWrapper}>
<div className={styles.cardHeaderbar}>
Expand All @@ -155,18 +156,32 @@ export default function SettingsView({
)}
</p>

<SwitchInput
style={{ margin: 0, marginLeft: '-10px' }}
size="default"
value={v.useAiHighlighter}
onChange={toggleUseAiHighlighter}
/>
{v.highlighterVersion !== '' ? (
<SwitchInput
style={{ margin: 0, marginLeft: '-10px' }}
size="default"
value={v.useAiHighlighter}
onChange={toggleUseAiHighlighter}
/>
) : (
<Button
style={{ width: 'fit-content' }}
type="primary"
onClick={() => {
HighlighterService.installAiHighlighter(true);
marvinoffers marked this conversation as resolved.
Show resolved Hide resolved
}}
>
Install AI Highlighter
marvinoffers marked this conversation as resolved.
Show resolved Hide resolved
</Button>
)}
<div className={styles.recommendedCorner}>{$t('Recommended')}</div>
</div>
)}
<div className={styles.manualCard}>
<h3 className={styles.cardHeaderTitle}>
{aiHighlighterEnabled ? 'Or use the manual highlighter ' : 'Manual highlighter'}
{aiHighlighterFeatureEnabled
? 'Or use the manual highlighter '
: 'Manual highlighter'}
marvinoffers marked this conversation as resolved.
Show resolved Hide resolved
</h3>
<p>
{$t(
Expand Down
33 changes: 20 additions & 13 deletions app/components-react/highlighter/StreamView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default function StreamView({ emitSetView }: { emitSetView: (data: IViewS
exportInfo: HighlighterService.views.exportInfo,
error: HighlighterService.views.error,
uploadInfo: HighlighterService.views.uploadInfo,
highlighterVersion: HighlighterService.views.highlighterVersion,
}));

// Below is only used because useVueX doesnt work as expected
Expand Down Expand Up @@ -205,6 +206,8 @@ export default function StreamView({ emitSetView }: { emitSetView: (data: IViewS
}

function onDrop(e: React.DragEvent<HTMLDivElement>) {
if (v.highlighterVersion === '') return;

const extensions = SUPPORTED_FILE_TYPES.map(e => `.${e}`);
const files: string[] = [];
let fi = e.dataTransfer.files.length;
Expand Down Expand Up @@ -237,18 +240,20 @@ export default function StreamView({ emitSetView }: { emitSetView: (data: IViewS
<h1 style={{ margin: 0 }}>{$t('My Stream Highlights')}</h1>
</div>
<div style={{ display: 'flex', gap: '16px' }}>
<div
className={styles.uploadWrapper}
style={{
opacity: aiDetectionInProgress ? '0.7' : '1',
cursor: aiDetectionInProgress ? 'not-allowed' : 'pointer',
}}
onClick={() => !aiDetectionInProgress && setShowModal({ type: 'upload' })}
>
<FortniteIcon />
{$t('Select your Fortnite recording')}
<Button disabled={aiDetectionInProgress === true}>{$t('Import')}</Button>
</div>
{v.highlighterVersion !== '' && (
<div
className={styles.uploadWrapper}
style={{
opacity: aiDetectionInProgress ? '0.7' : '1',
cursor: aiDetectionInProgress ? 'not-allowed' : 'pointer',
}}
onClick={() => !aiDetectionInProgress && setShowModal({ type: 'upload' })}
>
<FortniteIcon />
{$t('Select your Fortnite recording')}
<Button disabled={aiDetectionInProgress === true}>{$t('Import')}</Button>
</div>
)}
<Button onClick={() => emitSetView({ view: EHighlighterView.SETTINGS })}>
{$t('Settings')}
</Button>
Expand Down Expand Up @@ -297,7 +302,9 @@ export default function StreamView({ emitSetView }: { emitSetView: (data: IViewS
keyboard={false}
>
{!!v.error && <Alert message={v.error} type="error" showIcon />}
{showModal?.type === 'upload' && <ImportStreamModal close={closeModal} />}
{showModal?.type === 'upload' && v.highlighterVersion !== '' && (
<ImportStreamModal close={closeModal} />
)}
{showModal?.type === 'export' && <ExportModal close={closeModal} streamId={showModal.id} />}
{showModal?.type === 'preview' && (
<PreviewModal close={closeModal} streamId={showModal.id} />
Expand Down
16 changes: 10 additions & 6 deletions app/components-react/pages/Highlighter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EAvailableFeatures } from 'services/incremental-rollout';

export default function Highlighter(props: { params?: { view: string } }) {
const { HighlighterService, IncrementalRolloutService } = Services;
const aiHighlighterEnabled = IncrementalRolloutService.views.featureIsEnabled(
const aiHighlighterFeatureEnabled = IncrementalRolloutService.views.featureIsEnabled(
EAvailableFeatures.aiHighlighter,
);
const v = useVuex(() => ({
Expand All @@ -24,7 +24,11 @@ export default function Highlighter(props: { params?: { view: string } }) {

let initialViewState: IViewState;

if (v.streamAmount > 0 && v.clipsAmount > 0 && aiHighlighterEnabled) {
if (props.params?.view) {
const view =
props.params?.view === 'settings' ? EHighlighterView.SETTINGS : EHighlighterView.STREAM;
initialViewState = { view };
} else if (v.streamAmount > 0 && v.clipsAmount > 0 && aiHighlighterFeatureEnabled) {
initialViewState = { view: EHighlighterView.STREAM };
} else if (v.clipsAmount > 0) {
initialViewState = { view: EHighlighterView.CLIPS, id: undefined };
Expand All @@ -37,7 +41,7 @@ export default function Highlighter(props: { params?: { view: string } }) {
async function shouldUpdate() {
if (!HighlighterService.aiHighlighterUpdater) return false;
const versionAvailable = await HighlighterService.aiHighlighterUpdater.isNewVersionAvailable();
return versionAvailable && aiHighlighterEnabled && v.useAiHighlighter;
return versionAvailable && aiHighlighterFeatureEnabled && v.useAiHighlighter;
}

shouldUpdate().then(shouldUpdate => {
Expand All @@ -58,7 +62,7 @@ export default function Highlighter(props: { params?: { view: string } }) {
case EHighlighterView.STREAM:
return (
<>
{aiHighlighterEnabled && updaterModal}
{aiHighlighterFeatureEnabled && updaterModal}
<StreamView
emitSetView={data => {
setViewFromEmit(data);
Expand All @@ -69,7 +73,7 @@ export default function Highlighter(props: { params?: { view: string } }) {
case EHighlighterView.CLIPS:
return (
<>
{aiHighlighterEnabled && updaterModal}
{aiHighlighterFeatureEnabled && updaterModal}
<ClipsView
emitSetView={data => {
setViewFromEmit(data);
Expand All @@ -86,7 +90,7 @@ export default function Highlighter(props: { params?: { view: string } }) {
default:
return (
<>
{aiHighlighterEnabled && updaterModal}
{aiHighlighterFeatureEnabled && updaterModal}
<SettingsView
close={() => {
HighlighterService.actions.dismissTutorial();
Expand Down
105 changes: 96 additions & 9 deletions app/components-react/pages/PlatformAppStore.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import Utils from 'services/utils';
import urlLib from 'url';
import BrowserView from 'components-react/shared/BrowserView';
import { GuestApiHandler } from 'util/guest-api-handler';
import * as remote from '@electron/remote';
import { Services } from 'components-react/service-provider';
import { Button } from 'antd';
import { EMenuItemKey } from 'services/side-nav';
import { $t } from 'services/i18n';

export default function PlatformAppStore(p: { params: { appId?: string; type?: string } }) {
const { UserService, PlatformAppsService, PlatformAppStoreService, NavigationService } = Services;
const {
UserService,
PlatformAppsService,
PlatformAppStoreService,
NavigationService,
HighlighterService,
} = Services;
const [highlighterInstalled, setHighlighterInstalled] = useState<boolean>(
HighlighterService.views.highlighterVersion !== '',
);
const [platformAppsUrl, setPlatformAppsUrl] = useState('');

const [currentUrl, setCurrentUrl] = useState<string>('');
const browser = useRef<any>(null);
useEffect(() => {
marvinoffers marked this conversation as resolved.
Show resolved Hide resolved
async function getPlatformAppsUrl() {
const url = await UserService.views.appStoreUrl(p.params);
Expand Down Expand Up @@ -69,11 +82,85 @@ export default function PlatformAppStore(p: { params: { appId?: string; type?: s

if (!platformAppsUrl) return <></>;
return (
<BrowserView
style={{ position: 'absolute', top: 0, right: 0, bottom: 0, left: 0 }}
src={platformAppsUrl}
onReady={onBrowserViewReady}
enableGuestApi
/>
<>
<BrowserView
style={{
position: 'absolute',
top: 0,
right: 0,
left: 0,
height: `calc(100% - ${
currentUrl.includes('installed-apps') &&
HighlighterService.views.highlighterVersion !== ''
? '72'
: '0'
}px)`,
}}
src={platformAppsUrl}
onReady={onBrowserViewReady}
enableGuestApi
emitUrlChange={url => {
setCurrentUrl(url);
}}
/>
{currentUrl.includes('installed-apps') && highlighterInstalled && (
<div
style={{
display: 'flex',
gap: '16px',
position: 'absolute',
bottom: 0,
height: '72px',
alignItems: 'center',
padding: '8px',
}}
>
<div>{$t('Other installed apps:')}</div>
<div
style={{
borderRadius: 8,
border: '1px solid #30383D',
display: 'flex',
gap: '16px',
padding: '8px',
paddingLeft: '16px',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
marvinoffers marked this conversation as resolved.
Show resolved Hide resolved
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<h3 style={{ margin: 0 }}>AI Highlighter</h3>
<p style={{ opacity: 0.3, margin: 0 }}>by Streamlabs</p>
</div>
<div style={{ display: 'flex', gap: '8px' }}>
<Button
size="middle"
type="default"
onClick={() => {
setHighlighterInstalled(false);
HighlighterService.uninstallAiHighlighter();
}}
>
{$t('Uninstall')}
</Button>

<Button
size="middle"
type="primary"
onClick={() => {
NavigationService.actions.navigate(
'Highlighter',
{ view: 'settings' },
EMenuItemKey.Highlighter,
);
}}
>
{$t('Open')}
</Button>
</div>
</div>
</div>
)}
</>
);
}
21 changes: 18 additions & 3 deletions app/components-react/pages/RecordingHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class RecordingHistoryController {
);
}

get highlighterVersion() {
return this.HighlighterService.views.highlighterVersion;
}

get uploadOptions() {
const opts = [
{
Expand Down Expand Up @@ -200,15 +204,23 @@ export default function RecordingHistoryPage() {
export function RecordingHistory() {
const controller = useController(RecordingHistoryCtx);
const { formattedTimestamp, showFile, handleSelect, postError } = controller;
const aiHighlighterEnabled = Services.IncrementalRolloutService.views.featureIsEnabled(
const aiHighlighterFeatureEnabled = Services.IncrementalRolloutService.views.featureIsEnabled(
EAvailableFeatures.aiHighlighter,
);
const { uploadInfo, uploadOptions, recordings, hasSLID, aiDetectionInProgress } = useVuex(() => ({
const {
uploadInfo,
uploadOptions,
recordings,
hasSLID,
aiDetectionInProgress,
highlighterVersion,
} = useVuex(() => ({
recordings: controller.recordings,
aiDetectionInProgress: controller.aiDetectionInProgress,
uploadOptions: controller.uploadOptions,
uploadInfo: controller.uploadInfo,
hasSLID: controller.hasSLID,
highlighterVersion: controller.highlighterVersion,
}));

useEffect(() => {
Expand All @@ -231,7 +243,10 @@ export function RecordingHistory() {
<span className={styles.actionGroup}>
{uploadOptions
.map(option => {
if (option.value === 'highlighter' && !aiHighlighterEnabled) {
if (
option.value === 'highlighter' &&
(!aiHighlighterFeatureEnabled || highlighterVersion === '')
) {
return null;
}
return (
Expand Down
Loading
Loading