mirror of
https://github.com/zen-browser/desktop.git
synced 2025-10-06 09:56:36 +00:00
New features for media control
This commit is contained in:
@@ -6,10 +6,20 @@
|
|||||||
<toolbaritem>
|
<toolbaritem>
|
||||||
<vbox id="zen-media-main-vbox">
|
<vbox id="zen-media-main-vbox">
|
||||||
<vbox>
|
<vbox>
|
||||||
<vbox id="zen-media-info-vbox" class="show-on-hover">
|
<hbox id="zen-media-info-container" class="show-on-hover">
|
||||||
<label id="zen-media-title" fadein="true"/>
|
<vbox id="zen-media-info-vbox">
|
||||||
<label id="zen-media-artist" fadein="true"/>
|
<label id="zen-media-title" fadein="true"/>
|
||||||
</vbox>
|
<label id="zen-media-artist" fadein="true"/>
|
||||||
|
</vbox>
|
||||||
|
<hbox id="zen-media-buttons-hbox">
|
||||||
|
<toolbarbutton id="zen-media-pip-button"
|
||||||
|
class="toolbarbutton-1"
|
||||||
|
oncommand="gZenMediaController.onMediaPip();" />
|
||||||
|
<toolbarbutton id="zen-media-close-button"
|
||||||
|
class="toolbarbutton-1"
|
||||||
|
oncommand="gZenMediaController.onControllerClose();" />
|
||||||
|
</hbox>
|
||||||
|
</hbox>
|
||||||
<hbox id="zen-media-progress-hbox" class="show-on-hover">
|
<hbox id="zen-media-progress-hbox" class="show-on-hover">
|
||||||
<label id="zen-media-current-time">0:00</label>
|
<label id="zen-media-current-time">0:00</label>
|
||||||
<html:input type="range" id="zen-media-progress-bar"
|
<html:input type="range" id="zen-media-progress-bar"
|
||||||
|
@@ -13,6 +13,21 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zen-media-buttons-hbox {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not([can-pip]) {
|
||||||
|
#zen-media-info-vbox {
|
||||||
|
width: calc(100% - 26px);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#zen-media-pip-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#zen-media-prev-button,
|
#zen-media-prev-button,
|
||||||
#zen-media-play-pause-button,
|
#zen-media-play-pause-button,
|
||||||
#zen-media-next-button {
|
#zen-media-next-button {
|
||||||
@@ -234,6 +249,17 @@
|
|||||||
--toolbarbutton-outer-padding: 0;
|
--toolbarbutton-outer-padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zen-media-controls-toolbar[can-pip] {
|
||||||
|
#zen-media-info-vbox {
|
||||||
|
width: calc(100% - 58px);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#zen-media-pip-button {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:root:not([zen-sidebar-expanded='true']) {
|
:root:not([zen-sidebar-expanded='true']) {
|
||||||
#zen-media-controls-toolbar {
|
#zen-media-controls-toolbar {
|
||||||
display: none;
|
display: none;
|
||||||
|
@@ -14,6 +14,12 @@ class ZenMediaController {
|
|||||||
|
|
||||||
supportedKeys = ['playpause', 'previoustrack', 'nexttrack'];
|
supportedKeys = ['playpause', 'previoustrack', 'nexttrack'];
|
||||||
|
|
||||||
|
pipEligibilityMap = new Map();
|
||||||
|
mediaControllersMap = new Map();
|
||||||
|
|
||||||
|
_tabTimeout = null;
|
||||||
|
_controllerSwitchTimeout = null;
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.mediaTitle = document.querySelector('#zen-media-title');
|
this.mediaTitle = document.querySelector('#zen-media-title');
|
||||||
this.mediaArtist = document.querySelector('#zen-media-artist');
|
this.mediaArtist = document.querySelector('#zen-media-artist');
|
||||||
@@ -31,49 +37,34 @@ class ZenMediaController {
|
|||||||
this.onDeactivated = this._onDeactivated.bind(this);
|
this.onDeactivated = this._onDeactivated.bind(this);
|
||||||
|
|
||||||
window.addEventListener('TabSelect', (event) => {
|
window.addEventListener('TabSelect', (event) => {
|
||||||
if (this._currentBrowser) {
|
const linkedBrowser = event.target.linkedBrowser;
|
||||||
if (event.target.linkedBrowser.browserId === this._currentBrowser.browserId) {
|
this.switchController();
|
||||||
gZenUIManager.motion
|
|
||||||
.animate(
|
|
||||||
this.mediaControlBar,
|
|
||||||
{
|
|
||||||
opacity: [1, 0],
|
|
||||||
y: [0, 10],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 0.1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
this.mediaControlBar.setAttribute('hidden', 'true');
|
|
||||||
});
|
|
||||||
} else if (this.mediaControlBar.hasAttribute('hidden')) {
|
|
||||||
this.mediaControlBar.removeAttribute('hidden');
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
this.mediaControlBar.style.height =
|
|
||||||
this.mediaControlBar.querySelector('toolbaritem').getBoundingClientRect().height + 'px';
|
|
||||||
this.mediaControlBar.style.opacity = 0;
|
|
||||||
gZenUIManager.motion.animate(
|
|
||||||
this.mediaControlBar,
|
|
||||||
{
|
|
||||||
opacity: [0, 1],
|
|
||||||
y: [10, 0],
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
gZenUIManager.updateTabsToolbar();
|
if (this._currentBrowser) {
|
||||||
|
if (linkedBrowser.browserId === this._currentBrowser.browserId) {
|
||||||
|
if (this._tabTimeout) {
|
||||||
|
clearTimeout(this._tabTimeout);
|
||||||
|
this._tabTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hideMediaControls();
|
||||||
|
} else {
|
||||||
|
this._tabTimeout = setTimeout(() => {
|
||||||
|
if (!this.mediaControlBar.hasAttribute('pip')) this.showMediaControls();
|
||||||
|
else this._tabTimeout = null;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('TabClose', (event) => {
|
window.addEventListener('TabClose', (event) => {
|
||||||
if (this._currentBrowser) {
|
const linkedBrowser = event.target.linkedBrowser;
|
||||||
if (event.target.linkedBrowser.browserId === this._currentBrowser.browserId) {
|
this.deinitMediaController(
|
||||||
this.deinitMediaController(this._currentMediaController);
|
linkedBrowser.browsingContext.mediaController,
|
||||||
}
|
true,
|
||||||
}
|
linkedBrowser.browserId === this._currentBrowser?.browserId,
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('DOMAudioPlaybackStarted', (event) => {
|
window.addEventListener('DOMAudioPlaybackStarted', (event) => {
|
||||||
@@ -87,24 +78,46 @@ class ZenMediaController {
|
|||||||
* Deinitializes a media controller, removing all event listeners and resetting state.
|
* Deinitializes a media controller, removing all event listeners and resetting state.
|
||||||
* @param {Object} mediaController - The media controller to deinitialize.
|
* @param {Object} mediaController - The media controller to deinitialize.
|
||||||
*/
|
*/
|
||||||
deinitMediaController(mediaController) {
|
async deinitMediaController(mediaController, shouldForget = true, shouldOverride = true, shouldHide = true) {
|
||||||
if (!mediaController) return;
|
if (!mediaController) return;
|
||||||
|
|
||||||
mediaController.removeEventListener('positionstatechange', this.onPositionstateChange);
|
const retrievedMediaController = this.mediaControllersMap.get(mediaController.id);
|
||||||
mediaController.removeEventListener('playbackstatechange', this.onPlaybackstateChange);
|
|
||||||
mediaController.removeEventListener('supportedkeyschange', this.onSupportedKeysChange);
|
|
||||||
mediaController.removeEventListener('metadatachange', this.onMetadataChange);
|
|
||||||
mediaController.removeEventListener('deactivated', this.onDeactivated);
|
|
||||||
|
|
||||||
this._currentMediaController = null;
|
if (this.tabObserver && shouldOverride) {
|
||||||
this._currentBrowser = null;
|
this.tabObserver.disconnect();
|
||||||
|
this.tabObserver = null;
|
||||||
if (this._mediaUpdateInterval) {
|
|
||||||
clearInterval(this._mediaUpdateInterval);
|
|
||||||
this._mediaUpdateInterval = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gZenUIManager.motion
|
if (shouldForget) {
|
||||||
|
mediaController.removeEventListener('positionstatechange', this.onPositionstateChange);
|
||||||
|
mediaController.removeEventListener('playbackstatechange', this.onPlaybackstateChange);
|
||||||
|
mediaController.removeEventListener('supportedkeyschange', this.onSupportedKeysChange);
|
||||||
|
mediaController.removeEventListener('metadatachange', this.onMetadataChange);
|
||||||
|
mediaController.removeEventListener('deactivated', this.onDeactivated);
|
||||||
|
|
||||||
|
this.mediaControllersMap.delete(mediaController.id);
|
||||||
|
this.pipEligibilityMap.delete(retrievedMediaController.browser.browserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldOverride) {
|
||||||
|
this._currentMediaController = null;
|
||||||
|
this._currentBrowser = null;
|
||||||
|
|
||||||
|
if (this._mediaUpdateInterval) {
|
||||||
|
clearInterval(this._mediaUpdateInterval);
|
||||||
|
this._mediaUpdateInterval = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldHide) await this.hideMediaControls();
|
||||||
|
this.mediaControlBar.removeAttribute('muted');
|
||||||
|
this.mediaControlBar.classList.remove('playing');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideMediaControls() {
|
||||||
|
if (this.mediaControlBar.hasAttribute('hidden')) return;
|
||||||
|
|
||||||
|
return gZenUIManager.motion
|
||||||
.animate(
|
.animate(
|
||||||
this.mediaControlBar,
|
this.mediaControlBar,
|
||||||
{
|
{
|
||||||
@@ -119,8 +132,67 @@ class ZenMediaController {
|
|||||||
this.mediaControlBar.setAttribute('hidden', 'true');
|
this.mediaControlBar.setAttribute('hidden', 'true');
|
||||||
gZenUIManager.updateTabsToolbar();
|
gZenUIManager.updateTabsToolbar();
|
||||||
});
|
});
|
||||||
this.mediaControlBar.removeAttribute('muted');
|
}
|
||||||
this.mediaControlBar.classList.remove('playing');
|
|
||||||
|
showMediaControls() {
|
||||||
|
const tab = gBrowser.getTabForBrowser(this._currentBrowser);
|
||||||
|
if (tab.hasAttribute('pictureinpicture')) return this.hideMediaControls();
|
||||||
|
|
||||||
|
if (!this.mediaControlBar.hasAttribute('hidden')) return;
|
||||||
|
this.updatePipButton();
|
||||||
|
|
||||||
|
this.mediaControlBar.removeAttribute('hidden');
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
this.mediaControlBar.style.height =
|
||||||
|
this.mediaControlBar.querySelector('toolbaritem').getBoundingClientRect().height + 'px';
|
||||||
|
this.mediaControlBar.style.opacity = 0;
|
||||||
|
gZenUIManager.updateTabsToolbar();
|
||||||
|
gZenUIManager.motion.animate(
|
||||||
|
this.mediaControlBar,
|
||||||
|
{
|
||||||
|
opacity: [0, 1],
|
||||||
|
y: [10, 0],
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setupMediaController(mediaController, browser) {
|
||||||
|
this._currentMediaController = mediaController;
|
||||||
|
this._currentBrowser = browser;
|
||||||
|
|
||||||
|
this.updatePipButton();
|
||||||
|
|
||||||
|
this.tabObserver = new MutationObserver((entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.target.hasAttribute('pictureinpicture')) {
|
||||||
|
this.hideMediaControls();
|
||||||
|
this.mediaControlBar.setAttribute('pip', '');
|
||||||
|
} else {
|
||||||
|
const { selectedBrowser } = gBrowser;
|
||||||
|
if (selectedBrowser.browserId !== this._currentBrowser.browserId) {
|
||||||
|
this.showMediaControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mediaControlBar.removeAttribute('pip');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tabObserver.observe(gBrowser.getTabForBrowser(browser), {
|
||||||
|
attributes: true,
|
||||||
|
attributeFilter: ['pictureinpicture'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const positionState = mediaController.getPositionState();
|
||||||
|
this.mediaControllersMap.set(mediaController.id, {
|
||||||
|
controller: mediaController,
|
||||||
|
browser,
|
||||||
|
position: positionState.position,
|
||||||
|
duration: positionState.duration,
|
||||||
|
lastUpdated: Date.now(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,12 +200,15 @@ class ZenMediaController {
|
|||||||
* @param {Object} metadata - The media metadata (title, artist, etc.).
|
* @param {Object} metadata - The media metadata (title, artist, etc.).
|
||||||
* @param {Object} positionState - The position state (position, duration).
|
* @param {Object} positionState - The position state (position, duration).
|
||||||
*/
|
*/
|
||||||
setupMediaControl(metadata, positionState) {
|
setupMediaControlUI(metadata, positionState) {
|
||||||
if (!this.mediaControlBar.classList.contains('playing')) {
|
this.updatePipButton();
|
||||||
|
|
||||||
|
if (!this.mediaControlBar.classList.contains('playing') && this._currentMediaController.isPlaying) {
|
||||||
this.mediaControlBar.classList.add('playing');
|
this.mediaControlBar.classList.add('playing');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mediaFocusButton.style.listStyleImage = `url(${this._currentBrowser.mIconURL})`;
|
const iconURL = this._currentBrowser.mIconURL || `page-icon:${this._currentBrowser.currentURI.spec}`;
|
||||||
|
this.mediaFocusButton.style.listStyleImage = `url(${iconURL})`;
|
||||||
|
|
||||||
this.mediaTitle.textContent = metadata.title || '';
|
this.mediaTitle.textContent = metadata.title || '';
|
||||||
this.mediaArtist.textContent = metadata.artist || '';
|
this.mediaArtist.textContent = metadata.artist || '';
|
||||||
@@ -158,10 +233,21 @@ class ZenMediaController {
|
|||||||
this.updateMuteState();
|
this.updateMuteState();
|
||||||
|
|
||||||
if (!mediaController.isActive || this._currentBrowser?.browserId === browser.browserId) return;
|
if (!mediaController.isActive || this._currentBrowser?.browserId === browser.browserId) return;
|
||||||
|
|
||||||
|
const metadata = mediaController.getMetadata();
|
||||||
|
const positionState = mediaController.getPositionState();
|
||||||
|
this.mediaControllersMap.set(mediaController.id, {
|
||||||
|
controller: mediaController,
|
||||||
|
browser,
|
||||||
|
position: positionState.position,
|
||||||
|
duration: positionState.duration,
|
||||||
|
lastUpdated: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this._currentBrowser) this.switchController();
|
||||||
else {
|
else {
|
||||||
this.deinitMediaController(this._currentMediaController);
|
this.setupMediaController(mediaController, browser);
|
||||||
this._currentMediaController = mediaController;
|
this.setupMediaControlUI(metadata, positionState);
|
||||||
this._currentBrowser = browser;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaController.addEventListener('positionstatechange', this.onPositionstateChange);
|
mediaController.addEventListener('positionstatechange', this.onPositionstateChange);
|
||||||
@@ -169,28 +255,31 @@ class ZenMediaController {
|
|||||||
mediaController.addEventListener('supportedkeyschange', this.onSupportedKeysChange);
|
mediaController.addEventListener('supportedkeyschange', this.onSupportedKeysChange);
|
||||||
mediaController.addEventListener('metadatachange', this.onMetadataChange);
|
mediaController.addEventListener('metadatachange', this.onMetadataChange);
|
||||||
mediaController.addEventListener('deactivated', this.onDeactivated);
|
mediaController.addEventListener('deactivated', this.onDeactivated);
|
||||||
|
}
|
||||||
|
|
||||||
const metadata = mediaController.getMetadata();
|
updatePipEligibility(browser, isEligible) {
|
||||||
const positionState = mediaController.getPositionState();
|
this.pipEligibilityMap.set(browser.browserId, isEligible);
|
||||||
|
|
||||||
this.setupMediaControl(metadata, positionState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Event} event - The deactivation event.
|
* @param {Event} event - The deactivation event.
|
||||||
*/
|
*/
|
||||||
_onDeactivated(event) {
|
_onDeactivated(event) {
|
||||||
if (event.target === this._currentMediaController) {
|
this.deinitMediaController(event.target, true, event.target.id === this._currentMediaController.id, true);
|
||||||
this.deinitMediaController(event.target);
|
this.switchController();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates playback state and UI based on changes.
|
* Updates playback state and UI based on changes.
|
||||||
* @param {Event} event - The playback state change event.
|
* @param {Event} event - The playback state change event.
|
||||||
*/
|
*/
|
||||||
_onPlaybackstateChange(event) {
|
_onPlaybackstateChange() {
|
||||||
this.mediaControlBar.classList.toggle('playing', event.target.isPlaying);
|
if (this._currentMediaController?.isPlaying) {
|
||||||
|
this.mediaControlBar.classList.add('playing');
|
||||||
|
} else {
|
||||||
|
this.switchController();
|
||||||
|
this.mediaControlBar.classList.remove('playing');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -198,6 +287,7 @@ class ZenMediaController {
|
|||||||
* @param {Event} event - The supported keys change event.
|
* @param {Event} event - The supported keys change event.
|
||||||
*/
|
*/
|
||||||
_onSupportedKeysChange(event) {
|
_onSupportedKeysChange(event) {
|
||||||
|
if (event.target !== this._currentMediaController) return;
|
||||||
for (const key of this.supportedKeys) {
|
for (const key of this.supportedKeys) {
|
||||||
const button = this.mediaControlBar.querySelector(`#zen-media-${key}-button`);
|
const button = this.mediaControlBar.querySelector(`#zen-media-${key}-button`);
|
||||||
button.disabled = !event.target.supportedKeys.includes(key);
|
button.disabled = !event.target.supportedKeys.includes(key);
|
||||||
@@ -209,13 +299,61 @@ class ZenMediaController {
|
|||||||
* @param {Event} event - The position state change event.
|
* @param {Event} event - The position state change event.
|
||||||
*/
|
*/
|
||||||
_onPositionstateChange(event) {
|
_onPositionstateChange(event) {
|
||||||
if (event.target !== this._currentMediaController) return;
|
if (event.target !== this._currentMediaController) {
|
||||||
|
const mediaController = this.mediaControllersMap.get(event.target.id);
|
||||||
|
this.mediaControllersMap.set(event.target.id, {
|
||||||
|
...mediaController,
|
||||||
|
position: event.position,
|
||||||
|
duration: event.duration,
|
||||||
|
lastUpdated: Date.now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this._currentPosition = event.position;
|
this._currentPosition = event.position;
|
||||||
this._currentDuration = event.duration;
|
this._currentDuration = event.duration;
|
||||||
this.updateMediaPosition();
|
this.updateMediaPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switchController(force = false) {
|
||||||
|
let timeout = 3000;
|
||||||
|
|
||||||
|
if (this._controllerSwitchTimeout) {
|
||||||
|
clearTimeout(this._controllerSwitchTimeout);
|
||||||
|
this._controllerSwitchTimeout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mediaControllersMap.size === 1) timeout = 0;
|
||||||
|
this._controllerSwitchTimeout = setTimeout(() => {
|
||||||
|
if (!this._currentMediaController?.isPlaying || force) {
|
||||||
|
const nextController = Array.from(this.mediaControllersMap.values())
|
||||||
|
.filter(
|
||||||
|
(ctrl) =>
|
||||||
|
ctrl.controller.isPlaying &&
|
||||||
|
gBrowser.selectedBrowser.browserId !== ctrl.browser.browserId &&
|
||||||
|
ctrl.controller.id !== this._currentMediaController?.id
|
||||||
|
)
|
||||||
|
.sort((a, b) => b.lastUpdated - a.lastUpdated)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
if (nextController) {
|
||||||
|
this.deinitMediaController(this._currentMediaController, false, true, false).then(() => {
|
||||||
|
this.setupMediaController(nextController.controller, nextController.browser);
|
||||||
|
const elapsedTime = Math.floor((Date.now() - nextController.lastUpdated) / 1000);
|
||||||
|
|
||||||
|
this.setupMediaControlUI(nextController.controller.getMetadata(), {
|
||||||
|
position: nextController.position + (nextController.controller.isPlaying ? elapsedTime : 0),
|
||||||
|
duration: nextController.duration,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.showMediaControls();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._controllerSwitchTimeout = null;
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the media progress bar and time display.
|
* Updates the media progress bar and time display.
|
||||||
*/
|
*/
|
||||||
@@ -274,6 +412,9 @@ class ZenMediaController {
|
|||||||
* @param {Event} event - The metadata change event.
|
* @param {Event} event - The metadata change event.
|
||||||
*/
|
*/
|
||||||
_onMetadataChange(event) {
|
_onMetadataChange(event) {
|
||||||
|
if (event.target !== this._currentMediaController) return;
|
||||||
|
this.updatePipButton();
|
||||||
|
|
||||||
const metadata = event.target.getMetadata();
|
const metadata = event.target.getMetadata();
|
||||||
this.mediaTitle.textContent = metadata.title || '';
|
this.mediaTitle.textContent = metadata.title || '';
|
||||||
this.mediaArtist.textContent = metadata.artist || '';
|
this.mediaArtist.textContent = metadata.artist || '';
|
||||||
@@ -327,6 +468,18 @@ class ZenMediaController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onControllerClose() {
|
||||||
|
this._currentMediaController?.pause();
|
||||||
|
this.switchController(true);
|
||||||
|
this.deinitMediaController(this._currentMediaController, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMediaPip() {
|
||||||
|
this._currentBrowser.browsingContext.currentWindowGlobal
|
||||||
|
.getActor('PictureInPictureLauncher')
|
||||||
|
.sendAsyncMessage('PictureInPicture:KeyToggle');
|
||||||
|
}
|
||||||
|
|
||||||
updateMuteState() {
|
updateMuteState() {
|
||||||
if (!this._currentBrowser) return;
|
if (!this._currentBrowser) return;
|
||||||
if (this._currentBrowser._audioMuted) {
|
if (this._currentBrowser._audioMuted) {
|
||||||
@@ -335,6 +488,12 @@ class ZenMediaController {
|
|||||||
this.mediaControlBar.removeAttribute('muted');
|
this.mediaControlBar.removeAttribute('muted');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePipButton() {
|
||||||
|
const isPipEligible = this.pipEligibilityMap.get(this._currentBrowser.browserId);
|
||||||
|
if (isPipEligible) this.mediaControlBar.setAttribute('can-pip', '');
|
||||||
|
else this.mediaControlBar.removeAttribute('can-pip');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.gZenMediaController = new ZenMediaController();
|
window.gZenMediaController = new ZenMediaController();
|
||||||
|
@@ -1182,3 +1182,11 @@ menupopup > menuitem:is([type='checkbox']) .menu-iconic-left {
|
|||||||
#zen-media-focus-button:hover {
|
#zen-media-focus-button:hover {
|
||||||
list-style-image: url('screen.svg') !important;
|
list-style-image: url('screen.svg') !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zen-media-close-button {
|
||||||
|
list-style-image: url('close.svg') !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#zen-media-pip-button {
|
||||||
|
list-style-image: url('chrome://global/skin/media/picture-in-picture-open.svg') !important;
|
||||||
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs b/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs
|
diff --git a/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs b/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs
|
||||||
index 5da0404b2672ba8cce7bcf808bf2373474776654..c3d58941b66c54f9d506698d015e294f8c8a5ceb 100644
|
index 5da0404b2672ba8cce7bcf808bf2373474776654..44b62bd752294c2af96dd5b5d08c90ddf3dc513f 100644
|
||||||
--- a/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs
|
--- a/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs
|
||||||
+++ b/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs
|
+++ b/toolkit/components/pictureinpicture/PictureInPicture.sys.mjs
|
||||||
@@ -488,13 +488,13 @@ export var PictureInPicture = {
|
@@ -488,13 +488,13 @@ export var PictureInPicture = {
|
||||||
@@ -19,7 +19,15 @@ index 5da0404b2672ba8cce7bcf808bf2373474776654..c3d58941b66c54f9d506698d015e294f
|
|||||||
await this.closeSinglePipWindow({ reason: "Unpip", actorRef: pipActor });
|
await this.closeSinglePipWindow({ reason: "Unpip", actorRef: pipActor });
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -877,7 +877,7 @@ export var PictureInPicture = {
|
@@ -623,6 +623,7 @@ export var PictureInPicture = {
|
||||||
|
pipToggle.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ win.gZenMediaController.updatePipEligibility(browser, !pipToggle.hidden);
|
||||||
|
let browserHasPip = !!this.browserWeakMap.get(browser);
|
||||||
|
if (browserHasPip) {
|
||||||
|
this.setUrlbarPipIconActive(browser.ownerGlobal);
|
||||||
|
@@ -877,7 +878,7 @@ export var PictureInPicture = {
|
||||||
win.setIsMutedState(videoData.isMuted);
|
win.setIsMutedState(videoData.isMuted);
|
||||||
|
|
||||||
// set attribute which shows pip icon in tab
|
// set attribute which shows pip icon in tab
|
||||||
|
Reference in New Issue
Block a user