mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-07 07:58:53 -05:00
fix: Make seekbar more touch-friendly on Android
This commit is contained in:
parent
57616c6b81
commit
b04ad2344c
@ -23,6 +23,37 @@ html {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Simple fix: Move seekbar up by 10px on touch devices */
|
||||
.video-js .vjs-progress-control {
|
||||
bottom: 56px !important; /* Move up 10px from original 46px */
|
||||
}
|
||||
|
||||
/* Make seekbar more touch-friendly on Android */
|
||||
.video-js .vjs-progress-holder {
|
||||
touch-action: pan-x !important;
|
||||
-webkit-touch-callout: none !important;
|
||||
-webkit-user-select: none !important;
|
||||
user-select: none !important;
|
||||
}
|
||||
|
||||
.video-js .vjs-seek-bar {
|
||||
touch-action: pan-x !important;
|
||||
-webkit-touch-callout: none !important;
|
||||
-webkit-user-select: none !important;
|
||||
user-select: none !important;
|
||||
}
|
||||
|
||||
/* Prevent big play button from interfering with seekbar on touch devices */
|
||||
.video-js .vjs-big-play-button {
|
||||
pointer-events: auto !important;
|
||||
z-index: 1 !important; /* Lower than seekbar */
|
||||
}
|
||||
|
||||
.video-js .vjs-progress-control {
|
||||
z-index: 10 !important; /* Higher than big play button */
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* Exception: Allow intentional touch-activated tooltips */
|
||||
.video-js .vjs-autoplay-toggle.touch-active::after {
|
||||
opacity: 1 !important;
|
||||
@ -744,6 +775,7 @@ html {
|
||||
.vjs-slider-horizontal {
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
.video-js .vjs-spacer-control {
|
||||
flex: 1 !important;
|
||||
min-width: 1px !important;
|
||||
@ -1364,56 +1396,6 @@ button.vjs-button > .vjs-icon-placeholder:before {
|
||||
width: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Disable all tooltips on touch devices */
|
||||
.video-js .vjs-control:hover::after,
|
||||
.video-js .vjs-control:focus::after,
|
||||
.video-js .vjs-control:active::after {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
.video-js .vjs-play-control:hover::after,
|
||||
.video-js .vjs-mute-control:hover::after,
|
||||
.video-js .vjs-volume-panel:hover::after,
|
||||
.video-js .vjs-fullscreen-control:hover::after,
|
||||
.video-js .vjs-picture-in-picture-control:hover::after,
|
||||
.video-js .vjs-settings-control:hover::after,
|
||||
.video-js .vjs-chapters-control:hover::after,
|
||||
.video-js .vjs-autoplay-toggle:hover::after,
|
||||
.video-js .vjs-next-video-control:hover::after,
|
||||
.video-js .vjs-remaining-time:hover::after {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Disable Video.js native control text tooltips on touch devices */
|
||||
.video-js button.vjs-button:hover span.vjs-control-text {
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Disable chapter marker tooltips on touch devices */
|
||||
.vjs-chapter-marker:hover .vjs-chapter-marker-tooltip {
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Disable chapter floating tooltips on touch devices */
|
||||
.vjs-chapter-floating-tooltip,
|
||||
.vjs-sprite-preview-tooltip {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
/* Exception: Allow touch-activated autoplay tooltip on touch devices */
|
||||
.video-js .vjs-autoplay-toggle.touch-active::after {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
@ -1535,6 +1517,11 @@ button.vjs-button > .vjs-icon-placeholder:before {
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* Move seekbar up by 10px on mobile to prevent accidental button touches */
|
||||
.video-js .vjs-progress-control {
|
||||
bottom: 56px !important; /* Move up 10px from original 46px */
|
||||
}
|
||||
|
||||
.vjs-related-vdeo-item:nth-child(n + 5) {
|
||||
display: none;
|
||||
}
|
||||
@ -1773,6 +1760,11 @@ button.vjs-button > .vjs-icon-placeholder:before {
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
/* Move seekbar up by 10px on small mobile to prevent accidental button touches */
|
||||
.video-js .vjs-progress-control {
|
||||
bottom: 56px !important; /* Move up 10px from original 46px */
|
||||
}
|
||||
|
||||
.video-container {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
@ -1047,7 +1047,7 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
||||
},
|
||||
|
||||
// other
|
||||
useRoundedCorners: false,
|
||||
useRoundedCorners: true,
|
||||
isPlayList: true,
|
||||
previewSprite: {
|
||||
url: 'https://deic.mediacms.io/media/original/thumbnails/user/thorkild/2ca18fadeef8475eae513c12cc0830d3.19990812hd_1920_1080_30fps.mp4sprites.jpg',
|
||||
@ -1998,14 +1998,27 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
||||
touchStartTime = Date.now();
|
||||
const touch = e.touches[0];
|
||||
touchStartPos = { x: touch.clientX, y: touch.clientY };
|
||||
|
||||
// Check if touch is in seekbar area
|
||||
const progressControl = playerRef.current
|
||||
.getChild('controlBar')
|
||||
?.getChild('progressControl');
|
||||
if (progressControl && progressControl.el()) {
|
||||
const progressRect = progressControl.el().getBoundingClientRect();
|
||||
const isInSeekbarArea =
|
||||
touch.clientY >= progressRect.top && touch.clientY <= progressRect.bottom;
|
||||
if (isInSeekbarArea) {
|
||||
playerRef.current.seekbarTouching = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchEnd = (e) => {
|
||||
const touchEndTime = Date.now();
|
||||
const touchDuration = touchEndTime - touchStartTime;
|
||||
|
||||
// Only handle if it's a quick tap
|
||||
if (touchDuration < 500) {
|
||||
// Only handle if it's a quick tap and we're not touching the seekbar
|
||||
if (touchDuration < 500 && !playerRef.current.seekbarTouching) {
|
||||
const touch = e.changedTouches[0];
|
||||
const touchEndPos = { x: touch.clientX, y: touch.clientY };
|
||||
const distance = Math.sqrt(
|
||||
@ -2025,6 +2038,13 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always clear seekbar touching flag at the end
|
||||
setTimeout(() => {
|
||||
if (playerRef.current) {
|
||||
playerRef.current.seekbarTouching = false;
|
||||
}
|
||||
}, 50);
|
||||
};
|
||||
|
||||
videoEl.addEventListener('touchstart', handleTouchStart, { passive: true });
|
||||
@ -2506,6 +2526,100 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
||||
|
||||
// Store components reference for potential cleanup
|
||||
|
||||
// BEGIN: Fix Android seekbar touch functionality
|
||||
if (isTouchDevice) {
|
||||
setTimeout(() => {
|
||||
const progressControl = playerRef.current
|
||||
.getChild('controlBar')
|
||||
?.getChild('progressControl');
|
||||
const seekBar = progressControl?.getChild('seekBar');
|
||||
|
||||
if (seekBar && seekBar.el()) {
|
||||
const seekBarEl = seekBar.el();
|
||||
const progressHolder = seekBarEl.querySelector('.vjs-progress-holder');
|
||||
|
||||
if (progressHolder) {
|
||||
let isDragging = false;
|
||||
|
||||
const handleTouchStart = (e) => {
|
||||
isDragging = true;
|
||||
e.preventDefault();
|
||||
e.stopPropagation(); // Prevent event from reaching video element
|
||||
playerRef.current.userActive(true);
|
||||
|
||||
// Mark that we're interacting with seekbar to prevent play/pause
|
||||
playerRef.current.seekbarTouching = true;
|
||||
|
||||
// Temporarily disable big play button
|
||||
const bigPlayButton = playerRef.current.getChild('bigPlayButton');
|
||||
if (bigPlayButton && bigPlayButton.el()) {
|
||||
bigPlayButton.el().style.pointerEvents = 'none';
|
||||
bigPlayButton.el().style.touchAction = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchMove = (e) => {
|
||||
if (!isDragging) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation(); // Prevent event from reaching video element
|
||||
|
||||
const touch = e.touches[0];
|
||||
const rect = progressHolder.getBoundingClientRect();
|
||||
const percentage = Math.max(
|
||||
0,
|
||||
Math.min(1, (touch.clientX - rect.left) / rect.width)
|
||||
);
|
||||
const duration = playerRef.current.duration();
|
||||
|
||||
if (duration && !isNaN(duration)) {
|
||||
const newTime = percentage * duration;
|
||||
playerRef.current.currentTime(newTime);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchEnd = (e) => {
|
||||
isDragging = false;
|
||||
e.preventDefault();
|
||||
e.stopPropagation(); // Prevent event from reaching video element
|
||||
|
||||
// Re-enable big play button
|
||||
const bigPlayButton = playerRef.current.getChild('bigPlayButton');
|
||||
if (bigPlayButton && bigPlayButton.el()) {
|
||||
setTimeout(() => {
|
||||
bigPlayButton.el().style.pointerEvents = '';
|
||||
bigPlayButton.el().style.touchAction = '';
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// Clear the seekbar touching flag after a longer delay to prevent conflicts
|
||||
setTimeout(() => {
|
||||
if (playerRef.current) {
|
||||
playerRef.current.seekbarTouching = false;
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// Add touch event listeners specifically for Android
|
||||
progressHolder.addEventListener('touchstart', handleTouchStart, {
|
||||
passive: false,
|
||||
});
|
||||
progressHolder.addEventListener('touchmove', handleTouchMove, {
|
||||
passive: false,
|
||||
});
|
||||
progressHolder.addEventListener('touchend', handleTouchEnd, { passive: false });
|
||||
|
||||
// Store cleanup function
|
||||
customComponents.current.cleanupSeekbarTouch = () => {
|
||||
progressHolder.removeEventListener('touchstart', handleTouchStart);
|
||||
progressHolder.removeEventListener('touchmove', handleTouchMove);
|
||||
progressHolder.removeEventListener('touchend', handleTouchEnd);
|
||||
};
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
// END: Fix Android seekbar touch functionality
|
||||
|
||||
// BEGIN: Add comprehensive keyboard event handling
|
||||
const handleAllKeyboardEvents = (event) => {
|
||||
// Only handle if no input elements are focused
|
||||
@ -2805,6 +2919,11 @@ function VideoJSPlayer({ videoId = 'default-video' }) {
|
||||
customComponents.current.cleanupArrowKeyHandler();
|
||||
}
|
||||
|
||||
// Clean up seekbar touch handlers if they exist
|
||||
if (customComponents.current && customComponents.current.cleanupSeekbarTouch) {
|
||||
customComponents.current.cleanupSeekbarTouch();
|
||||
}
|
||||
|
||||
if (playerRef.current && !playerRef.current.isDisposed()) {
|
||||
playerRef.current.dispose();
|
||||
playerRef.current = null;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user