Skip to content

Commit

Permalink
Platform settings in settings window (stream-labs#901)
Browse files Browse the repository at this point in the history
* tmp commit

* switch to developer settings

* fixed some stuff

* finish file input, dsiable app paltform settings

* remove v-if false

* before embarking on name source refactor (build errors)

* working end to end demo

* hook up app reload

* added popout, reload, uninstalled UI

* banner image support in the showcase

* add ability to copy url for unpacked apps

* add deep nesting support to the guest api

* guest api security

* working modular API system with permissions

* modified guest API system to work in all windows

* support for events over platform API

* more source events

* refactoring and web security/session implementation

* add initial source size with relative and absolute modes

* tmp scenes module

* add basic scenes/sources API

* use dev server intead of file:// protocol

* working script blocking system

* disable eval for security

* use server app id hash instead of manifest app id

* fetch dev mode state from the server

* scene events, dev mode works in child window

* add obs settings api module

* remove example module, add buildPath

* add timeout to reload

* app load validations

* support persistent app slots

* disable main window when app is popped out

* whitelist minified app sdk url

* various fixes

* add a method to switch to a scene

* get build ready for distribution

* disable patch notes for now

* add streaming recording module

* build 2

* first pass authorization module

* switch to protocol redirect instead of navigation

* final touchs on authorization module

* build 3

* ovrstream

* add theme module

* build 4

* added per-source app settings

* expose scene collections schema

* formatting

* build 5

* add sllowPopout option to pages

* external links

* expose available source types

* add app module, and redirect to settings

* build 6

* allow web requests from cross origin iframes that cannot access the parent window

* add/remove sources/sceneitems api

* Platform  load prod app (stream-labs#840)

* can load production apps now

* removed linebreak

* only add app to local storage if unpacked

* update interface name and remove line break

* tagged union pattern

* working with live.platform

* added app store to slobs

* changed icon for store on topnav

* attempting discrim union

* reverted discrim union

* commented out app store

* added logs

* fixed another conflict

* fix popout, add reload button

* Platform  notification api (stream-labs#874)

* added notifications module

* Added notifications module api, tested locally

* uncomment install production apps

* cloned interface and types to isolate data structure between api and rest of slobs

* removed unrequested apis

* removed actions from notifications

* restrict loading apps with duplicate keys (stream-labs#883)

* build 7

* implement hotkeys module

* build 8

* wow I can't type

* guest API improvements

* resolve merge conflict

* back out window title change

* cleanup for settings

* Platform  app store events (stream-labs#871)

* can load production apps now

* removed linebreak

* only add app to local storage if unpacked

* update interface name and remove line break

* tagged union pattern

* working with live.platform

* added app store to slobs

* changed icon for store on topnav

* attempting discrim union

* reverted discrim union

* install App callback from app store

* minor

* commented out app store

* pushing for andy

* removed dev tools

* added logs

* added platform app store service and fix logs

* removed nodeIntegration and popups on app store webview

* fixed more conflict

* fixed another conflict

* only open dev tools for app store if devMode

* fixed andys comments and unload/reload prod apps when login/out

* added nightmode to app store url

* finished chat slot

* uncomment out install prod apps

* devmode -> unpacked

* Platform  production scripts (stream-labs#894)

* can load production apps now

* removed linebreak

* only add app to local storage if unpacked

* update interface name and remove line break

* tagged union pattern

* working with live.platform

* added app store to slobs

* changed icon for store on topnav

* attempting discrim union

* reverted discrim union

* commented out app store

* added logs

* fixed another conflict

* can import scripts in production apps, and append build to filepath only when unpacked

* fixed andys comments

* fixed andys comments

* script request starts with app.url

* removed comment and validatemanifest only if unpacked

* removed logs

* removed log

* fixed conflicts :(

* added settings tab

* add enable to loadedapps

* installed apps []

* can reset and enable, need to handle dup ids

* settings tab to control prod apps

* added icon

* added loadedApp.enabled:boolean

* fix enabled and dup ids

* check if same before setEnable
  • Loading branch information
Nitsorn authored and avacreeth committed Oct 11, 2018
1 parent 97d04f2 commit e8e9b07
Show file tree
Hide file tree
Showing 19 changed files with 338 additions and 38 deletions.
4 changes: 2 additions & 2 deletions app/components/AppPlatformDeveloperSettings.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ export default class AppPlatformDeveloperSettings extends Vue {
this.currentlyLoadedUnpackedApp.appToken : '';

get currentlyLoadedUnpackedApp() {
if (this.platformAppsService.state.loadedApps.length === 0) return null;
if (this.platformAppsService.enabledApps.length === 0) return null;

return this.platformAppsService.state.loadedApps.find(app => app.unpacked);
return this.platformAppsService.enabledApps.find(app => app.unpacked);
}

loading = false;
Expand Down
7 changes: 6 additions & 1 deletion app/components/Chat.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ export default class Chat extends Vue {
const protocol = parsedUrl.protocol;

if (protocol === 'http:' || protocol === 'https:') {
if (parsedUrl.host && parsedUrl.query && (parsedUrl.host === 'twitch.tv' || parsedUrl.host.endsWith('.twitch.tv')) && parsedUrl.query.includes('ffz-settings')) {
if (
parsedUrl.host &&
parsedUrl.query &&
(parsedUrl.host === 'twitch.tv' || parsedUrl.host.endsWith('.twitch.tv')) &&
parsedUrl.query.includes('ffz-settings')
) {
this.windowsService.createOneOffWindow({
componentName: 'FFZSettings',
title: $t('FrankerFaceZ Settings'),
Expand Down
55 changes: 55 additions & 0 deletions app/components/InstalledApps.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<div class="section">
<table>
<thead>
<tr>
<th> {{ $t('icon') }} </th>
<th> {{ $t('name')}} </th>
<th> {{ $t('vers')}} </th>
<th></th>
</tr>
</thead>
<tbody>
<tr
v-for="app in installedApps"
:key="app.id"
>
<td> <img :src="app.icon" alt="-" width='50'> </td>
<td> {{ app.manifest.name }} </td>
<td> {{ app.manifest.version }} </td>
<td>
<button
v-if="isEnabled(app.id)"
@click="reload(app.id)"
class="button button--action">Reload</button>
<button
v-if="noUnpackedVersionLoaded(app.id)"
@click="toggleEnable(app)"
class="button button--default">
{{ isEnabled(app.id) ? 'Disable' : 'Enable' }}
</button>
<div v-else>
<button
disabled
class="button button--default">
{{ $t('Unpacked vers loaded') }}
</button>
<i
v-tooltip.left=" $t('You must unload unpacked version before enabling this app.') "
class="icon-question"
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>

<script lang="ts" src="./InstalledApps.vue.ts"></script>

<style lang="less" scoped>
table td:last-child {
text-align: right;
}
</style>
37 changes: 37 additions & 0 deletions app/components/InstalledApps.vue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Vue from 'vue';
import { Component } from 'vue-property-decorator';
import { Inject } from 'util/injector';
import { PlatformAppsService, ILoadedApp } from 'services/platform-apps';

@Component({})
export default class InstalledApps extends Vue {
@Inject() platformAppsService: PlatformAppsService;

get installedApps() {
// installed == production apps
return this.platformAppsService.productionApps;
}

get enabledInstalledAppIds(): string[] {
return this.installedApps
.filter(app => app.enabled)
.map(app => app.id);
}

isEnabled(appId: string) {
return this.enabledInstalledAppIds.includes(appId);
}

reload(appId: string) {
this.platformAppsService.reloadApp(appId);
}

toggleEnable(app: ILoadedApp) {
if (this.isEnabled(app.id)) this.platformAppsService.setEnabled(app.id, false);
else this.platformAppsService.setEnabled(app.id, true);
}

noUnpackedVersionLoaded(appId: string) {
return !this.platformAppsService.enabledApps.find(app => app.id === appId && app.unpacked);
}
}
42 changes: 40 additions & 2 deletions app/components/LiveDock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,34 @@
<i class="icon-settings" />
</a>
</div>
<a @click="refreshChat" v-if="isTwitch || isMixer || (isYoutube && isStreaming)">{{ $t('Refresh Chat') }}</a>
<div class="flex">
<div v-if="hasChatApps" class="live-dock-chat-apps__list-input flex">
<i
class="live-dock-chat-apps__popout icon-pop-out-1"
v-tooltip.left="$t('Pop out to new window')"
v-if="isPopOutAllowed"
@click="popOut"
/>
<list-input
v-model="selectedChat"
:metadata="chatAppsListMetadata"
/>
</div>
<a @click="refreshChat" v-if="isTwitch || isMixer || (isYoutube && isStreaming)">{{ $t('Refresh Chat') }}</a>
</div>
</div>

<div class="live-dock-chat" v-if="isTwitch || isMixer || (isYoutube && isStreaming)">
<chat ref="chat" />
<chat :style="chatStyles()" ref="chat" />
<PlatformAppWebview
v-for="app in chatApps"
v-if="(app.id === selectedChat) || isAppPersistent(app.id)"
:style="chatStyles(app.id)"
:key="app.id"
class="live-dock-platform-app-webview"
:appId="app.id"
:pageSlot="slot"
/>
</div>
<div class="flex flex--center flex--column live-dock-chat--offline" v-else >
<img class="live-dock-chat__img--offline live-dock-chat__img--offline-day" src="../../media/images/sleeping-kevin-day.png">
Expand Down Expand Up @@ -203,6 +226,7 @@
.live-dock-chat {
flex-grow: 1;
position: relative;
.flex();
}
.live-dock-chat--offline {
Expand Down Expand Up @@ -239,6 +263,20 @@
.flex();
}
.live-dock-chat-apps__list-input {
.margin-right();
}
.live-dock-chat-apps__popout {
.padding();
.cursor--pointer();
}
.live-dock-platform-app-webview {
.flex--grow();
}
.night-theme {
.live-dock {
border-color: @night-border;
Expand Down
88 changes: 85 additions & 3 deletions app/components/LiveDock.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,29 @@ import electron from 'electron';
import { getPlatformService } from 'services/platforms';
import { YoutubeService } from 'services/platforms/youtube';
import { $t } from 'services/i18n';
import PlatformAppWebview from 'components/PlatformAppWebview.vue';
import {
PlatformAppsService,
EAppPageSlot,
ILoadedApp
} from 'services/platform-apps';
import ListInput from 'components/shared/inputs/ListInput.vue';
import { metadata as metadataHelper } from 'components/widgets/inputs';

@Component({
components: {
Chat,
Slider
Slider,
ListInput,
PlatformAppWebview
}
})
export default class LiveDock extends Vue {
@Inject() streamingService: StreamingService;
@Inject() streamInfoService: StreamInfoService;
@Inject() userService: UserService;
@Inject() customizationService: CustomizationService;
@Inject() platformAppsService: PlatformAppsService;

@Prop({ default: false })
onLeft: boolean;
Expand All @@ -34,6 +45,10 @@ export default class LiveDock extends Vue {
chat: Chat;
};

slot = EAppPageSlot.Chat;

selectedChat = 'default';

viewStreamTooltip = $t('Go to Youtube to view your live stream');
editStreamInfoTooltip = $t('Edit your stream title and description');
controlRoomTooltip = $t('Go to Youtube Live Dashboard to control your stream');
Expand Down Expand Up @@ -94,8 +109,7 @@ export default class LiveDock extends Vue {
if (this.streamingStatus === EStreamingState.Live) return 'Live';
if (this.streamingStatus === EStreamingState.Starting) return 'Starting';
if (this.streamingStatus === EStreamingState.Ending) return 'Ending';
if (this.streamingStatus === EStreamingState.Reconnecting)
return 'Reconnecting';
if (this.streamingStatus === EStreamingState.Reconnecting) return 'Reconnecting';
return 'Offline';
}

Expand Down Expand Up @@ -158,6 +172,74 @@ export default class LiveDock extends Vue {
}

refreshChat() {
if (!this.showDefaultPlatformChat) {
this.platformAppsService.reloadApp(this.selectedChat);
return;
}
this.$refs.chat.refresh();
}

get hasChatApps() {
return this.chatApps.length > 0;
}

get showDefaultPlatformChat() {
return this.selectedChat === 'default';
}

get chatApps(): ILoadedApp[] {
return this.platformAppsService.enabledApps.filter(app => {
return !!app.manifest.pages.find(page => {
return page.slot === EAppPageSlot.Chat;
});
});
}

get chatAppsListMetadata() {
let options = [
{
title: this.userService.platform.type as string,
value: 'default'
}
];
this.chatApps.forEach(chatApp => {
options.push({
title: chatApp.manifest.name,
value: chatApp.id
})
});
return metadataHelper.list({ options })
}

get isPopOutAllowed() {
if (this.showDefaultPlatformChat) return false;

const chatPage = this.platformAppsService
.getApp(this.selectedChat)
.manifest.pages.find(page => page.slot === EAppPageSlot.Chat);
if (!chatPage) return false;

// Default result is true
return chatPage.allowPopout == null ? true : chatPage.allowPopout;
}

popOut() {
this.platformAppsService.popOutAppPage(this.selectedChat, this.slot);
this.selectedChat = 'default';
}

isAppPersistent(appId: string) {
return this.platformAppsService.isAppSlotPersistent(appId, EAppPageSlot.Chat);
}

chatStyles(appId = 'default') {
if (this.selectedChat === appId) {
return {};
} else {
return {
position: 'absolute',
top: '-10000px'
};
}
}
}
7 changes: 7 additions & 0 deletions app/components/PlatformAppWebview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@
</template>

<script lang="ts" src="./PlatformAppWebview.vue.ts"></script>
<style lang="less" scoped>
@import "../styles/index";
.platform-app-webview {
flex-grow: 1;
}
</style>
2 changes: 1 addition & 1 deletion app/components/TopNav.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export default class TopNav extends Vue {
}

get topNavApps() {
return this.platformAppsService.state.loadedApps.filter(app => {
return this.platformAppsService.enabledApps.filter(app => {
return !!app.manifest.pages.find(page => {
return page.slot === EAppPageSlot.TopNav;
});
Expand Down
1 change: 0 additions & 1 deletion app/components/pages/PlatformAppContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
Pop Out
</button>
<button
v-if="isUnpacked"
@click="refreshApp"
class="button button--default">
Reload
Expand Down
2 changes: 1 addition & 1 deletion app/components/pages/PlatformAppContainer.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default class PlatformAppContainer extends Vue {
slot = EAppPageSlot.TopNav;

get app() {
return this.platformAppsService.state.loadedApps.find(app => {
return this.platformAppsService.enabledApps.find(app => {
return app.id === this.params.appId;
});
}
Expand Down
2 changes: 1 addition & 1 deletion app/components/windows/Main.vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export default class Main extends Vue {
}

get platformApps() {
return this.platformAppsService.state.loadedApps;
return this.platformAppsService.enabledApps;
}

isAppPersistent(appId: string) {
Expand Down
Loading

0 comments on commit e8e9b07

Please sign in to comment.