diff --git a/package.json b/package.json index 7d30fc1f..abbb4200 100644 --- a/package.json +++ b/package.json @@ -264,31 +264,39 @@ "when": "debugType == 'brightscript' && view == rendezvousView", "group": "navigation" }, + { "command": "extension.brightscript.refreshDeviceList", "when": "view == onlineDevicesView", "group": "navigation" }, + { "command": "extension.brightscript.rokuRegistry.refreshRegistry", "when": "view == rokuRegistryView && brightscript.isOnDeviceComponentAvailable", - "group": "navigation" + "group": "navigation@1" }, { "command": "extension.brightscript.rokuRegistry.importRegistry", "when": "view == rokuRegistryView && brightscript.isOnDeviceComponentAvailable", - "group": "navigation" + "group": "navigation@2" }, { "command": "extension.brightscript.rokuRegistry.exportRegistry", "when": "view == rokuRegistryView && brightscript.isOnDeviceComponentAvailable", - "group": "navigation" + "group": "navigation@3" }, { "command": "extension.brightscript.rokuRegistry.clearRegistry", "when": "view == rokuRegistryView && brightscript.isOnDeviceComponentAvailable", - "group": "navigation" + "group": "navigation@4" }, + { + "command": "extension.brightscript.disconnectFromDevice", + "when": "view == rokuRegistryView && brightscript.isOnDeviceComponentAvailable", + "group": "navigation@5" + }, + { "command": "extension.brightscript.rokuDeviceView.refreshScreenshot", "when": "view == rokuDeviceView && !brightscript.rokuDeviceView.enableScreenshotCapture", @@ -319,6 +327,12 @@ "when": "view == rokuDeviceView", "group": "navigation@4" }, + { + "command": "extension.brightscript.disconnectFromDevice", + "when": "view == rokuDeviceView && brightscript.rokuDeviceView.isOnDeviceComponentAvailable", + "group": "navigation@5" + }, + { "command": "extension.brightscript.rokuAutomationView.startRecording", "when": "view == rokuAutomationView && !brightscript.rokuAutomationView.isRecording", @@ -344,6 +358,12 @@ "when": "view == rokuFileSystemView && brightscript.isOnDeviceComponentAvailable", "group": "navigation@1" }, + { + "command": "extension.brightscript.disconnectFromDevice", + "when": "view == rokuFileSystemView && brightscript.isOnDeviceComponentAvailable", + "group": "navigation@2" + }, + { "command": "extension.brightscript.rokuAppOverlaysView.addNewOverlay", "when": "view == rokuAppOverlaysView && brightscript.isOnDeviceComponentAvailable", @@ -353,6 +373,23 @@ "command": "extension.brightscript.rokuAppOverlaysView.removeAllOverlays", "when": "view == rokuAppOverlaysView && brightscript.isOnDeviceComponentAvailable", "group": "navigation@2" + }, + { + "command": "extension.brightscript.disconnectFromDevice", + "when": "view == rokuAppOverlaysView && brightscript.isOnDeviceComponentAvailable", + "group": "navigation@3" + }, + + { + "command": "extension.brightscript.disconnectFromDevice", + "when": "view == rokuCommandsView && brightscript.isOnDeviceComponentAvailable", + "group": "navigation@1" + }, + + { + "command": "extension.brightscript.disconnectFromDevice", + "when": "view == sceneGraphInspectorView && brightscript.isOnDeviceComponentAvailable", + "group": "navigation@1" } ], "webview/context": [ @@ -2901,6 +2938,12 @@ "title": "Refresh Nodetree", "category": "BrighterScript", "icon": "$(refresh)" + }, + { + "command": "extension.brightscript.disconnectFromDevice", + "title": "Disconnect From Roku Device", + "category": "BrighterScript", + "icon": "$(debug-disconnect)" } ], "keybindings": [ diff --git a/src/commands/VscodeCommand.ts b/src/commands/VscodeCommand.ts index 131c9322..38eae7b0 100644 --- a/src/commands/VscodeCommand.ts +++ b/src/commands/VscodeCommand.ts @@ -17,5 +17,6 @@ export enum VscodeCommand { disableRemoteControlMode = 'extension.brightscript.disableRemoteControlMode', rokuAppOverlaysViewAddNewOverlay = 'extension.brightscript.rokuAppOverlaysView.addNewOverlay', rokuAppOverlaysViewRemoveAllOverlays = 'extension.brightscript.rokuAppOverlaysView.removeAllOverlays', - rokuFileSystemViewRefresh = 'extension.brightscript.rokuFileSystemView.refresh' + rokuFileSystemViewRefresh = 'extension.brightscript.rokuFileSystemView.refresh', + disconnectFromDevice = 'extension.brightscript.disconnectFromDevice' } diff --git a/src/extension.ts b/src/extension.ts index 0a2ed83c..738a6922 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -77,7 +77,7 @@ export class Extension { userInputManager ); - this.rtaManager = new RtaManager(); + this.rtaManager = new RtaManager(context); this.webviewViewProviderManager = new WebviewViewProviderManager(context, this.rtaManager, this.brightScriptCommands); this.rtaManager.setWebviewViewProviderManager(this.webviewViewProviderManager); @@ -177,6 +177,7 @@ export class Extension { //if this is a brightscript debug session if (e.type === 'brightscript') { logOutputManager.onDidStartDebugSession(); + this.webviewViewProviderManager.onDidStartDebugSession(e); } this.diagnosticManager.clear(); }); @@ -189,6 +190,7 @@ export class Extension { if (config.remoteControlMode?.deactivateOnSessionEnd) { void this.remoteControlManager.setRemoteControlMode(false, 'launch'); } + this.webviewViewProviderManager.onDidTerminateDebugSession(e); } this.diagnosticManager.clear(); }); diff --git a/src/managers/RtaManager.ts b/src/managers/RtaManager.ts index 514275ef..5af9a3e3 100644 --- a/src/managers/RtaManager.ts +++ b/src/managers/RtaManager.ts @@ -1,12 +1,25 @@ import * as fs from 'fs'; import * as path from 'path'; import * as rta from 'roku-test-automation'; +import * as vscode from 'vscode'; import { ViewProviderEvent } from '../viewProviders/ViewProviderEvent'; import { ViewProviderId } from '../viewProviders/ViewProviderId'; import { vscodeContextManager } from './VscodeContextManager'; import type { WebviewViewProviderManager } from './WebviewViewProviderManager'; +import { VscodeCommand } from '../commands/VscodeCommand'; export class RtaManager { + constructor( + context: vscode.ExtensionContext + ) { + context.subscriptions.push(vscode.commands.registerCommand(VscodeCommand.disconnectFromDevice, () => { + void this.onDeviceComponent?.shutdown(); + this.onDeviceComponent = undefined; + void vscodeContextManager.set('brightscript.isOnDeviceComponentAvailable', false); + this.updateDeviceAvailabilityOnWebViewProviders(); + })); + } + public onDeviceComponent?: rta.OnDeviceComponent; public device?: rta.RokuDevice; @@ -44,11 +57,7 @@ export class RtaManager { } void vscodeContextManager.set('brightscript.isOnDeviceComponentAvailable', !!this.onDeviceComponent); - for (const webviewProvider of this.webviewViewProviderManager.getWebviewViewProviders()) { - if (typeof webviewProvider.updateDeviceAvailability === 'function') { - webviewProvider.updateDeviceAvailability(); - } - } + this.updateDeviceAvailabilityOnWebViewProviders(); if (config.disableScreenSaver) { void this.onDeviceComponent?.disableScreenSaver({ disableScreensaver: true }); @@ -95,4 +104,12 @@ export class RtaManager { public getStoredNodeReferences() { return this.lastStoreNodesResponse; } + + private updateDeviceAvailabilityOnWebViewProviders() { + for (const webviewProvider of this.webviewViewProviderManager.getWebviewViewProviders()) { + if (typeof webviewProvider.updateDeviceAvailability === 'function') { + webviewProvider.updateDeviceAvailability(); + } + } + } } diff --git a/src/managers/WebviewViewProviderManager.spec.ts b/src/managers/WebviewViewProviderManager.spec.ts index 4a26e5b7..190ed022 100644 --- a/src/managers/WebviewViewProviderManager.spec.ts +++ b/src/managers/WebviewViewProviderManager.spec.ts @@ -47,7 +47,7 @@ describe('WebviewViewProviderManager', () => { let spy; before(() => { spy = sinon.spy(vscode.window, 'registerWebviewViewProvider'); - rtaManager = new RtaManager(); + rtaManager = new RtaManager(context); webviewViewProviderManager = new WebviewViewProviderManager(context, rtaManager, brightScriptCommands); }); @@ -76,7 +76,7 @@ describe('WebviewViewProviderManager', () => { } }; - rtaManager = new RtaManager(); + rtaManager = new RtaManager(context); webviewViewProviderManager = new WebviewViewProviderManager(context, rtaManager, brightScriptCommands); rtaManager.setWebviewViewProviderManager(webviewViewProviderManager); }); diff --git a/src/managers/WebviewViewProviderManager.ts b/src/managers/WebviewViewProviderManager.ts index e7f8b7f1..ab9d8506 100644 --- a/src/managers/WebviewViewProviderManager.ts +++ b/src/managers/WebviewViewProviderManager.ts @@ -61,6 +61,18 @@ export class WebviewViewProviderManager { return providers; } + public onDidStartDebugSession(e: vscode.DebugSession) { + for (const webview of this.webviewViews) { + webview.provider.onDidStartDebugSession(e); + } + } + + public onDidTerminateDebugSession(e: vscode.DebugSession) { + for (const webview of this.webviewViews) { + webview.provider.onDidTerminateDebugSession(e); + } + } + // Notification from extension public onChannelPublishedEvent(e: ChannelPublishedEvent) { const config = e.body.launchConfiguration as BrightScriptLaunchConfiguration; diff --git a/src/viewProviders/BaseWebviewViewProvider.ts b/src/viewProviders/BaseWebviewViewProvider.ts index 01c928d1..b66c28db 100644 --- a/src/viewProviders/BaseWebviewViewProvider.ts +++ b/src/viewProviders/BaseWebviewViewProvider.ts @@ -47,6 +47,14 @@ export abstract class BaseWebviewViewProvider implements vscode.WebviewViewProvi this.webviewViewProviderManager = manager; } + public onDidStartDebugSession(e: vscode.DebugSession) { + // Can be overwritten in a child to notify on debug session start + } + + public onDidTerminateDebugSession(e: vscode.DebugSession) { + // Can be overwritten in a child to notify on debug session end + } + public onChannelPublishedEvent(e: ChannelPublishedEvent) { // Can be overwritten in a child to notify on channel publish } diff --git a/src/viewProviders/RokuDeviceViewViewProvider.ts b/src/viewProviders/RokuDeviceViewViewProvider.ts index b4a3c2aa..fc75dfca 100644 --- a/src/viewProviders/RokuDeviceViewViewProvider.ts +++ b/src/viewProviders/RokuDeviceViewViewProvider.ts @@ -1,4 +1,5 @@ import type * as vscode from 'vscode'; +import type { ChannelPublishedEvent } from 'roku-debug'; import { VscodeCommand } from '../commands/VscodeCommand'; import { BaseRdbViewProvider } from './BaseRdbViewProvider'; import { ViewProviderId } from './ViewProviderId'; @@ -7,6 +8,9 @@ import { ViewProviderCommand } from './ViewProviderCommand'; export class RokuDeviceViewViewProvider extends BaseRdbViewProvider { public readonly id = ViewProviderId.rokuDeviceView; + private temporarilyDisableScreenshotCapture = false; + private resumeScreenshotCapture?: () => void; + constructor(context: vscode.ExtensionContext, dependencies) { super(context, dependencies); @@ -20,9 +24,15 @@ export class RokuDeviceViewViewProvider extends BaseRdbViewProvider { this.view.show(false); }); - this.addMessageCommandCallback(ViewProviderCommand.getScreenshot, async (message) => { try { + if (this.temporarilyDisableScreenshotCapture) { + // Sometimes we need to temporarily stop screenshot capture as it can prevent successful package deployment to the device + // Originally was just returning true here but now we just pause until we resume capturing + await new Promise((resolve) => { + this.resumeScreenshotCapture = resolve; + }); + } const result = await this.dependencies.rtaManager.device.getScreenshot(); this.postOrQueueMessage({ ...message, @@ -42,4 +52,21 @@ export class RokuDeviceViewViewProvider extends BaseRdbViewProvider { return true; }); } + + public onDidStartDebugSession(e: vscode.DebugSession) { + this.temporarilyDisableScreenshotCapture = true; + } + + public onDidTerminateDebugSession(e: vscode.DebugSession) { + // In case we failed to start debugging we want to allow screenshots again + this.temporarilyDisableScreenshotCapture = false; + this.resumeScreenshotCapture?.(); + delete this.resumeScreenshotCapture; + } + + public onChannelPublishedEvent(e: ChannelPublishedEvent) { + this.temporarilyDisableScreenshotCapture = false; + this.resumeScreenshotCapture?.(); + delete this.resumeScreenshotCapture; + } } diff --git a/src/viewProviders/RokuRegistryViewProvider.spec.ts b/src/viewProviders/RokuRegistryViewProvider.spec.ts index 91fdcc22..c8e02453 100644 --- a/src/viewProviders/RokuRegistryViewProvider.spec.ts +++ b/src/viewProviders/RokuRegistryViewProvider.spec.ts @@ -24,7 +24,7 @@ afterEach(() => { }); describe('RokuRegistryViewProvider', () => { - const rtaManager = new RtaManager(); + const rtaManager = new RtaManager(vscode.context); const provider = new RokuRegistryViewProvider(vscode.context, { rtaManager: rtaManager }); diff --git a/webviews/src/views/SceneGraphInspectorView/NodeDetailPage.svelte b/webviews/src/views/SceneGraphInspectorView/NodeDetailPage.svelte index 37dec305..e7bb0bd9 100644 --- a/webviews/src/views/SceneGraphInspectorView/NodeDetailPage.svelte +++ b/webviews/src/views/SceneGraphInspectorView/NodeDetailPage.svelte @@ -1,3 +1,4 @@ +