From 123e653ad0c8aed419b31ce822ebdd4ebffbea28 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Fri, 27 Sep 2024 15:16:05 -0400 Subject: [PATCH] Consistent device list sorting and formatting. (#596) * Consistent device list sorting and formatting. * Fix failing tests --- package-lock.json | 10 +++--- package.json | 4 +-- src/ActiveDeviceManager.ts | 28 ++++++++------- src/icons.ts | 15 ++++++++ src/managers/UserInputManager.spec.ts | 17 +++++---- src/managers/UserInputManager.ts | 16 ++++++--- .../OnlineDevicesViewProvider.ts | 36 ++++++++----------- 7 files changed, 75 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index b8b815b4..c380636a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "@types/resolve": "^1.20.6", "@types/semver": "^7.1.0", "@types/sinon": "7.0.6", - "@types/vscode": "^1.53.0", + "@types/vscode": "^1.81.0", "@types/xml2js": "^0.4.14", "@types/yargs": "^17.0.10", "@typescript-eslint/eslint-plugin": "^5.14.0", @@ -100,7 +100,7 @@ }, "engines": { "node": "^12.12.0", - "vscode": "^1.57.0" + "vscode": "^1.81.0" }, "optionalDependencies": { "fsevents": "~2.3.2" @@ -1540,9 +1540,9 @@ "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==" }, "node_modules/@types/vscode": { - "version": "1.74.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.74.0.tgz", - "integrity": "sha512-LyeCIU3jb9d38w0MXFwta9r0Jx23ugujkAxdwLTNCyspdZTKUc43t7ppPbCiPoQ/Ivd/pnDFZrb4hWd45wrsgA==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.81.0.tgz", + "integrity": "sha512-YIaCwpT+O2E7WOMq0eCgBEABE++SX3Yl/O02GoMIF2DO3qAtvw7m6BXFYsxnc6XyzwZgh6/s/UG78LSSombl2w==", "dev": true }, "node_modules/@types/xml2js": { diff --git a/package.json b/package.json index bda26d58..1ebe8494 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "multi-root-ready" ], "engines": { - "vscode": "^1.57.0", + "vscode": "^1.81.0", "node": "^12.12.0" }, "repository": { @@ -107,7 +107,7 @@ "@types/resolve": "^1.20.6", "@types/semver": "^7.1.0", "@types/sinon": "7.0.6", - "@types/vscode": "^1.53.0", + "@types/vscode": "^1.81.0", "@types/xml2js": "^0.4.14", "@types/yargs": "^17.0.10", "@typescript-eslint/eslint-plugin": "^5.14.0", diff --git a/src/ActiveDeviceManager.ts b/src/ActiveDeviceManager.ts index cfb46576..b810ea5b 100644 --- a/src/ActiveDeviceManager.ts +++ b/src/ActiveDeviceManager.ts @@ -85,18 +85,22 @@ export class ActiveDeviceManager { this.firstRequestForDevices = false; const devices = Object.values( this.deviceCache.mget(this.deviceCache.keys()) as Record - ).sort(firstBy((a: RokuDeviceDetails, b: RokuDeviceDetails) => { - return this.getPriorityForDeviceFormFactor(a) - this.getPriorityForDeviceFormFactor(b); - }).thenBy((a: RokuDeviceDetails, b: RokuDeviceDetails) => { - if (a.id < b.id) { - return -1; - } - if (a.id > b.id) { - return 1; - } - // ids must be equal - return 0; - })); + ).sort( + firstBy((a, b) => { + return this.getPriorityForDeviceFormFactor(a) - this.getPriorityForDeviceFormFactor(b); + }).thenBy((a, b) => { + return a.deviceInfo['default-device-name'].localeCompare(b.deviceInfo['default-device-name']); + }).thenBy((a, b) => { + if (a.id < b.id) { + return -1; + } + if (a.id > b.id) { + return 1; + } + // ids must be equal + return 0; + }) + ); return devices; } diff --git a/src/icons.ts b/src/icons.ts index 68cb7137..7a76f8ee 100644 --- a/src/icons.ts +++ b/src/icons.ts @@ -1,4 +1,6 @@ import * as vscode from 'vscode'; +import type { RokuDeviceDetails } from './ActiveDeviceManager'; + export const icons = { streamingStick: { light: vscode.Uri.file(`${__dirname}/../images/icons/streaming-stick-light.svg`), @@ -11,5 +13,18 @@ export const icons = { setTopBox: { light: vscode.Uri.file(`${__dirname}/../images/icons/set-top-box-light.svg`), dark: vscode.Uri.file(`${__dirname}/../images/icons/set-top-box-dark.svg`) + }, + /** + * Get the correct icon for the device type + */ + getDeviceType: (device: RokuDeviceDetails) => { + if (device.deviceInfo?.['is-stick']) { + return icons.streamingStick; + } else if (device.deviceInfo?.['is-tv']) { + return icons.tv; + //fall back to settop box in all other cases + } else { + return icons.setTopBox; + } } }; diff --git a/src/managers/UserInputManager.spec.ts b/src/managers/UserInputManager.spec.ts index de80e6c7..14db233a 100644 --- a/src/managers/UserInputManager.spec.ts +++ b/src/managers/UserInputManager.spec.ts @@ -8,6 +8,7 @@ import { standardizePath as s } from 'brighterscript'; import * as fsExtra from 'fs-extra'; import type { RokuDeviceDetails } from '../ActiveDeviceManager'; import { ActiveDeviceManager } from '../ActiveDeviceManager'; +import { icons } from '../icons'; const sinon = createSandbox(); const Module = require('module'); @@ -47,7 +48,8 @@ describe('UserInputManager', () => { deviceInfo: { 'user-device-name': 'roku1', 'serial-number': 'alpha', - 'model-number': 'model1' + 'model-number': 'model1', + 'software-version': '11.5.0' }, id: '1', ip: '1.1.1.1', @@ -56,7 +58,8 @@ describe('UserInputManager', () => { deviceInfo: { 'user-device-name': 'roku2', 'serial-number': 'beta', - 'model-number': 'model2' + 'model-number': 'model2', + 'software-version': '11.5.0' }, id: '2', ip: '1.1.1.2', @@ -65,14 +68,15 @@ describe('UserInputManager', () => { deviceInfo: { 'user-device-name': 'roku3', 'serial-number': 'charlie', - 'model-number': 'model3' + 'model-number': 'model3', + 'software-version': '11.5.0' }, id: '3', ip: '1.1.1.3', location: '???' }]; function label(device: RokuDeviceDetails) { - return `${device.ip} | ${device.deviceInfo['user-device-name']} - ${device.deviceInfo['serial-number']} - ${device.deviceInfo['model-number']}`; + return `${device.deviceInfo['model-number']} – ${device.deviceInfo['user-device-name']} – OS ${device.deviceInfo['software-version']} – ${device.ip}`; } it('includes "manual', () => { @@ -95,8 +99,9 @@ describe('UserInputManager', () => { label: 'devices' }, { - label: '1.1.1.1 | roku1 - alpha - model1', - device: devices[0] + label: 'model1 – roku1 – OS 11.5.0 – 1.1.1.1', + device: devices[0], + iconPath: icons.setTopBox }, { kind: QuickPickItemKind.Separator, diff --git a/src/managers/UserInputManager.ts b/src/managers/UserInputManager.ts index ac750161..5692b14c 100644 --- a/src/managers/UserInputManager.ts +++ b/src/managers/UserInputManager.ts @@ -5,6 +5,7 @@ import type { } from 'vscode'; import * as vscode from 'vscode'; import type { ActiveDeviceManager, RokuDeviceDetails } from '../ActiveDeviceManager'; +import { icons } from '../icons'; /** * An id to represent the "Enter manually" option in the host picker @@ -143,7 +144,12 @@ export class UserInputManager { * @returns a properly formatted host string */ private createHostLabel(device: RokuDeviceDetails) { - return `${device.ip} | ${device.deviceInfo['user-device-name']} - ${device.deviceInfo['serial-number']} - ${device.deviceInfo['model-number']}`; + return [ + device.deviceInfo['model-number'], + device.deviceInfo['user-device-name'], + `OS ${device.deviceInfo['software-version']}`, + device.ip + ].join(' – '); } /** @@ -169,8 +175,9 @@ export class UserInputManager { //add the device items.push({ label: this.createHostLabel(lastUsedDevice), - device: lastUsedDevice - }); + device: lastUsedDevice, + iconPath: icons.getDeviceType(lastUsedDevice) + } as any); } //add all other devices @@ -185,7 +192,8 @@ export class UserInputManager { //add the device items.push({ label: this.createHostLabel(device), - device: device + device: device, + iconPath: icons.getDeviceType(device) }); } } diff --git a/src/viewProviders/OnlineDevicesViewProvider.ts b/src/viewProviders/OnlineDevicesViewProvider.ts index 55926af1..ab34d14a 100644 --- a/src/viewProviders/OnlineDevicesViewProvider.ts +++ b/src/viewProviders/OnlineDevicesViewProvider.ts @@ -19,21 +19,12 @@ export class OnlineDevicesViewProvider implements vscode.TreeDataProvider { - if (!this.findDeviceById(newDevice.id)) { - // Add the device to the list - this.devices.push(newDevice); - this._onDidChangeTreeData.fire(null); - } else { - // Update the device - const foundIndex = this.devices.findIndex(device => device.id === newDevice.id); - this.devices[foundIndex] = newDevice; - } + this.devices = this.activeDeviceManager.getActiveDevices(); + this._onDidChangeTreeData.fire(null); }); this.activeDeviceManager.on('device-expired', device => { - // Remove the device from the list - const foundIndex = this.devices.findIndex(x => x.id === device.id); - this.devices.splice(foundIndex, 1); + this.devices = this.activeDeviceManager.getActiveDevices(); this._onDidChangeTreeData.fire(null); }); } @@ -47,6 +38,14 @@ export class OnlineDevicesViewProvider implements vscode.TreeDataProvider; + private makeName(device: RokuDeviceDetails) { + return [ + device.deviceInfo['model-number'], + device.deviceInfo['user-device-name'], + `OS ${device.deviceInfo['software-version']}` + ].join(' – '); + } + getChildren(element?: DeviceTreeItem | DeviceInfoTreeItem): vscode.ProviderResult { if (!element) { if (this.devices) { @@ -54,20 +53,13 @@ export class OnlineDevicesViewProvider implements vscode.TreeDataProvider