Skip to content

Commit 0d39b7d

Browse files
authored
Fix inconsistent go live experiences with custom stream settings and … (#5500)
* Fix inconsistent go live experiences with custom stream settings and dual output * Code review * Don't move to video settings when enabling custom rtmp * Keep stream settings open * Fix console errors * Port NavigationService to realm * Remove unused function * Fix CI error
1 parent d4d14ab commit 0d39b7d

File tree

17 files changed

+185
-72
lines changed

17 files changed

+185
-72
lines changed

app/components-react/editor/elements/SourceSelector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ class SourceSelectorController {
669669
// only open video settings when toggling on dual output
670670
const skipShowVideoSettings = this.dualOutputService.views.dualOutputMode === true;
671671

672-
this.dualOutputService.actions.setDualOutputMode(
672+
this.dualOutputService.actions.setDualOutputModeIfPossible(
673673
!this.dualOutputService.views.dualOutputMode,
674674
skipShowVideoSettings,
675675
);
@@ -708,7 +708,7 @@ class SourceSelectorController {
708708
handleAuth() {
709709
this.userService.actions.showLogin();
710710
const onboardingCompleted = Services.OnboardingService.onboardingCompleted.subscribe(() => {
711-
Services.DualOutputService.actions.setDualOutputMode();
711+
Services.DualOutputService.actions.setDualOutputModeIfPossible();
712712
Services.SettingsService.actions.showSettings('Video');
713713
onboardingCompleted.unsubscribe();
714714
});

app/components-react/shared/DualOutputToggle.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export default function DualOutputToggle(p: IDualOutputToggleProps) {
5757
}
5858

5959
// toggle dual output
60-
DualOutputService.actions.setDualOutputMode(!v.dualOutputMode, true, true);
60+
DualOutputService.actions.setDualOutputModeIfPossible(!v.dualOutputMode, true, true);
6161

6262
if (v.dualOutputMode) {
6363
UsageStatisticsService.recordFeatureUsage('DualOutput');

app/components-react/sidebar/NavTools.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export default function SideNav() {
101101

102102
const handleAuth = () => {
103103
if (isLoggedIn) {
104-
Services.DualOutputService.actions.setDualOutputMode(false, true);
104+
Services.DualOutputService.actions.setDualOutputModeIfPossible(false, true);
105105
UserService.actions.logOut();
106106
} else {
107107
WindowsService.actions.closeChildWindow();

app/components-react/windows/go-live/GoLiveWindow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function ModalFooter() {
7676
},
7777

7878
toggleDualOutputMode() {
79-
this.dualOutputService.actions.setDualOutputMode(false, true, true);
79+
this.dualOutputService.actions.setDualOutputModeIfPossible(false, true, true);
8080
},
8181

8282
get horizontalHasTargets() {

app/components-react/windows/settings/Hotkeys.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,35 @@ export default function Hotkeys(props: HotkeysProps) {
5555
const [hotkeySet, setHotkeysSet] = useState<IHotkeysSet | null>(null);
5656

5757
useEffect(() => {
58+
let isMounted = true;
5859
if (!hotkeySet) {
5960
// We don't want hotkeys registering while trying to bind.
6061
// We may change our minds on this in the future.
6162
HotkeysService.actions.unregisterAll();
6263

6364
HotkeysService.actions.return
6465
.getHotkeysSet()
65-
.then(setHotkeysSet)
66+
.then((hotkeys: IHotkeysSet) => {
67+
if (!isMounted) return;
68+
setHotkeysSet(hotkeys);
69+
})
6670
.then(() => highlightSearch(searchString));
6771
}
6872

6973
return () => {
7074
if (hotkeySet) {
7175
HotkeysService.actions.applyHotkeySet(hotkeySet);
7276
}
77+
isMounted = false;
7378
};
7479
}, [hotkeySet]);
7580

81+
// Highlight search results when the search string changes
82+
useEffect(() => {
83+
if (!searchString) return;
84+
highlightSearch(searchString);
85+
}, [searchString]);
86+
7687
const emptyHotkeySet: IAugmentedHotkeySet = {
7788
general: {},
7889
sources: {},
@@ -117,9 +128,6 @@ export default function Hotkeys(props: HotkeysProps) {
117128
return filteredHotkeySet;
118129
}, [augmentedHotkeySet, searchString]);
119130

120-
// Highlight search results when the search string changes
121-
useEffect(() => highlightSearch(searchString), [searchString]);
122-
123131
if (!hotkeySet) {
124132
return <div />;
125133
}

app/components-react/windows/settings/Stream.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ class StreamSettingsModule {
109109
return Services.CustomizationService;
110110
}
111111

112+
private get dualOutputService() {
113+
return Services.DualOutputService;
114+
}
115+
112116
// DEFINE MUTATIONS
113117

114118
@mutation()
@@ -182,6 +186,9 @@ class StreamSettingsModule {
182186

183187
disableProtectedMode() {
184188
this.streamSettingsService.actions.setSettings({ protectedModeEnabled: false });
189+
if (this.dualOutputService.views.dualOutputMode) {
190+
this.dualOutputService.actions.setDualOutputModeIfPossible(false, true);
191+
}
185192
}
186193

187194
enableProtectedMode() {

app/components-react/windows/settings/Video.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ class VideoSettingsModule {
389389
*/
390390
setFPSType(value: EFPSType) {
391391
const obsSettings: ObsSetting[] = [
392-
{ key: 'fpsType', value: value },
392+
{ key: 'fpsType', value },
393393
{ key: 'fpsNum', value: 30 },
394394
{ key: 'fpsDen', value: 1 },
395395
];
@@ -503,7 +503,7 @@ class VideoSettingsModule {
503503
}
504504

505505
// toggle dual output
506-
this.dualOutputService.actions.setDualOutputMode(
506+
this.dualOutputService.actions.setDualOutputModeIfPossible(
507507
!this.dualOutputService.views.dualOutputMode,
508508
);
509509
this.state.setShowDualOutputSettings(!this.state.showDualOutputSettings);
@@ -527,7 +527,7 @@ class VideoSettingsModule {
527527
Services.WindowsService.actions.closeChildWindow();
528528
this.userService.actions.showLogin();
529529
const onboardingCompleted = Services.OnboardingService.onboardingCompleted.subscribe(() => {
530-
Services.DualOutputService.actions.setDualOutputMode();
530+
Services.DualOutputService.actions.setDualOutputModeIfPossible();
531531
Services.SettingsService.actions.showSettings('Video');
532532
onboardingCompleted.unsubscribe();
533533
});

app/components/windows/Main.vue.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ Vue.use(VueResize);
3232

3333
// Pages
3434
import { Inject } from '../../services/core/injector';
35-
import { CustomizationService, CustomizationState } from 'services/customization';
36-
import { NavigationService } from 'services/navigation';
35+
import { CustomizationService } from 'services/customization';
36+
import { NavigationService, TAppPage } from 'services/navigation';
3737
import { AppService } from 'services/app';
3838
import { UserService } from 'services/user';
3939
import { IModalOptions, WindowsService } from 'services/windows';
@@ -83,21 +83,26 @@ export default class Main extends Vue {
8383
};
8484

8585
theme: Theme = 'night-theme';
86+
page: TAppPage = 'Studio';
8687
minEditorWidth = 500;
8788

8889
created() {
8990
window.addEventListener('resize', this.windowSizeHandler);
9091
}
9192

92-
unbind: () => void;
93+
unbindCustomization: () => void;
94+
unbindNavigation: () => void;
9395

9496
mounted() {
95-
this.unbind = this.customizationService.state.bindProps(this, {
97+
this.unbindCustomization = this.customizationService.state.bindProps(this, {
9698
theme: 'theme',
9799
isDockCollapsed: 'livedockCollapsed',
98100
leftDock: 'leftDock',
99101
liveDockSize: 'livedockSize',
100102
});
103+
this.unbindNavigation = this.navigationService.state.bindProps(this, {
104+
page: 'currentPage',
105+
});
101106

102107
antdThemes[this.theme].use();
103108
WindowsService.modalChanged.subscribe(modalOptions => {
@@ -130,17 +135,14 @@ export default class Main extends Vue {
130135

131136
destroyed() {
132137
window.removeEventListener('resize', this.windowSizeHandler);
133-
this.unbind();
138+
this.unbindCustomization();
139+
this.unbindNavigation();
134140
}
135141

136142
get title() {
137143
return this.windowsService.state.main.title;
138144
}
139145

140-
get page() {
141-
return this.navigationService.state.currentPage;
142-
}
143-
144146
get params() {
145147
return this.navigationService.state.params;
146148
}
@@ -174,7 +176,7 @@ export default class Main extends Vue {
174176
leftDock = false;
175177

176178
get isOnboarding() {
177-
return this.navigationService.state.currentPage === 'Onboarding';
179+
return this.page === 'Onboarding';
178180
}
179181

180182
get platformApps() {

app/components/windows/settings/Settings.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
:contentStyles="{ padding: '0' }"
77
>
88
<div slot="content" class="settings">
9-
<NavMenu v-model="categoryName" class="settings-nav">
9+
<NavMenu
10+
:value="currentSettingsTab"
11+
@input="cat => setCategoryName(cat)"
12+
class="settings-nav"
13+
>
1014
<scrollable style="height: 100%" :isResizable="false">
1115
<form-input
1216
:value="searchStr"
@@ -73,7 +77,7 @@
7377
<scrollable className="settings-container">
7478
<searchable-pages
7579
ref="settingsContainer"
76-
:page="categoryName"
80+
:page="currentSettingsTab"
7781
:pages="categoryNames"
7882
:searchStr="searchStr"
7983
:onBeforePageScan="onBeforePageScanHandler"

app/components/windows/settings/Settings.vue.ts

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { $t } from 'services/i18n';
2929
import { debounce } from 'lodash-decorators';
3030
import * as remote from '@electron/remote';
3131
import Utils from '../../../services/utils';
32+
import { NavigationService } from 'app-services';
3233

3334
@Component({
3435
components: {
@@ -57,6 +58,7 @@ export default class Settings extends Vue {
5758
@Inject() userService: UserService;
5859
@Inject() dismissablesService: DismissablesService;
5960
@Inject() dualOutputService: DualOutputService;
61+
@Inject() navigationService: NavigationService;
6062

6163
$refs: { settingsContainer: HTMLElement & SearchablePages };
6264

@@ -88,34 +90,38 @@ export default class Settings extends Vue {
8890
['Appearance']: EDismissable.CustomMenuSettings,
8991
};
9092

91-
internalCategoryName: string = null;
92-
9393
created() {
9494
// Make sure we have the latest settings
9595
this.settingsService.actions.loadSettingsIntoStore();
9696
}
9797

98+
currentSettingsTab = 'General';
99+
100+
unbind: () => void;
101+
102+
mounted() {
103+
this.unbind = this.navigationService.state.bindProps(this, {
104+
currentSettingsTab: 'currentSettingsTab',
105+
});
106+
}
107+
108+
destroyed() {
109+
this.unbind();
110+
}
111+
98112
/**
99113
* Whether we have built a cache of searchable pages already.
100114
* If we havne't - we should debounce the user input.
101115
* If we have - no need to debounce and we should preserve a snappy experience
102116
*/
103117
scanningDone = false;
104118

105-
get categoryName() {
106-
if (this.internalCategoryName == null) {
107-
this.internalCategoryName = this.getInitialCategoryName();
108-
}
109-
110-
return this.internalCategoryName;
111-
}
112-
113119
get settingsData() {
114-
return this.settingsService.state[this.categoryName]?.formData ?? [];
120+
return this.settingsService.state[this.currentSettingsTab]?.formData ?? [];
115121
}
116122

117-
set categoryName(val: string) {
118-
this.internalCategoryName = val;
123+
setCategoryName(val: string) {
124+
this.navigationService.actions.setSettingsNavigation(val);
119125
}
120126

121127
get isPrime() {
@@ -153,11 +159,11 @@ export default class Settings extends Vue {
153159
}
154160

155161
get shouldShowReactPage() {
156-
return this.reactPages.includes(this.categoryName);
162+
return this.reactPages.includes(this.currentSettingsTab);
157163
}
158164

159165
get shouldShowVuePage() {
160-
if (this.reactPages.includes(this.categoryName)) return false;
166+
if (this.reactPages.includes(this.currentSettingsTab)) return false;
161167
return ![
162168
'Stream',
163169
'API',
@@ -169,7 +175,7 @@ export default class Settings extends Vue {
169175
'Installed Apps',
170176
'Virtual Webcam',
171177
'Developer',
172-
].includes(this.categoryName);
178+
].includes(this.currentSettingsTab);
173179
}
174180

175181
getInitialCategoryName() {
@@ -194,7 +200,7 @@ export default class Settings extends Vue {
194200
}
195201

196202
save(settingsData: ISettingsSubCategory[]) {
197-
this.settingsService.setSettings(this.categoryName, settingsData);
203+
this.settingsService.setSettings(this.currentSettingsTab, settingsData);
198204
}
199205

200206
done() {
@@ -210,15 +216,15 @@ export default class Settings extends Vue {
210216

211217
onBeforePageScanHandler(page: string) {
212218
if (this.originalCategory == null) {
213-
this.originalCategory = this.categoryName;
219+
this.originalCategory = this.currentSettingsTab;
214220
}
215221

216-
this.categoryName = page;
222+
this.setCategoryName(page);
217223
}
218224

219225
onScanCompletedHandler() {
220226
this.scanningDone = true;
221-
this.categoryName = this.originalCategory;
227+
this.setCategoryName(this.originalCategory);
222228
this.originalCategory = null;
223229
}
224230

@@ -234,8 +240,8 @@ export default class Settings extends Vue {
234240
this.searchResultPages = foundPages;
235241
}
236242
// if there are not search results for the current page than switch to the first found page
237-
if (foundPages.length && !foundPages.includes(this.categoryName)) {
238-
this.categoryName = foundPages[0];
243+
if (foundPages.length && !foundPages.includes(this.currentSettingsTab)) {
244+
this.setCategoryName(foundPages[0]);
239245
}
240246
}
241247

@@ -264,7 +270,7 @@ export default class Settings extends Vue {
264270
}
265271

266272
highlightSearch(searchStr: string) {
267-
this.$refs.settingsContainer.highlightPage(searchStr);
273+
this.$refs.settingsContainer?.highlightPage(searchStr);
268274
}
269275

270276
handleAuth() {
@@ -279,7 +285,7 @@ export default class Settings extends Vue {
279285
})
280286
.then(({ response }) => {
281287
if (response === 0) {
282-
this.dualOutputService.setDualOutputMode(false, true);
288+
this.dualOutputService.setDualOutputModeIfPossible(false, true);
283289
this.userService.logOut();
284290
}
285291
});

0 commit comments

Comments
 (0)