mirror of
https://github.com/zen-browser/desktop.git
synced 2025-09-05 19:08:18 +00:00
Fix media control not working for web panels
This commit is contained in:
@@ -35,6 +35,7 @@ class ZenMediaController {
|
||||
this.onSupportedKeysChange = this._onSupportedKeysChange.bind(this);
|
||||
this.onMetadataChange = this._onMetadataChange.bind(this);
|
||||
this.onDeactivated = this._onDeactivated.bind(this);
|
||||
this.onPipModeChange = this._onPictureInPictureModeChange.bind(this);
|
||||
|
||||
window.addEventListener('TabSelect', (event) => {
|
||||
const linkedBrowser = event.target.linkedBrowser;
|
||||
@@ -87,21 +88,13 @@ class ZenMediaController {
|
||||
window.addEventListener('DOMAudioPlaybackStopped', () => this.updateMuteState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deinitializes a media controller, removing all event listeners and resetting state.
|
||||
* @param {Object} mediaController - The media controller to deinitialize.
|
||||
*/
|
||||
async deinitMediaController(mediaController, shouldForget = true, shouldOverride = true, shouldHide = true) {
|
||||
if (!mediaController) return;
|
||||
|
||||
const retrievedMediaController = this.mediaControllersMap.get(mediaController.id);
|
||||
|
||||
if (this.tabObserver && shouldOverride) {
|
||||
this.tabObserver.disconnect();
|
||||
this.tabObserver = null;
|
||||
}
|
||||
|
||||
if (shouldForget) {
|
||||
mediaController.removeEventListener('pictureinpicturemodechange', this.onPipModeChange);
|
||||
mediaController.removeEventListener('positionstatechange', this.onPositionstateChange);
|
||||
mediaController.removeEventListener('playbackstatechange', this.onPlaybackstateChange);
|
||||
mediaController.removeEventListener('supportedkeyschange', this.onSupportedKeysChange);
|
||||
@@ -148,10 +141,9 @@ class ZenMediaController {
|
||||
}
|
||||
|
||||
showMediaControls() {
|
||||
const tab = gBrowser.getTabForBrowser(this._currentBrowser);
|
||||
if (tab.hasAttribute('pictureinpicture')) return this.hideMediaControls();
|
||||
|
||||
if (this._currentMediaController.isBeingUsedInPIPModeOrFullscreen) return this.hideMediaControls();
|
||||
if (!this.mediaControlBar.hasAttribute('hidden')) return;
|
||||
|
||||
this.updatePipButton();
|
||||
|
||||
this.mediaControlBar.removeAttribute('hidden');
|
||||
@@ -190,27 +182,6 @@ class ZenMediaController {
|
||||
|
||||
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,
|
||||
@@ -221,11 +192,6 @@ class ZenMediaController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the media control UI with metadata and position state.
|
||||
* @param {Object} metadata - The media metadata (title, artist, etc.).
|
||||
* @param {Object} positionState - The position state (position, duration).
|
||||
*/
|
||||
setupMediaControlUI(metadata, positionState) {
|
||||
this.updatePipButton();
|
||||
|
||||
@@ -251,10 +217,6 @@ class ZenMediaController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} mediaController - The media controller to activate.
|
||||
* @param {Object} browser - The browser associated with the media controller.
|
||||
*/
|
||||
activateMediaControls(mediaController, browser) {
|
||||
this.updateMuteState();
|
||||
this.switchController();
|
||||
@@ -276,6 +238,7 @@ class ZenMediaController {
|
||||
this.setupMediaControlUI(metadata, positionState);
|
||||
}
|
||||
|
||||
mediaController.addEventListener('pictureinpicturemodechange', this.onPipModeChange);
|
||||
mediaController.addEventListener('positionstatechange', this.onPositionstateChange);
|
||||
mediaController.addEventListener('playbackstatechange', this.onPlaybackstateChange);
|
||||
mediaController.addEventListener('supportedkeyschange', this.onSupportedKeysChange);
|
||||
@@ -287,18 +250,11 @@ class ZenMediaController {
|
||||
this.pipEligibilityMap.set(browser.browserId, isEligible);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Event} event - The deactivation event.
|
||||
*/
|
||||
_onDeactivated(event) {
|
||||
this.deinitMediaController(event.target, true, event.target.id === this._currentMediaController.id, true);
|
||||
this.switchController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates playback state and UI based on changes.
|
||||
* @param {Event} event - The playback state change event.
|
||||
*/
|
||||
_onPlaybackstateChange() {
|
||||
if (this._currentMediaController?.isPlaying) {
|
||||
this.mediaControlBar.classList.add('playing');
|
||||
@@ -308,24 +264,16 @@ class ZenMediaController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates supported keys in the UI.
|
||||
* @param {Event} event - The supported keys change event.
|
||||
*/
|
||||
_onSupportedKeysChange(event) {
|
||||
if (event.target !== this._currentMediaController) return;
|
||||
if (event.target.id !== this._currentMediaController?.id) return;
|
||||
for (const key of this.supportedKeys) {
|
||||
const button = this.mediaControlBar.querySelector(`#zen-media-${key}-button`);
|
||||
button.disabled = !event.target.supportedKeys.includes(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates position state and UI when the media position changes.
|
||||
* @param {Event} event - The position state change event.
|
||||
*/
|
||||
_onPositionstateChange(event) {
|
||||
if (event.target !== this._currentMediaController) {
|
||||
if (event.target.id !== this._currentMediaController?.id) {
|
||||
const mediaController = this.mediaControllersMap.get(event.target.id);
|
||||
this.mediaControllersMap.set(event.target.id, {
|
||||
...mediaController,
|
||||
@@ -362,7 +310,7 @@ class ZenMediaController {
|
||||
.shift();
|
||||
|
||||
if (nextController) {
|
||||
this.deinitMediaController(this._currentMediaController, false, true, false).then(() => {
|
||||
this.deinitMediaController(this._currentMediaController, false, true).then(() => {
|
||||
this.setupMediaController(nextController.controller, nextController.browser);
|
||||
const elapsedTime = Math.floor((Date.now() - nextController.lastUpdated) / 1000);
|
||||
|
||||
@@ -380,9 +328,6 @@ class ZenMediaController {
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the media progress bar and time display.
|
||||
*/
|
||||
updateMediaPosition() {
|
||||
if (this._mediaUpdateInterval) {
|
||||
clearInterval(this._mediaUpdateInterval);
|
||||
@@ -413,11 +358,6 @@ class ZenMediaController {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats seconds into a hours:minutes:seconds string.
|
||||
* @param {number} seconds - The time in seconds.
|
||||
* @returns {string} Formatted time string.
|
||||
*/
|
||||
formatSecondsToTime(seconds) {
|
||||
if (!seconds || isNaN(seconds)) return '0:00';
|
||||
|
||||
@@ -433,12 +373,8 @@ class ZenMediaController {
|
||||
return `${minutes}:${secs.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates metadata in the UI.
|
||||
* @param {Event} event - The metadata change event.
|
||||
*/
|
||||
_onMetadataChange(event) {
|
||||
if (event.target !== this._currentMediaController) return;
|
||||
if (event.target.id !== this._currentMediaController.id) return;
|
||||
this.updatePipButton();
|
||||
|
||||
const metadata = event.target.getMetadata();
|
||||
@@ -446,6 +382,21 @@ class ZenMediaController {
|
||||
this.mediaArtist.textContent = metadata.artist || '';
|
||||
}
|
||||
|
||||
_onPictureInPictureModeChange(event) {
|
||||
if (event.target.id !== this._currentMediaController.id) return;
|
||||
if (event.target.isBeingUsedInPIPModeOrFullscreen) {
|
||||
this.hideMediaControls();
|
||||
this.mediaControlBar.setAttribute('pip', '');
|
||||
} else {
|
||||
const { selectedBrowser } = gBrowser;
|
||||
if (selectedBrowser.browserId !== this._currentBrowser.browserId) {
|
||||
this.showMediaControls();
|
||||
}
|
||||
|
||||
this.mediaControlBar.removeAttribute('pip');
|
||||
}
|
||||
}
|
||||
|
||||
onMediaPlayPrev() {
|
||||
if (this._currentMediaController?.supportedKeys.includes('previoustrack')) {
|
||||
this._currentMediaController.prevTrack();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
diff --git a/dom/chrome-webidl/MediaController.webidl b/dom/chrome-webidl/MediaController.webidl
|
||||
index 20f416d1c3b41798e0f90bbac5db40ed2a4ab000..06cb4c847fcfba964eeb93089613e293dc10bd87 100644
|
||||
index 20f416d1c3b41798e0f90bbac5db40ed2a4ab000..1c5d893f9166a3aa7bc7802bb0d1207d169033ee 100644
|
||||
--- a/dom/chrome-webidl/MediaController.webidl
|
||||
+++ b/dom/chrome-webidl/MediaController.webidl
|
||||
@@ -20,6 +20,12 @@ enum MediaControlKey {
|
||||
@@ -15,7 +15,12 @@ index 20f416d1c3b41798e0f90bbac5db40ed2a4ab000..06cb4c847fcfba964eeb93089613e293
|
||||
/**
|
||||
* MediaController is used to control media playback for a tab, and each tab
|
||||
* would only have one media controller, which can be accessed from the
|
||||
@@ -36,6 +42,9 @@ interface MediaController : EventTarget {
|
||||
@@ -32,10 +38,14 @@ interface MediaController : EventTarget {
|
||||
readonly attribute boolean isAudible;
|
||||
readonly attribute boolean isPlaying;
|
||||
readonly attribute MediaSessionPlaybackState playbackState;
|
||||
+ readonly attribute boolean isBeingUsedInPIPModeOrFullscreen;
|
||||
|
||||
[Throws]
|
||||
MediaMetadataInit getMetadata();
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
diff --git a/dom/media/mediacontrol/MediaController.cpp b/dom/media/mediacontrol/MediaController.cpp
|
||||
index 3f08d24d4ed56bb72ed513ed602b2c8fa48afe7b..690d9abdb0ab8efc019dd606743b82504834faa0 100644
|
||||
index 3f08d24d4ed56bb72ed513ed602b2c8fa48afe7b..98dfe4df48f5daebd2b619f0d4d4eb3ac873a66f 100644
|
||||
--- a/dom/media/mediacontrol/MediaController.cpp
|
||||
+++ b/dom/media/mediacontrol/MediaController.cpp
|
||||
@@ -51,6 +51,25 @@ void MediaController::GetSupportedKeys(
|
||||
@@ -28,3 +28,11 @@ index 3f08d24d4ed56bb72ed513ed602b2c8fa48afe7b..690d9abdb0ab8efc019dd606743b8250
|
||||
void MediaController::GetMetadata(MediaMetadataInit& aMetadata,
|
||||
ErrorResult& aRv) {
|
||||
if (!IsActive() || mShutdown) {
|
||||
@@ -412,6 +431,7 @@ void MediaController::SetIsInPictureInPictureMode(
|
||||
ForceToBecomeMainControllerIfNeeded();
|
||||
UpdateDeactivationTimerIfNeeded();
|
||||
mPictureInPictureModeChangedEvent.Notify(mIsInPictureInPictureMode);
|
||||
+ DispatchAsyncEvent(u"pictureinpicturemodechange"_ns);
|
||||
}
|
||||
|
||||
void MediaController::NotifyMediaFullScreenState(uint64_t aBrowsingContextId,
|
||||
|
Reference in New Issue
Block a user