Add mobile support and responsive player controls
- Mobile devices open player in new tab (better than PiP) - Add playsInline attribute for iOS autoplay support - Responsive controls: hide PiP/auto-resize/always-on-top on mobile - Implement togglePip function for desktop PiP button - Optimize button sizes and spacing for touch screens - Detect mobile via user agent and fallback gracefully
This commit is contained in:
parent
a6c76456d4
commit
962a89c3a6
4 changed files with 89 additions and 4 deletions
|
|
@ -41,6 +41,26 @@
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle Picture-in-Picture mode
|
||||
*/
|
||||
window.togglePip = async function() {
|
||||
if (!document.pictureInPictureEnabled || !media || media.tagName !== 'VIDEO') {
|
||||
alert('Picture-in-Picture is not supported for this media');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (document.pictureInPictureElement) {
|
||||
await document.exitPictureInPicture();
|
||||
} else {
|
||||
await media.requestPictureInPicture();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error toggling PiP:', err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle fullscreen mode
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -128,7 +128,16 @@ async function loadMedia(mediaElement, productId) {
|
|||
}
|
||||
|
||||
async function openMediaPlayer(productId) {
|
||||
// Fetch player data to get media URL and navigation info
|
||||
// Mobile detection
|
||||
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
|
||||
// On mobile, open in new tab (works better than PiP)
|
||||
if (isMobile) {
|
||||
window.open(`/player/${productId}`, '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
// Desktop: Fetch player data to get media URL and navigation info
|
||||
try {
|
||||
const response = await fetch(`/player/${productId}`);
|
||||
const html = await response.text();
|
||||
|
|
@ -154,6 +163,7 @@ async function openMediaPlayer(productId) {
|
|||
media.style.zIndex = '9999';
|
||||
media.controls = true;
|
||||
media.autoplay = true;
|
||||
media.playsInline = true; // Important for iOS
|
||||
document.body.appendChild(media);
|
||||
|
||||
// Extract playerData from script
|
||||
|
|
|
|||
|
|
@ -40,6 +40,46 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
/* Mobile optimizations */
|
||||
@media (max-width: 600px) {
|
||||
.controls-grid {
|
||||
padding: 1rem;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.controls-grid button {
|
||||
padding: 0.6rem 0.8rem;
|
||||
font-size: 0.9rem;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.controls-grid button.nav-btn,
|
||||
.controls-grid button.play-btn {
|
||||
font-size: 1.3rem;
|
||||
padding: 0.8rem;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
font-size: 1rem;
|
||||
padding: 0.4rem 0.8rem;
|
||||
}
|
||||
|
||||
/* Hide desktop-only buttons on mobile */
|
||||
#pipBtn,
|
||||
#autoResizeBtn,
|
||||
#alwaysOnTopBtn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Adjust grid for mobile - only show essential buttons */
|
||||
.controls-grid {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: auto auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Player controls overlay - centered grid */
|
||||
.player-controls {
|
||||
grid-area: media;
|
||||
|
|
@ -137,11 +177,11 @@
|
|||
<body>
|
||||
<div class="player-container" id="playerContainer">
|
||||
{% if media_type == 'video' %}
|
||||
<video id="media" src="{{ presigned_url }}" autoplay controls>
|
||||
<video id="media" src="{{ presigned_url }}" autoplay controls playsinline>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
{% elif media_type == 'audio' %}
|
||||
<audio id="media" src="{{ presigned_url }}" autoplay controls>
|
||||
<audio id="media" src="{{ presigned_url }}" autoplay controls playsinline>
|
||||
Your browser does not support the audio tag.
|
||||
</audio>
|
||||
{% elif media_type == 'image' %}
|
||||
|
|
@ -170,7 +210,12 @@
|
|||
<!-- Row 2: Features -->
|
||||
<button id="alwaysOnTopBtn" onclick="toggleAlwaysOnTop()" title="Always on Top (T)">📌 On Top</button>
|
||||
<button id="fullscreenBtn" onclick="toggleFullscreen()" title="Fullscreen (F)">⛶ Full</button>
|
||||
<button id="pipBtn" onclick="togglePip()" title="Picture-in-Picture (P)">📺 PiP</button>
|
||||
|
||||
<!-- Row 3: More options -->
|
||||
<button id="autoResizeBtn" onclick="toggleAutoResize()" title="Auto-Resize Window (R)">↔ Resize</button>
|
||||
<button onclick="window.close()" title="Close Window (ESC)">✕ Close</button>
|
||||
<div></div><!-- Empty cell for grid alignment -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -206,7 +206,16 @@ async function loadMedia(mediaElement, productId) {
|
|||
}
|
||||
|
||||
async function openMediaPlayer(productId) {
|
||||
// Fetch player data to get media URL and navigation info
|
||||
// Mobile detection
|
||||
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
|
||||
// On mobile, open in new tab (works better than PiP)
|
||||
if (isMobile) {
|
||||
window.open(`/player/${productId}`, '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
// Desktop: Fetch player data to get media URL and navigation info
|
||||
try {
|
||||
const response = await fetch(`/player/${productId}`);
|
||||
const html = await response.text();
|
||||
|
|
@ -232,6 +241,7 @@ async function openMediaPlayer(productId) {
|
|||
media.style.zIndex = '9999';
|
||||
media.controls = true;
|
||||
media.autoplay = true;
|
||||
media.playsInline = true; // Important for iOS
|
||||
document.body.appendChild(media);
|
||||
|
||||
// Extract playerData from script
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue