Skip to content

Commit 19ea45c

Browse files
ktranDevtools-frontend LUCI CQ
authored andcommitted
[GM3Restyling] Update media player empty states
Before: https://imgur.com/a/8XhEFwn After: https://imgur.com/a/jrBAv6X Bug: 325443331 Change-Id: Id173f8c5e8b05d2f5ad83c2b89ed106b9f42622d Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6252965 Reviewed-by: Kateryna Prokopenko <[email protected]> Commit-Queue: Kim-Anh Tran <[email protected]>
1 parent 2bb7afa commit 19ea45c

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

front_end/panels/media/MainView.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,54 @@ describeWithMockConnection('MediaMainView', () => {
5757
it('reacts to error on in scope event', testUiUpdate(Media.MediaModel.Events.PLAYER_ERRORS_RAISED, 'onError', true));
5858
it('does not react to error on out of scope event',
5959
testUiUpdate(Media.MediaModel.Events.PLAYER_ERRORS_RAISED, 'onError', false));
60+
61+
it('shows a placeholder if no player is available', () => {
62+
const mainView = new Media.MainView.MainView();
63+
assert.exists(mainView.contentElement.querySelector('.empty-state'));
64+
assert.deepEqual(mainView.contentElement.querySelector('.empty-state-header')?.textContent, 'No media player');
65+
assert.deepEqual(
66+
mainView.contentElement.querySelector('.empty-state-description span')?.textContent,
67+
'On this page you can view and export media player details.');
68+
mainView.detach();
69+
});
70+
71+
it('shows a placeholder if no player was selected', () => {
72+
const model = target.model(Media.MediaModel.MediaModel);
73+
assert.exists(model);
74+
75+
// Show main view, which will register event listeners on the model.
76+
const mainView = new Media.MainView.MainView();
77+
mainView.markAsRoot();
78+
mainView.show(document.body);
79+
80+
model.dispatchEventToListeners(Media.MediaModel.Events.PLAYERS_CREATED, [PLAYER_ID]);
81+
assert.exists(mainView.contentElement.querySelector('.empty-state'));
82+
assert.deepEqual(
83+
mainView.contentElement.querySelector('.empty-state-header')?.textContent, 'No media player selected');
84+
assert.deepEqual(
85+
mainView.contentElement.querySelector('.empty-state-description span')?.textContent,
86+
'Select a media player to inspect its details.');
87+
mainView.detach();
88+
});
89+
90+
it('shows a placeholder that no player was detected if all players are hidden', () => {
91+
const model = target.model(Media.MediaModel.MediaModel);
92+
assert.exists(model);
93+
94+
// Show main view, which will register event listeners on the model.
95+
const mainView = new Media.MainView.MainView();
96+
mainView.markAsRoot();
97+
mainView.show(document.body);
98+
99+
model.dispatchEventToListeners(Media.MediaModel.Events.PLAYERS_CREATED, [PLAYER_ID]);
100+
mainView.markPlayerForDeletion(PLAYER_ID);
101+
102+
assert.exists(mainView.contentElement.querySelector('.empty-state'));
103+
assert.deepEqual(mainView.contentElement.querySelector('.empty-state-header')?.textContent, 'No media player');
104+
assert.deepEqual(
105+
mainView.contentElement.querySelector('.empty-state-description span')?.textContent,
106+
'On this page you can view and export media player details.');
107+
mainView.detach();
108+
});
109+
60110
});

front_end/panels/media/MainView.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// found in the LICENSE file.
44

55
import type * as Common from '../../core/common/common.js';
6+
import * as i18n from '../../core/i18n/i18n.js';
7+
import type * as Platform from '../../core/platform/platform.js';
68
import * as SDK from '../../core/sdk/sdk.js';
79
import type * as Protocol from '../../generated/protocol.js';
810
import * as UI from '../../ui/legacy/legacy.js';
@@ -11,6 +13,34 @@ import {Events, MediaModel, type PlayerEvent} from './MediaModel.js';
1113
import {PlayerDetailView} from './PlayerDetailView.js';
1214
import {PlayerListView} from './PlayerListView.js';
1315

16+
const UIStrings = {
17+
/**
18+
*@description Text to show if no media player has been selected
19+
* A media player can be an audio and video source of a page.
20+
*/
21+
noPlayerDetailsSelected: 'No media player selected',
22+
/**
23+
*@description Text to instruct the user on how to view media player details
24+
* A media player can be an audio and video source of a page.
25+
*/
26+
selectToViewDetails: 'Select a media player to inspect its details.',
27+
/**
28+
*@description Text to show if no player can be shown
29+
* A media player can be an audio and video source of a page.
30+
*/
31+
noMediaPlayer: 'No media player',
32+
/**
33+
*@description Text to explain this panel
34+
* A media player can be an audio and video source of a page.
35+
*/
36+
mediaPlayerDescription: 'On this page you can view and export media player details.',
37+
};
38+
const str_ = i18n.i18n.registerUIStrings('panels/media/MainView.ts', UIStrings);
39+
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
40+
41+
const MEDIA_PLAYER_EXPLANATION_URL =
42+
'https://developer.chrome.com/docs/devtools/media-panel#hide-show' as Platform.DevToolsPath.UrlString;
43+
1444
export interface TriggerHandler {
1545
onProperty(property: Protocol.Media.PlayerProperty): void;
1646
onError(error: Protocol.Media.PlayerError): void;
@@ -135,6 +165,8 @@ export class MainView extends UI.Panel.PanelWithSidebar implements SDK.TargetMan
135165
private readonly downloadStore: PlayerDataDownloadManager;
136166
private readonly sidebar: PlayerListView;
137167

168+
#placeholder: UI.EmptyWidget.EmptyWidget;
169+
138170
constructor(downloadStore: PlayerDataDownloadManager = new PlayerDataDownloadManager()) {
139171
super('media');
140172
this.detailPanels = new Map();
@@ -146,6 +178,11 @@ export class MainView extends UI.Panel.PanelWithSidebar implements SDK.TargetMan
146178
this.sidebar = new PlayerListView(this);
147179
this.sidebar.show(this.panelSidebarElement());
148180

181+
this.#placeholder =
182+
new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noMediaPlayer), UIStrings.mediaPlayerDescription);
183+
this.#placeholder.show(this.mainElement());
184+
this.#placeholder.appendLink(MEDIA_PLAYER_EXPLANATION_URL);
185+
149186
SDK.TargetManager.TargetManager.instance().observeModels(MediaModel, this, {scoped: true});
150187
}
151188

@@ -204,6 +241,11 @@ export class MainView extends UI.Panel.PanelWithSidebar implements SDK.TargetMan
204241
this.sidebar.addMediaElementItem(playerID);
205242
this.detailPanels.set(playerID, new PlayerDetailView());
206243
this.downloadStore.addPlayer(playerID);
244+
245+
if (this.detailPanels.size === 1) {
246+
this.#placeholder.header = i18nString(UIStrings.noPlayerDetailsSelected);
247+
this.#placeholder.text = i18nString(UIStrings.selectToViewDetails);
248+
}
207249
}
208250

209251
private propertiesChanged(event: Common.EventTarget.EventTargetEvent<Protocol.Media.PlayerPropertiesChangedEvent>):
@@ -286,6 +328,10 @@ export class MainView extends UI.Panel.PanelWithSidebar implements SDK.TargetMan
286328
this.detailPanels.delete(playerID);
287329
this.sidebar.deletePlayer(playerID);
288330
this.downloadStore.deletePlayer(playerID);
331+
if (this.detailPanels.size === 0) {
332+
this.#placeholder.header = i18nString(UIStrings.noMediaPlayer);
333+
this.#placeholder.text = i18nString(UIStrings.mediaPlayerDescription);
334+
}
289335
}
290336

291337
markOtherPlayersForDeletion(playerID: string): void {

0 commit comments

Comments
 (0)