unified-video-framework 1.4.119 → 1.4.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -739,87 +739,26 @@ export class WebPlayer extends BasePlayer {
|
|
|
739
739
|
this.debugWarn('Failed to exit fullscreen:', error.message);
|
|
740
740
|
}
|
|
741
741
|
}
|
|
742
|
-
isPictureInPictureSupported() {
|
|
743
|
-
if (!this.video)
|
|
744
|
-
return false;
|
|
745
|
-
const hasStandardPiP = 'requestPictureInPicture' in this.video &&
|
|
746
|
-
'pictureInPictureEnabled' in document;
|
|
747
|
-
const hasSafariPiP = 'webkitSupportsPresentationMode' in this.video &&
|
|
748
|
-
typeof this.video.webkitSupportsPresentationMode === 'function' &&
|
|
749
|
-
this.video.webkitSupportsPresentationMode('picture-in-picture');
|
|
750
|
-
const userAgent = navigator.userAgent.toLowerCase();
|
|
751
|
-
const isIOS = /iphone|ipad|ipod/.test(userAgent);
|
|
752
|
-
const isAndroid = /android/.test(userAgent);
|
|
753
|
-
const isChrome = /chrome/.test(userAgent) && !/edge/.test(userAgent);
|
|
754
|
-
const isSafari = /safari/.test(userAgent) && !/chrome/.test(userAgent);
|
|
755
|
-
const isFirefox = /firefox/.test(userAgent);
|
|
756
|
-
const iosSupport = isIOS && isSafari && hasSafariPiP;
|
|
757
|
-
const androidChromeSupport = isAndroid && isChrome && hasStandardPiP;
|
|
758
|
-
const firefoxSupport = isFirefox && hasStandardPiP && !this.isMobileDevice();
|
|
759
|
-
this.debugLog('PiP Support Detection:', {
|
|
760
|
-
hasStandardPiP,
|
|
761
|
-
hasSafariPiP,
|
|
762
|
-
isIOS,
|
|
763
|
-
isAndroid,
|
|
764
|
-
isChrome,
|
|
765
|
-
isSafari,
|
|
766
|
-
isFirefox,
|
|
767
|
-
iosSupport,
|
|
768
|
-
androidChromeSupport,
|
|
769
|
-
firefoxSupport,
|
|
770
|
-
overall: hasStandardPiP || iosSupport || androidChromeSupport || firefoxSupport
|
|
771
|
-
});
|
|
772
|
-
return hasStandardPiP || iosSupport || androidChromeSupport || firefoxSupport;
|
|
773
|
-
}
|
|
774
|
-
isMobileDevice() {
|
|
775
|
-
const userAgent = navigator.userAgent.toLowerCase();
|
|
776
|
-
return /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/.test(userAgent) ||
|
|
777
|
-
(!!(navigator.maxTouchPoints && navigator.maxTouchPoints > 2) && /macintosh/.test(userAgent));
|
|
778
|
-
}
|
|
779
742
|
async enterPictureInPicture() {
|
|
780
|
-
if (!this.video)
|
|
781
|
-
|
|
782
|
-
}
|
|
783
|
-
if (!this.isPictureInPictureSupported()) {
|
|
784
|
-
throw new Error('Picture-in-Picture not supported on this device/browser');
|
|
785
|
-
}
|
|
743
|
+
if (!this.video)
|
|
744
|
+
return;
|
|
786
745
|
try {
|
|
787
|
-
if (
|
|
746
|
+
if (this.video.requestPictureInPicture) {
|
|
788
747
|
await this.video.requestPictureInPicture();
|
|
789
|
-
this.debugLog('PiP entered using standard API');
|
|
790
|
-
return;
|
|
791
748
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
this.debugLog('PiP entered using WebKit API');
|
|
795
|
-
return;
|
|
749
|
+
else {
|
|
750
|
+
throw new Error('Picture-in-Picture not supported');
|
|
796
751
|
}
|
|
797
|
-
throw new Error('No supported PiP API available');
|
|
798
752
|
}
|
|
799
753
|
catch (error) {
|
|
800
|
-
|
|
754
|
+
console.error('Failed to enter PiP:', error);
|
|
801
755
|
throw error;
|
|
802
756
|
}
|
|
803
757
|
}
|
|
804
758
|
async exitPictureInPicture() {
|
|
805
759
|
try {
|
|
806
|
-
|
|
807
|
-
const inWebkitPiP = this.video &&
|
|
808
|
-
'webkitPresentationMode' in this.video &&
|
|
809
|
-
this.video.webkitPresentationMode === 'picture-in-picture';
|
|
810
|
-
if (!inStandardPiP && !inWebkitPiP) {
|
|
811
|
-
this.debugLog('Not currently in PiP mode');
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
if (inStandardPiP && 'exitPictureInPicture' in document) {
|
|
760
|
+
if (document.exitPictureInPicture) {
|
|
815
761
|
await document.exitPictureInPicture();
|
|
816
|
-
this.debugLog('PiP exited using standard API');
|
|
817
|
-
return;
|
|
818
|
-
}
|
|
819
|
-
if (inWebkitPiP && this.video && 'webkitSetPresentationMode' in this.video) {
|
|
820
|
-
this.video.webkitSetPresentationMode('inline');
|
|
821
|
-
this.debugLog('PiP exited using WebKit API');
|
|
822
|
-
return;
|
|
823
762
|
}
|
|
824
763
|
}
|
|
825
764
|
catch (error) {
|
|
@@ -1529,44 +1468,16 @@ export class WebPlayer extends BasePlayer {
|
|
|
1529
1468
|
}
|
|
1530
1469
|
|
|
1531
1470
|
.uvf-video {
|
|
1532
|
-
|
|
1533
|
-
top: 50%;
|
|
1534
|
-
left: 50%;
|
|
1535
|
-
transform: translate(-50%, -50%);
|
|
1471
|
+
display: block;
|
|
1536
1472
|
max-width: 100%;
|
|
1537
1473
|
max-height: 100%;
|
|
1538
|
-
width:
|
|
1539
|
-
height:
|
|
1474
|
+
width: 100%;
|
|
1475
|
+
height: 100%;
|
|
1540
1476
|
background: #000;
|
|
1541
1477
|
object-fit: contain;
|
|
1542
|
-
/* Ensure proper centering and scaling */
|
|
1543
1478
|
object-position: center;
|
|
1544
1479
|
}
|
|
1545
1480
|
|
|
1546
|
-
/* Mobile-specific video centering improvements */
|
|
1547
|
-
@media screen and (max-width: 767px) {
|
|
1548
|
-
.uvf-video {
|
|
1549
|
-
/* Force full width/height on mobile for better centering */
|
|
1550
|
-
width: 100%;
|
|
1551
|
-
height: 100%;
|
|
1552
|
-
top: 0;
|
|
1553
|
-
left: 0;
|
|
1554
|
-
transform: none;
|
|
1555
|
-
object-fit: contain;
|
|
1556
|
-
object-position: center;
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
.uvf-video-container {
|
|
1560
|
-
/* Remove aspect ratio constraint on mobile for full height usage */
|
|
1561
|
-
aspect-ratio: unset;
|
|
1562
|
-
min-height: 100%;
|
|
1563
|
-
height: 100%;
|
|
1564
|
-
display: flex;
|
|
1565
|
-
align-items: center;
|
|
1566
|
-
justify-content: center;
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
1481
|
.uvf-watermark-layer {
|
|
1571
1482
|
position: absolute;
|
|
1572
1483
|
top: 0;
|
|
@@ -2687,10 +2598,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
2687
2598
|
@media screen and (max-width: 767px) {
|
|
2688
2599
|
html, body {
|
|
2689
2600
|
overflow-x: hidden;
|
|
2690
|
-
/* Prevent iOS Safari address bar bounce */
|
|
2691
|
-
position: fixed;
|
|
2692
|
-
height: 100%;
|
|
2693
|
-
width: 100%;
|
|
2694
2601
|
}
|
|
2695
2602
|
|
|
2696
2603
|
.uvf-player-wrapper {
|
|
@@ -2700,23 +2607,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
2700
2607
|
|
|
2701
2608
|
/* Prevent zoom on double tap */
|
|
2702
2609
|
touch-action: manipulation;
|
|
2703
|
-
|
|
2704
|
-
/* Ensure full viewport usage */
|
|
2705
|
-
position: relative;
|
|
2706
|
-
width: 100vw;
|
|
2707
|
-
height: 100vh;
|
|
2708
|
-
|
|
2709
|
-
/* iOS Safari fix for viewport height */
|
|
2710
|
-
min-height: -webkit-fill-available;
|
|
2711
|
-
}
|
|
2712
|
-
|
|
2713
|
-
.uvf-video-container {
|
|
2714
|
-
/* Full viewport container */
|
|
2715
|
-
width: 100vw;
|
|
2716
|
-
height: 100vh;
|
|
2717
|
-
min-height: -webkit-fill-available;
|
|
2718
|
-
position: relative;
|
|
2719
|
-
overflow: hidden;
|
|
2720
2610
|
}
|
|
2721
2611
|
|
|
2722
2612
|
.uvf-video {
|
|
@@ -2729,38 +2619,12 @@ export class WebPlayer extends BasePlayer {
|
|
|
2729
2619
|
/* Ensure hardware acceleration */
|
|
2730
2620
|
-webkit-transform: translateZ(0);
|
|
2731
2621
|
transform: translateZ(0);
|
|
2732
|
-
|
|
2733
|
-
/* Full viewport video with proper centering */
|
|
2734
|
-
width: 100%;
|
|
2735
|
-
height: 100%;
|
|
2736
|
-
object-fit: contain;
|
|
2737
|
-
object-position: center center;
|
|
2738
2622
|
}
|
|
2739
2623
|
|
|
2740
2624
|
/* Fix for controls being cut off by virtual keyboard */
|
|
2741
2625
|
.uvf-controls-bar {
|
|
2742
2626
|
position: fixed !important;
|
|
2743
2627
|
bottom: var(--uvf-safe-area-bottom, 0) !important;
|
|
2744
|
-
left: var(--uvf-safe-area-left, 0) !important;
|
|
2745
|
-
right: var(--uvf-safe-area-right, 0) !important;
|
|
2746
|
-
width: auto !important;
|
|
2747
|
-
z-index: 9999;
|
|
2748
|
-
}
|
|
2749
|
-
|
|
2750
|
-
/* Top controls safe area positioning */
|
|
2751
|
-
.uvf-top-controls {
|
|
2752
|
-
position: fixed !important;
|
|
2753
|
-
top: var(--uvf-safe-area-top, 10px) !important;
|
|
2754
|
-
right: var(--uvf-safe-area-right, 10px) !important;
|
|
2755
|
-
z-index: 9999;
|
|
2756
|
-
}
|
|
2757
|
-
|
|
2758
|
-
.uvf-title-bar {
|
|
2759
|
-
position: fixed !important;
|
|
2760
|
-
top: var(--uvf-safe-area-top, 10px) !important;
|
|
2761
|
-
left: var(--uvf-safe-area-left, 10px) !important;
|
|
2762
|
-
right: calc(120px + var(--uvf-safe-area-right, 10px)) !important; /* Leave space for top controls */
|
|
2763
|
-
z-index: 9999;
|
|
2764
2628
|
}
|
|
2765
2629
|
|
|
2766
2630
|
/* Ensure controls stay above virtual keyboards */
|
|
@@ -2769,127 +2633,160 @@ export class WebPlayer extends BasePlayer {
|
|
|
2769
2633
|
bottom: max(var(--uvf-safe-area-bottom, 0), env(keyboard-inset-height, 0)) !important;
|
|
2770
2634
|
}
|
|
2771
2635
|
}
|
|
2772
|
-
|
|
2773
|
-
/* Enhanced safe area support for newer devices */
|
|
2774
|
-
@supports (padding: max(0px)) {
|
|
2775
|
-
.uvf-controls-bar {
|
|
2776
|
-
padding-bottom: max(16px, calc(16px + var(--uvf-safe-area-bottom, 0)));
|
|
2777
|
-
padding-left: max(12px, calc(12px + var(--uvf-safe-area-left, 0)));
|
|
2778
|
-
padding-right: max(12px, calc(12px + var(--uvf-safe-area-right, 0)));
|
|
2779
|
-
}
|
|
2780
|
-
|
|
2781
|
-
.uvf-top-controls {
|
|
2782
|
-
top: max(10px, calc(10px + var(--uvf-safe-area-top, 0))) !important;
|
|
2783
|
-
right: max(10px, calc(10px + var(--uvf-safe-area-right, 0))) !important;
|
|
2784
|
-
}
|
|
2785
|
-
|
|
2786
|
-
.uvf-title-bar {
|
|
2787
|
-
top: max(10px, calc(10px + var(--uvf-safe-area-top, 0))) !important;
|
|
2788
|
-
left: max(10px, calc(10px + var(--uvf-safe-area-left, 0))) !important;
|
|
2789
|
-
}
|
|
2790
|
-
}
|
|
2791
2636
|
}
|
|
2792
2637
|
|
|
2793
|
-
/*
|
|
2794
|
-
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
2795
|
-
@supports (top: env(safe-area-inset-top)) {
|
|
2796
|
-
.uvf-responsive-container,
|
|
2797
|
-
.uvf-player-wrapper,
|
|
2798
|
-
.uvf-video-container {
|
|
2799
|
-
height: 100vh;
|
|
2800
|
-
height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
|
|
2805
|
-
/* Landscape orientation fixes for mobile */
|
|
2806
|
-
@media screen and (max-width: 767px) and (orientation: landscape) {
|
|
2807
|
-
html, body {
|
|
2808
|
-
height: 100vh;
|
|
2809
|
-
overflow: hidden;
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
.uvf-responsive-container,
|
|
2813
|
-
.uvf-player-wrapper,
|
|
2814
|
-
.uvf-video-container {
|
|
2815
|
-
height: 100vh;
|
|
2816
|
-
width: 100vw;
|
|
2817
|
-
}
|
|
2818
|
-
|
|
2819
|
-
@supports (height: 100dvh) {
|
|
2820
|
-
.uvf-responsive-container,
|
|
2821
|
-
.uvf-player-wrapper,
|
|
2822
|
-
.uvf-video-container {
|
|
2823
|
-
height: 100dvh;
|
|
2824
|
-
width: 100dvw;
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
}
|
|
2638
|
+
/* Mobile-First Responsive Video Player Layout */
|
|
2828
2639
|
|
|
2829
|
-
/*
|
|
2830
|
-
|
|
2831
|
-
|
|
2640
|
+
/* Mobile devices (all orientations) - Base mobile styles */
|
|
2641
|
+
@media screen and (max-width: 767px) {
|
|
2642
|
+
/* Force full viewport usage with proper safe area handling */
|
|
2832
2643
|
.uvf-responsive-container {
|
|
2833
|
-
|
|
2644
|
+
position: fixed !important;
|
|
2645
|
+
top: 0;
|
|
2646
|
+
left: 0;
|
|
2834
2647
|
width: 100vw !important;
|
|
2835
|
-
height:
|
|
2648
|
+
height: 100vh !important;
|
|
2649
|
+
height: calc(100vh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
|
|
2836
2650
|
margin: 0;
|
|
2837
|
-
|
|
2651
|
+
padding: 0;
|
|
2838
2652
|
overflow: hidden;
|
|
2653
|
+
z-index: 1000;
|
|
2839
2654
|
}
|
|
2840
2655
|
|
|
2656
|
+
/* Modern viewport support */
|
|
2841
2657
|
@supports (height: 100dvh) {
|
|
2842
2658
|
.uvf-responsive-container {
|
|
2843
|
-
height:
|
|
2659
|
+
height: 100dvh !important;
|
|
2660
|
+
height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
|
|
2844
2661
|
}
|
|
2845
2662
|
}
|
|
2846
2663
|
|
|
2664
|
+
/* Player wrapper fills container completely */
|
|
2847
2665
|
.uvf-responsive-container .uvf-player-wrapper {
|
|
2848
|
-
|
|
2666
|
+
position: absolute;
|
|
2667
|
+
top: 0;
|
|
2668
|
+
left: 0;
|
|
2669
|
+
width: 100% !important;
|
|
2849
2670
|
height: 100% !important;
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
.uvf-responsive-container .uvf-player-wrapper {
|
|
2855
|
-
min-height: calc(100dvh - var(--uvf-safe-area-top) - var(--uvf-safe-area-bottom));
|
|
2856
|
-
}
|
|
2671
|
+
max-width: none;
|
|
2672
|
+
max-height: none;
|
|
2673
|
+
display: flex;
|
|
2674
|
+
flex-direction: column;
|
|
2857
2675
|
}
|
|
2858
2676
|
|
|
2677
|
+
/* Video container optimized for mobile centering */
|
|
2859
2678
|
.uvf-responsive-container .uvf-video-container {
|
|
2860
|
-
|
|
2679
|
+
position: relative;
|
|
2680
|
+
width: 100% !important;
|
|
2861
2681
|
height: 100% !important;
|
|
2682
|
+
flex: 1;
|
|
2862
2683
|
aspect-ratio: unset !important;
|
|
2863
|
-
|
|
2684
|
+
display: flex;
|
|
2685
|
+
align-items: center;
|
|
2686
|
+
justify-content: center;
|
|
2687
|
+
background: #000;
|
|
2688
|
+
overflow: hidden;
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
/* Perfectly centered mobile video */
|
|
2692
|
+
.uvf-responsive-container .uvf-video {
|
|
2693
|
+
position: relative;
|
|
2694
|
+
display: block;
|
|
2695
|
+
width: 100%;
|
|
2696
|
+
height: 100%;
|
|
2697
|
+
max-width: 100%;
|
|
2698
|
+
max-height: 100%;
|
|
2699
|
+
object-fit: contain;
|
|
2700
|
+
object-position: center center;
|
|
2701
|
+
background: transparent;
|
|
2864
2702
|
}
|
|
2865
2703
|
|
|
2866
|
-
/*
|
|
2704
|
+
/* Mobile controls positioned with safe areas */
|
|
2867
2705
|
.uvf-controls-bar {
|
|
2868
|
-
position: absolute;
|
|
2869
|
-
bottom:
|
|
2870
|
-
left:
|
|
2871
|
-
right:
|
|
2872
|
-
|
|
2873
|
-
padding
|
|
2874
|
-
padding-
|
|
2875
|
-
padding-
|
|
2876
|
-
|
|
2706
|
+
position: absolute !important;
|
|
2707
|
+
bottom: env(safe-area-inset-bottom, 0px);
|
|
2708
|
+
left: env(safe-area-inset-left, 0px);
|
|
2709
|
+
right: env(safe-area-inset-right, 0px);
|
|
2710
|
+
width: auto;
|
|
2711
|
+
padding: 16px;
|
|
2712
|
+
padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
|
|
2713
|
+
padding-left: calc(16px + env(safe-area-inset-left, 0px));
|
|
2714
|
+
padding-right: calc(16px + env(safe-area-inset-right, 0px));
|
|
2715
|
+
background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.6) 70%, transparent 100%);
|
|
2716
|
+
backdrop-filter: blur(10px);
|
|
2717
|
+
-webkit-backdrop-filter: blur(10px);
|
|
2877
2718
|
box-sizing: border-box;
|
|
2878
|
-
z-index:
|
|
2719
|
+
z-index: 2000;
|
|
2720
|
+
opacity: 1;
|
|
2721
|
+
transform: none;
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
/* Top controls with safe area */
|
|
2725
|
+
.uvf-top-controls {
|
|
2726
|
+
position: absolute !important;
|
|
2727
|
+
top: calc(16px + env(safe-area-inset-top, 0px));
|
|
2728
|
+
right: calc(16px + env(safe-area-inset-right, 0px));
|
|
2729
|
+
z-index: 2000;
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
/* Title bar with safe area */
|
|
2733
|
+
.uvf-title-bar {
|
|
2734
|
+
position: absolute !important;
|
|
2735
|
+
top: calc(16px + env(safe-area-inset-top, 0px));
|
|
2736
|
+
left: calc(16px + env(safe-area-inset-left, 0px));
|
|
2737
|
+
right: calc(120px + env(safe-area-inset-right, 0px));
|
|
2738
|
+
z-index: 2000;
|
|
2879
2739
|
}
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
/* Mobile Portrait - Optimized vertical layout */
|
|
2743
|
+
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
2880
2744
|
|
|
2881
2745
|
.uvf-progress-section {
|
|
2882
2746
|
margin-bottom: 16px;
|
|
2883
2747
|
}
|
|
2884
2748
|
|
|
2885
|
-
/* Mobile-
|
|
2749
|
+
/* Mobile-optimized controls layout */
|
|
2886
2750
|
.uvf-controls-row {
|
|
2887
|
-
|
|
2888
|
-
flex-wrap: nowrap;
|
|
2751
|
+
display: flex;
|
|
2889
2752
|
align-items: center;
|
|
2890
2753
|
justify-content: space-between;
|
|
2891
|
-
position: relative;
|
|
2892
2754
|
width: 100%;
|
|
2755
|
+
gap: 12px;
|
|
2756
|
+
flex-wrap: nowrap;
|
|
2757
|
+
position: relative;
|
|
2758
|
+
min-height: 52px;
|
|
2759
|
+
}
|
|
2760
|
+
|
|
2761
|
+
/* Ensure controls are always visible */
|
|
2762
|
+
.uvf-controls-row > * {
|
|
2763
|
+
flex-shrink: 0;
|
|
2764
|
+
display: flex;
|
|
2765
|
+
align-items: center;
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
/* Control groups with proper flex behavior */
|
|
2769
|
+
.uvf-left-controls {
|
|
2770
|
+
display: flex;
|
|
2771
|
+
align-items: center;
|
|
2772
|
+
gap: 8px;
|
|
2773
|
+
flex: 0 0 auto;
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
.uvf-center-controls {
|
|
2777
|
+
display: flex;
|
|
2778
|
+
align-items: center;
|
|
2779
|
+
gap: 8px;
|
|
2780
|
+
flex: 1 1 auto;
|
|
2781
|
+
justify-content: center;
|
|
2782
|
+
min-width: 0;
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
.uvf-right-controls {
|
|
2786
|
+
display: flex !important;
|
|
2787
|
+
align-items: center;
|
|
2788
|
+
gap: 8px;
|
|
2789
|
+
flex: 0 0 auto;
|
|
2893
2790
|
}
|
|
2894
2791
|
|
|
2895
2792
|
/* Left side controls group */
|
|
@@ -3017,26 +2914,68 @@ export class WebPlayer extends BasePlayer {
|
|
|
3017
2914
|
display: none !important;
|
|
3018
2915
|
}
|
|
3019
2916
|
|
|
3020
|
-
/*
|
|
2917
|
+
/* Enhanced mobile settings menu */
|
|
3021
2918
|
.uvf-settings-menu {
|
|
3022
|
-
|
|
3023
|
-
bottom:
|
|
3024
|
-
right:
|
|
2919
|
+
position: fixed !important;
|
|
2920
|
+
bottom: calc(80px + env(safe-area-inset-bottom, 0px));
|
|
2921
|
+
right: calc(16px + env(safe-area-inset-right, 0px));
|
|
2922
|
+
min-width: 200px;
|
|
2923
|
+
max-width: 280px;
|
|
2924
|
+
max-height: 60vh;
|
|
2925
|
+
background: rgba(0,0,0,0.95);
|
|
2926
|
+
backdrop-filter: blur(20px);
|
|
2927
|
+
-webkit-backdrop-filter: blur(20px);
|
|
2928
|
+
border: 1px solid rgba(255,255,255,0.2);
|
|
2929
|
+
border-radius: 12px;
|
|
2930
|
+
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
|
|
2931
|
+
z-index: 3000;
|
|
2932
|
+
overflow: hidden;
|
|
3025
2933
|
font-size: 14px;
|
|
3026
|
-
|
|
2934
|
+
opacity: 0;
|
|
2935
|
+
transform: translateY(10px) scale(0.95);
|
|
2936
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2937
|
+
pointer-events: none;
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
.uvf-settings-menu.active {
|
|
2941
|
+
opacity: 1;
|
|
2942
|
+
transform: translateY(0) scale(1);
|
|
2943
|
+
pointer-events: auto;
|
|
3027
2944
|
}
|
|
3028
2945
|
|
|
2946
|
+
/* Touch-optimized settings options */
|
|
3029
2947
|
.uvf-settings-option {
|
|
3030
|
-
padding:
|
|
3031
|
-
font-size:
|
|
3032
|
-
min-height:
|
|
2948
|
+
padding: 16px 20px;
|
|
2949
|
+
font-size: 16px;
|
|
2950
|
+
min-height: 56px;
|
|
3033
2951
|
display: flex;
|
|
3034
2952
|
align-items: center;
|
|
2953
|
+
cursor: pointer;
|
|
2954
|
+
transition: all 0.2s ease;
|
|
2955
|
+
border: none;
|
|
2956
|
+
background: transparent;
|
|
2957
|
+
color: #fff;
|
|
2958
|
+
width: 100%;
|
|
2959
|
+
text-align: left;
|
|
3035
2960
|
}
|
|
3036
2961
|
|
|
3037
|
-
.uvf-settings-option:hover
|
|
2962
|
+
.uvf-settings-option:hover,
|
|
2963
|
+
.uvf-settings-option:focus {
|
|
3038
2964
|
background: rgba(255,255,255,0.15);
|
|
3039
|
-
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
.uvf-settings-option.active {
|
|
2968
|
+
background: rgba(255,77,79,0.2);
|
|
2969
|
+
color: #ff4d4f;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
/* Settings groups with proper spacing */
|
|
2973
|
+
.uvf-settings-group {
|
|
2974
|
+
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
.uvf-settings-group:last-child {
|
|
2978
|
+
border-bottom: none;
|
|
3040
2979
|
}
|
|
3041
2980
|
|
|
3042
2981
|
/* Simplified settings - hide complex options */
|
|
@@ -3177,11 +3116,46 @@ export class WebPlayer extends BasePlayer {
|
|
|
3177
3116
|
display: block;
|
|
3178
3117
|
}
|
|
3179
3118
|
|
|
3119
|
+
/* Ensure settings button is always visible and functional */
|
|
3120
|
+
#uvf-settings-btn {
|
|
3121
|
+
display: flex !important;
|
|
3122
|
+
align-items: center;
|
|
3123
|
+
justify-content: center;
|
|
3124
|
+
width: 44px;
|
|
3125
|
+
height: 44px;
|
|
3126
|
+
min-width: 44px;
|
|
3127
|
+
min-height: 44px;
|
|
3128
|
+
background: rgba(255,255,255,0.15);
|
|
3129
|
+
backdrop-filter: blur(8px);
|
|
3130
|
+
border: 1px solid rgba(255,255,255,0.2);
|
|
3131
|
+
border-radius: 22px;
|
|
3132
|
+
transition: all 0.2s ease;
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
#uvf-settings-btn:hover {
|
|
3136
|
+
background: rgba(255,255,255,0.25);
|
|
3137
|
+
transform: scale(1.05);
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
#uvf-settings-btn svg {
|
|
3141
|
+
width: 20px;
|
|
3142
|
+
height: 20px;
|
|
3143
|
+
fill: #fff;
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3180
3146
|
/* Essential controls in right section - Settings, PiP, and Fullscreen only */
|
|
3181
3147
|
.uvf-right-controls > *:not(#uvf-settings-btn):not(#uvf-fullscreen-btn):not(#uvf-pip-btn) {
|
|
3182
3148
|
display: none;
|
|
3183
3149
|
}
|
|
3184
3150
|
|
|
3151
|
+
/* Make sure right controls are properly spaced */
|
|
3152
|
+
.uvf-right-controls {
|
|
3153
|
+
display: flex;
|
|
3154
|
+
align-items: center;
|
|
3155
|
+
gap: 8px;
|
|
3156
|
+
flex-shrink: 0;
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3185
3159
|
/* Hide skip buttons on small mobile devices to save space */
|
|
3186
3160
|
@media screen and (max-width: 480px) {
|
|
3187
3161
|
#uvf-skip-back,
|
|
@@ -4136,13 +4110,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
4136
4110
|
pipBtn.id = 'uvf-pip-btn';
|
|
4137
4111
|
pipBtn.title = 'Picture-in-Picture';
|
|
4138
4112
|
pipBtn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M19 7h-8v6h8V7zm2-4H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H3V5h18v14z"/></svg>';
|
|
4139
|
-
|
|
4140
|
-
rightControls.appendChild(pipBtn);
|
|
4141
|
-
this.debugLog('PiP button added - support detected');
|
|
4142
|
-
}
|
|
4143
|
-
else {
|
|
4144
|
-
this.debugLog('PiP button not added - no support detected');
|
|
4145
|
-
}
|
|
4113
|
+
rightControls.appendChild(pipBtn);
|
|
4146
4114
|
const fullscreenBtn = document.createElement('button');
|
|
4147
4115
|
fullscreenBtn.className = 'uvf-control-btn';
|
|
4148
4116
|
fullscreenBtn.id = 'uvf-fullscreen-btn';
|
|
@@ -5255,41 +5223,17 @@ export class WebPlayer extends BasePlayer {
|
|
|
5255
5223
|
this.setAutoQuality(true);
|
|
5256
5224
|
}
|
|
5257
5225
|
}
|
|
5258
|
-
isPictureInPictureActive() {
|
|
5259
|
-
const inStandardPiP = !!document.pictureInPictureElement;
|
|
5260
|
-
const inWebkitPiP = !!(this.video &&
|
|
5261
|
-
'webkitPresentationMode' in this.video &&
|
|
5262
|
-
this.video.webkitPresentationMode === 'picture-in-picture');
|
|
5263
|
-
return inStandardPiP || inWebkitPiP;
|
|
5264
|
-
}
|
|
5265
5226
|
async togglePiP() {
|
|
5266
|
-
if (!this.isPictureInPictureSupported()) {
|
|
5267
|
-
this.showShortcutIndicator('PiP not supported');
|
|
5268
|
-
this.debugWarn('PiP not supported on this device/browser');
|
|
5269
|
-
return;
|
|
5270
|
-
}
|
|
5271
5227
|
try {
|
|
5272
|
-
if (
|
|
5228
|
+
if (document.pictureInPictureElement) {
|
|
5273
5229
|
await this.exitPictureInPicture();
|
|
5274
|
-
this.showShortcutIndicator('Exit PiP');
|
|
5275
|
-
this.debugLog('PiP deactivated');
|
|
5276
5230
|
}
|
|
5277
5231
|
else {
|
|
5278
5232
|
await this.enterPictureInPicture();
|
|
5279
|
-
this.showShortcutIndicator('Enter PiP');
|
|
5280
|
-
this.debugLog('PiP activated');
|
|
5281
5233
|
}
|
|
5282
5234
|
}
|
|
5283
5235
|
catch (error) {
|
|
5284
|
-
|
|
5285
|
-
this.showShortcutIndicator(`PiP Error: ${errorMessage}`);
|
|
5286
|
-
this.debugError('PiP toggle failed:', errorMessage);
|
|
5287
|
-
if (errorMessage.includes('not supported')) {
|
|
5288
|
-
this.showShortcutIndicator('PiP not supported');
|
|
5289
|
-
}
|
|
5290
|
-
else if (errorMessage.includes('user gesture')) {
|
|
5291
|
-
this.showShortcutIndicator('PiP requires user interaction');
|
|
5292
|
-
}
|
|
5236
|
+
console.error('PiP toggle failed:', error);
|
|
5293
5237
|
}
|
|
5294
5238
|
}
|
|
5295
5239
|
setupCastContextSafe() {
|