forked from EXT/VR180-Web-Player
Implement proper mute/unmute button functionality for 2D controls
- Add CSS classes (.muted/.unmuted) for mute button state management - Fix button logic to show action that will be taken (standard UI pattern): - When audio playing (unmuted): shows mute icon (click to mute) - When audio muted: shows unmute icon (click to unmute) - Add proper hover states for both mute and unmute icons - Initialize button state correctly on video load - Smooth 0.15s transitions between all states - Follows standard media player UI conventions
This commit is contained in:
@@ -162,6 +162,22 @@
|
|||||||
background-image: url(mute-hover.png);
|
background-image: url(mute-hover.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#mute.muted {
|
||||||
|
background-image: url(mute.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#mute.muted:hover {
|
||||||
|
background-image: url(mute-hover.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#mute.unmuted {
|
||||||
|
background-image: url(unmute.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#mute.unmuted:hover {
|
||||||
|
background-image: url(unmute-hover.png);
|
||||||
|
}
|
||||||
|
|
||||||
#nav {
|
#nav {
|
||||||
grid-area: nav;
|
grid-area: nav;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ let controlPanel, videoTitle, currentTimeDisplay, totalTimeDisplay, progressBar,
|
|||||||
let fullscreenBtn, backBtn, play2Btn, forwardBtn, muteBtn;
|
let fullscreenBtn, backBtn, play2Btn, forwardBtn, muteBtn;
|
||||||
let controlPanelTimeout;
|
let controlPanelTimeout;
|
||||||
let isControlPanelVisible = false;
|
let isControlPanelVisible = false;
|
||||||
const CONTROL_PANEL_HIDE_DELAY = 5000; // 5 seconds
|
const CONTROL_PANEL_HIDE_DELAY = 3000; // 3 seconds
|
||||||
|
|
||||||
let isXrLoopActive = false;
|
let isXrLoopActive = false;
|
||||||
let is2DMode = false;
|
let is2DMode = false;
|
||||||
@@ -555,6 +555,7 @@ function init() {
|
|||||||
updateVRPlayPauseButtonIcon();
|
updateVRPlayPauseButtonIcon();
|
||||||
updateVRVolumeButtonIcon();
|
updateVRVolumeButtonIcon();
|
||||||
update2DControlPanel();
|
update2DControlPanel();
|
||||||
|
update2DMuteButton();
|
||||||
};
|
};
|
||||||
video.oncanplaythrough = () => {
|
video.oncanplaythrough = () => {
|
||||||
if (playBtn && video.readyState >= video.HAVE_FUTURE_DATA) {
|
if (playBtn && video.readyState >= video.HAVE_FUTURE_DATA) {
|
||||||
@@ -795,6 +796,9 @@ function onMouseDown(event) {
|
|||||||
lastMouseY = event.clientY;
|
lastMouseY = event.clientY;
|
||||||
cameraVelocity.yaw = 0;
|
cameraVelocity.yaw = 0;
|
||||||
cameraVelocity.pitch = 0;
|
cameraVelocity.pitch = 0;
|
||||||
|
|
||||||
|
// Hide controls when dragging starts
|
||||||
|
hide2DControlPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMouseMove(event) {
|
function onMouseMove(event) {
|
||||||
@@ -813,6 +817,9 @@ function onMouseMove(event) {
|
|||||||
function onMouseUp(event) {
|
function onMouseUp(event) {
|
||||||
if (!is2DMode) return;
|
if (!is2DMode) return;
|
||||||
isDragging = false;
|
isDragging = false;
|
||||||
|
|
||||||
|
// Show controls when dragging ends
|
||||||
|
show2DControlPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Touch Controls
|
// Touch Controls
|
||||||
@@ -825,6 +832,9 @@ function onTouchStart(event) {
|
|||||||
lastTouchY = event.touches[0].clientY;
|
lastTouchY = event.touches[0].clientY;
|
||||||
cameraVelocity.yaw = 0;
|
cameraVelocity.yaw = 0;
|
||||||
cameraVelocity.pitch = 0;
|
cameraVelocity.pitch = 0;
|
||||||
|
|
||||||
|
// Hide controls when dragging starts
|
||||||
|
hide2DControlPanel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,6 +858,9 @@ function onTouchEnd(event) {
|
|||||||
if (!is2DMode) return;
|
if (!is2DMode) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
isDragging = false;
|
isDragging = false;
|
||||||
|
|
||||||
|
// Show controls when dragging ends
|
||||||
|
show2DControlPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2D Render Loop
|
// 2D Render Loop
|
||||||
@@ -942,8 +955,7 @@ function init2DControlPanel() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add mouse movement listener for 2D mode
|
// Mouse movement listener will be added to canvas in start2DMode
|
||||||
document.addEventListener('mousemove', on2DMouseMove);
|
|
||||||
document.addEventListener('touchstart', on2DTouchStart);
|
document.addEventListener('touchstart', on2DTouchStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -965,6 +977,12 @@ function hide2DControlPanel() {
|
|||||||
isControlPanelVisible = false;
|
isControlPanelVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCanvasMouseMove() {
|
||||||
|
if (is2DMode && !isDragging) {
|
||||||
|
show2DControlPanel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function on2DMouseMove() {
|
function on2DMouseMove() {
|
||||||
if (is2DMode) {
|
if (is2DMode) {
|
||||||
show2DControlPanel();
|
show2DControlPanel();
|
||||||
@@ -1011,8 +1029,15 @@ function update2DPlayPauseButton() {
|
|||||||
function update2DMuteButton() {
|
function update2DMuteButton() {
|
||||||
if (!is2DMode || !muteBtn || !video) return;
|
if (!is2DMode || !muteBtn || !video) return;
|
||||||
|
|
||||||
// The CSS will handle the visual state based on the muted property
|
if (video.muted) {
|
||||||
// We could add classes here if needed for different mute states
|
// Video is muted, show unmute icon (user can click to unmute)
|
||||||
|
muteBtn.classList.remove('muted');
|
||||||
|
muteBtn.classList.add('unmuted');
|
||||||
|
} else {
|
||||||
|
// Video is unmuted, show mute icon (user can click to mute)
|
||||||
|
muteBtn.classList.remove('unmuted');
|
||||||
|
muteBtn.classList.add('muted');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle2DFullscreen() {
|
function toggle2DFullscreen() {
|
||||||
@@ -1034,6 +1059,24 @@ function toggle2DFullscreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handle2DVideoEnd() {
|
||||||
|
if (!is2DMode || !video) return;
|
||||||
|
|
||||||
|
// Keep video at last frame (don't reset currentTime)
|
||||||
|
// Video is already paused by onVideoEnded()
|
||||||
|
|
||||||
|
// Show control panel and keep it visible (no auto-hide timeout)
|
||||||
|
if (controlPanel) {
|
||||||
|
clearTimeout(controlPanelTimeout);
|
||||||
|
controlPanel.classList.add('visible');
|
||||||
|
isControlPanelVisible = true;
|
||||||
|
// Don't set timeout - panel stays visible until user interacts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update play button to show replay state
|
||||||
|
update2DPlayPauseButton();
|
||||||
|
}
|
||||||
|
|
||||||
function position2DControlPanel() {
|
function position2DControlPanel() {
|
||||||
if (!is2DMode || !controlPanel || !renderer) return;
|
if (!is2DMode || !controlPanel || !renderer) return;
|
||||||
|
|
||||||
@@ -1089,10 +1132,20 @@ function enableNativeControls() {
|
|||||||
function togglePlayPause() {
|
function togglePlayPause() {
|
||||||
if (!video || !video.currentSrc) return;
|
if (!video || !video.currentSrc) return;
|
||||||
if (video.paused || video.ended) {
|
if (video.paused || video.ended) {
|
||||||
|
// If video has ended in 2D mode, restart from beginning
|
||||||
|
if (video.ended && is2DMode) {
|
||||||
|
video.currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (video.readyState >= video.HAVE_ENOUGH_DATA || video.currentSrc) {
|
if (video.readyState >= video.HAVE_ENOUGH_DATA || video.currentSrc) {
|
||||||
const playPromise = video.play();
|
const playPromise = video.play();
|
||||||
if (playPromise !== undefined) {
|
if (playPromise !== undefined) {
|
||||||
playPromise.catch(err => console.error("Error during video.play():", err));
|
playPromise.then(() => {
|
||||||
|
// Resume normal control panel auto-hide behavior after restart
|
||||||
|
if (is2DMode && video.ended === false) {
|
||||||
|
show2DControlPanel();
|
||||||
|
}
|
||||||
|
}).catch(err => console.error("Error during video.play():", err));
|
||||||
} else {
|
} else {
|
||||||
console.error("video.play() did not return a promise.");
|
console.error("video.play() did not return a promise.");
|
||||||
}
|
}
|
||||||
@@ -1147,7 +1200,9 @@ function resetToOriginalState() {
|
|||||||
|
|
||||||
function onVideoEnded() {
|
function onVideoEnded() {
|
||||||
if (video && !video.paused) video.pause();
|
if (video && !video.paused) video.pause();
|
||||||
|
|
||||||
if (xrSession && renderer && renderer.xr.isPresenting) {
|
if (xrSession && renderer && renderer.xr.isPresenting) {
|
||||||
|
// VR mode - exit VR and reset to original state
|
||||||
actualSessionToggle().catch(err => {
|
actualSessionToggle().catch(err => {
|
||||||
console.error("Error during automatic VR exit on video end:", err);
|
console.error("Error during automatic VR exit on video end:", err);
|
||||||
// Fallback cleanup if actualSessionToggle fails or doesn't fully clean up
|
// Fallback cleanup if actualSessionToggle fails or doesn't fully clean up
|
||||||
@@ -1160,8 +1215,11 @@ function onVideoEnded() {
|
|||||||
onVRSessionEnd({session: null}); // Call with null session if already gone
|
onVRSessionEnd({session: null}); // Call with null session if already gone
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if (is2DMode) {
|
||||||
|
// 2D mode - stay on last frame with controls visible
|
||||||
|
handle2DVideoEnd();
|
||||||
} else {
|
} else {
|
||||||
// If not in VR, still reset to original state when video ends
|
// Regular mode - reset to original state
|
||||||
resetToOriginalState();
|
resetToOriginalState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1298,6 +1356,9 @@ function add2DEventListeners() {
|
|||||||
renderer.domElement.addEventListener('mousemove', onMouseMove);
|
renderer.domElement.addEventListener('mousemove', onMouseMove);
|
||||||
renderer.domElement.addEventListener('mouseup', onMouseUp);
|
renderer.domElement.addEventListener('mouseup', onMouseUp);
|
||||||
|
|
||||||
|
// Canvas-specific mouse movement for showing controls
|
||||||
|
renderer.domElement.addEventListener('mousemove', onCanvasMouseMove);
|
||||||
|
|
||||||
// Touch events
|
// Touch events
|
||||||
renderer.domElement.addEventListener('touchstart', onTouchStart, { passive: false });
|
renderer.domElement.addEventListener('touchstart', onTouchStart, { passive: false });
|
||||||
renderer.domElement.addEventListener('touchmove', onTouchMove, { passive: false });
|
renderer.domElement.addEventListener('touchmove', onTouchMove, { passive: false });
|
||||||
|
|||||||
Reference in New Issue
Block a user