unified-video-framework 1.4.166 → 1.4.168
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.
|
@@ -21,7 +21,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
21
21
|
this.currentSubtitle = 'off';
|
|
22
22
|
this.currentPlaybackRate = 1;
|
|
23
23
|
this.isDragging = false;
|
|
24
|
-
this.isSettingsOpen = false;
|
|
25
24
|
this.settingsConfig = {
|
|
26
25
|
enabled: true,
|
|
27
26
|
speed: true,
|
|
@@ -53,16 +52,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
53
52
|
this.hasTriedButtonFallback = false;
|
|
54
53
|
this.lastUserInteraction = 0;
|
|
55
54
|
this.showTimeTooltip = false;
|
|
56
|
-
this.lastTapTime = 0;
|
|
57
|
-
this.tapCount = 0;
|
|
58
|
-
this.tapTimeout = null;
|
|
59
|
-
this.longPressTimer = null;
|
|
60
|
-
this.longPressActive = false;
|
|
61
|
-
this.longPressStartTime = 0;
|
|
62
|
-
this.originalPlaybackRate = 1;
|
|
63
|
-
this.dominantColor = '#ff0000';
|
|
64
|
-
this.accentColor = '#ff4d4f';
|
|
65
|
-
this.surfaceTint = 'rgba(255, 0, 0, 0.08)';
|
|
66
55
|
this.autoplayCapabilities = {
|
|
67
56
|
canAutoplay: false,
|
|
68
57
|
canAutoplayMuted: false,
|
|
@@ -240,26 +229,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
240
229
|
catch (_) { }
|
|
241
230
|
this.setupCastContextSafe();
|
|
242
231
|
this.updateMetadataUI();
|
|
243
|
-
this.enableMaterialYouMobileIfNeeded();
|
|
244
|
-
}
|
|
245
|
-
enableMaterialYouMobileIfNeeded() {
|
|
246
|
-
const isMobile = this.isMobileDevice();
|
|
247
|
-
const isPortrait = window.innerHeight > window.innerWidth;
|
|
248
|
-
if (isMobile && isPortrait && this.playerWrapper) {
|
|
249
|
-
this.debugLog('Enabling Material You mobile layout');
|
|
250
|
-
this.playerWrapper.classList.add('uvf-material-you-mobile');
|
|
251
|
-
window.addEventListener('resize', () => {
|
|
252
|
-
const isNowPortrait = window.innerHeight > window.innerWidth;
|
|
253
|
-
if (this.playerWrapper) {
|
|
254
|
-
if (isMobile && isNowPortrait) {
|
|
255
|
-
this.playerWrapper.classList.add('uvf-material-you-mobile');
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
this.playerWrapper.classList.remove('uvf-material-you-mobile');
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
232
|
}
|
|
264
233
|
setupVideoEventListeners() {
|
|
265
234
|
if (!this.video)
|
|
@@ -337,7 +306,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
337
306
|
this.state.duration = this.video.duration || 0;
|
|
338
307
|
this.debugLog('Metadata loaded - duration:', this.video.duration);
|
|
339
308
|
this.updateTimeDisplay();
|
|
340
|
-
this.renderChapterMarkersOnProgressBar();
|
|
341
309
|
this.emit('onLoadedMetadata', {
|
|
342
310
|
duration: this.video.duration || 0,
|
|
343
311
|
width: this.video.videoWidth || 0,
|
|
@@ -1907,8 +1875,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
1907
1875
|
--uvf-scrollbar-thumb-hover-start: rgba(255,0,0,0.5);
|
|
1908
1876
|
--uvf-scrollbar-thumb-hover-end: rgba(255,0,0,0.6);
|
|
1909
1877
|
--uvf-firefox-scrollbar-color: rgba(255,255,255,0.25);
|
|
1910
|
-
/* Material You surface tint */
|
|
1911
|
-
--uvf-surface-tint: rgba(255, 0, 0, 0.08);
|
|
1912
1878
|
}
|
|
1913
1879
|
|
|
1914
1880
|
/* Player focus styles for better UX */
|
|
@@ -3817,162 +3783,35 @@ export class WebPlayer extends BasePlayer {
|
|
|
3817
3783
|
}
|
|
3818
3784
|
}
|
|
3819
3785
|
|
|
3820
|
-
/* iOS Safari specific fixes -
|
|
3786
|
+
/* iOS Safari specific fixes - fullscreen only */
|
|
3821
3787
|
@supports (-webkit-appearance: none) {
|
|
3822
3788
|
.uvf-player-wrapper.uvf-fullscreen,
|
|
3823
3789
|
.uvf-video-container.uvf-fullscreen {
|
|
3824
3790
|
height: -webkit-fill-available;
|
|
3825
3791
|
min-height: -webkit-fill-available;
|
|
3826
3792
|
}
|
|
3827
|
-
|
|
3828
|
-
/* Handle iOS Safari's dynamic address bar */
|
|
3829
|
-
@media screen and (max-width: 767px) {
|
|
3830
|
-
.uvf-responsive-container {
|
|
3831
|
-
height: -webkit-fill-available;
|
|
3832
|
-
min-height: 100vh;
|
|
3833
|
-
}
|
|
3834
|
-
|
|
3835
|
-
.uvf-player-wrapper {
|
|
3836
|
-
height: -webkit-fill-available;
|
|
3837
|
-
min-height: 100vh;
|
|
3838
|
-
/* Fix for iOS Safari control overlay positioning */
|
|
3839
|
-
position: relative;
|
|
3840
|
-
overflow: hidden;
|
|
3841
|
-
}
|
|
3842
|
-
|
|
3843
|
-
/* iOS Safari specific fixes for control positioning */
|
|
3844
|
-
.uvf-controls-bar {
|
|
3845
|
-
position: absolute !important;
|
|
3846
|
-
bottom: 0 !important;
|
|
3847
|
-
left: 0 !important;
|
|
3848
|
-
right: 0 !important;
|
|
3849
|
-
/* Ensure hardware acceleration */
|
|
3850
|
-
-webkit-transform: translate3d(0,0,0);
|
|
3851
|
-
transform: translate3d(0,0,0);
|
|
3852
|
-
/* Prevent any webkit transforms that could cause positioning issues */
|
|
3853
|
-
-webkit-perspective: 1000;
|
|
3854
|
-
perspective: 1000;
|
|
3855
|
-
}
|
|
3856
|
-
|
|
3857
|
-
/* Ensure all control elements use hardware acceleration */
|
|
3858
|
-
.uvf-control-btn,
|
|
3859
|
-
.uvf-progress-bar,
|
|
3860
|
-
.uvf-progress-section {
|
|
3861
|
-
-webkit-transform: translateZ(0);
|
|
3862
|
-
transform: translateZ(0);
|
|
3863
|
-
}
|
|
3864
|
-
}
|
|
3865
3793
|
}
|
|
3866
3794
|
|
|
3867
|
-
/* Android Chrome specific fixes */
|
|
3868
|
-
@supports (display: -webkit-box) {
|
|
3869
|
-
.uvf-responsive-container {
|
|
3870
|
-
min-height: 100vh;
|
|
3871
|
-
}
|
|
3872
|
-
|
|
3873
|
-
/* Fix for Android Chrome's address bar behavior */
|
|
3874
|
-
@media screen and (max-width: 767px) {
|
|
3875
|
-
.uvf-video-container {
|
|
3876
|
-
min-height: calc(100vh - 56px); /* Chrome mobile address bar height */
|
|
3877
|
-
}
|
|
3878
|
-
}
|
|
3879
|
-
}
|
|
3880
|
-
|
|
3881
|
-
/* Samsung Internet Browser fixes */
|
|
3882
|
-
@media screen and (-webkit-min-device-pixel-ratio: 1) {
|
|
3883
|
-
@media screen and (max-width: 767px) {
|
|
3884
|
-
.uvf-responsive-container {
|
|
3885
|
-
position: fixed;
|
|
3886
|
-
top: 0;
|
|
3887
|
-
left: 0;
|
|
3888
|
-
width: 100vw;
|
|
3889
|
-
height: 100vh;
|
|
3890
|
-
}
|
|
3891
|
-
}
|
|
3892
|
-
}
|
|
3893
3795
|
|
|
3894
|
-
/*
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3796
|
+
/* Enhanced Responsive Media Queries with UX Best Practices */
|
|
3797
|
+
/* Mobile devices (portrait) - Material You Design (25-50-25 Layout) */
|
|
3798
|
+
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
3799
|
+
.uvf-responsive-container {
|
|
3800
|
+
padding: 0;
|
|
3801
|
+
width: 100vw !important;
|
|
3802
|
+
height: 100vh;
|
|
3803
|
+
height: 100dvh;
|
|
3804
|
+
margin: 0;
|
|
3805
|
+
position: fixed;
|
|
3806
|
+
top: 0;
|
|
3807
|
+
left: 0;
|
|
3903
3808
|
overflow: hidden;
|
|
3904
|
-
|
|
3905
|
-
/* Prevent zoom on double tap */
|
|
3906
|
-
touch-action: manipulation;
|
|
3907
|
-
}
|
|
3908
|
-
|
|
3909
|
-
.uvf-video {
|
|
3910
|
-
/* Prevent video from being selectable */
|
|
3911
|
-
-webkit-user-select: none;
|
|
3912
|
-
-moz-user-select: none;
|
|
3913
|
-
-ms-user-select: none;
|
|
3914
|
-
user-select: none;
|
|
3915
|
-
|
|
3916
|
-
/* Ensure hardware acceleration */
|
|
3917
|
-
-webkit-transform: translateZ(0);
|
|
3918
|
-
transform: translateZ(0);
|
|
3919
|
-
}
|
|
3920
|
-
|
|
3921
|
-
/* Fix for controls being cut off by virtual keyboard */
|
|
3922
|
-
.uvf-controls-bar {
|
|
3923
|
-
position: absolute !important;
|
|
3924
|
-
bottom: 0 !important;
|
|
3925
|
-
left: 0 !important;
|
|
3926
|
-
right: 0 !important;
|
|
3927
|
-
/* Remove fixed positioning that causes issues on iOS Safari */
|
|
3928
|
-
z-index: 1000 !important;
|
|
3929
|
-
transform: translateZ(0); /* Force hardware acceleration */
|
|
3930
|
-
}
|
|
3931
|
-
|
|
3932
|
-
/* Ensure controls stay above virtual keyboards */
|
|
3933
|
-
@supports (bottom: env(keyboard-inset-height)) {
|
|
3934
|
-
.uvf-controls-bar {
|
|
3935
|
-
bottom: max(0px, env(keyboard-inset-height, 0)) !important;
|
|
3936
|
-
padding-bottom: calc(16px + max(var(--uvf-safe-area-bottom, 0), env(keyboard-inset-height, 0))) !important;
|
|
3937
|
-
}
|
|
3938
3809
|
}
|
|
3939
3810
|
|
|
3940
|
-
|
|
3941
|
-
#uvf-pip-btn {
|
|
3942
|
-
display: none !important;
|
|
3943
|
-
}
|
|
3944
|
-
|
|
3945
|
-
/* Mobile fullscreen enhancements */
|
|
3946
|
-
.uvf-player-wrapper.uvf-fullscreen {
|
|
3947
|
-
/* Ensure fullscreen covers entire viewport on mobile */
|
|
3948
|
-
position: fixed !important;
|
|
3949
|
-
top: 0 !important;
|
|
3950
|
-
left: 0 !important;
|
|
3811
|
+
.uvf-responsive-container .uvf-player-wrapper {
|
|
3951
3812
|
width: 100vw !important;
|
|
3952
|
-
height: 100vh !important;
|
|
3953
|
-
z-index: 2147483647 !important;
|
|
3954
|
-
background: #000 !important;
|
|
3955
|
-
}
|
|
3956
|
-
|
|
3957
|
-
/* iOS Safari specific fullscreen fixes */
|
|
3958
|
-
@supports (-webkit-appearance: none) {
|
|
3959
|
-
.uvf-player-wrapper.uvf-fullscreen {
|
|
3960
|
-
/* Use viewport units that work better with iOS Safari */
|
|
3961
|
-
height: -webkit-fill-available !important;
|
|
3962
|
-
}
|
|
3963
|
-
}
|
|
3964
|
-
}
|
|
3965
|
-
|
|
3966
|
-
/* Enhanced Responsive Media Queries with UX Best Practices */
|
|
3967
|
-
|
|
3968
|
-
/* Material You Mobile Portrait Layout - 25% Black + 50% Video + 25% Black */
|
|
3969
|
-
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
3970
|
-
/* Enable Material You mode with class flag */
|
|
3971
|
-
.uvf-player-wrapper.uvf-material-you-mobile {
|
|
3972
|
-
/* Full viewport height layout */
|
|
3973
3813
|
height: 100vh;
|
|
3974
3814
|
height: 100dvh;
|
|
3975
|
-
width: 100vw;
|
|
3976
3815
|
position: fixed;
|
|
3977
3816
|
top: 0;
|
|
3978
3817
|
left: 0;
|
|
@@ -3982,8 +3821,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
3982
3821
|
overflow: hidden;
|
|
3983
3822
|
}
|
|
3984
3823
|
|
|
3985
|
-
|
|
3986
|
-
|
|
3824
|
+
/* Video container occupies middle 50% */
|
|
3825
|
+
.uvf-responsive-container .uvf-video-container {
|
|
3987
3826
|
height: 50vh;
|
|
3988
3827
|
height: 50dvh;
|
|
3989
3828
|
width: 100vw;
|
|
@@ -3991,22 +3830,20 @@ export class WebPlayer extends BasePlayer {
|
|
|
3991
3830
|
margin-top: 25vh;
|
|
3992
3831
|
margin-top: 25dvh;
|
|
3993
3832
|
aspect-ratio: unset !important;
|
|
3994
|
-
/* Match existing theme background */
|
|
3995
3833
|
background: radial-gradient(ellipse at center, #1a1a2e 0%, #000 100%);
|
|
3996
|
-
/* Material Design elevation */
|
|
3997
3834
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4),
|
|
3998
3835
|
0 4px 16px rgba(0, 0, 0, 0.3),
|
|
3999
3836
|
0 2px 8px rgba(0, 0, 0, 0.2);
|
|
4000
3837
|
}
|
|
4001
3838
|
|
|
4002
|
-
.uvf-
|
|
3839
|
+
.uvf-video {
|
|
4003
3840
|
width: 100%;
|
|
4004
3841
|
height: 100%;
|
|
4005
3842
|
object-fit: contain;
|
|
4006
3843
|
}
|
|
4007
3844
|
|
|
4008
|
-
/* Top black section (25%) - Tap zone
|
|
4009
|
-
.uvf-player-wrapper
|
|
3845
|
+
/* Top black section (25%) - Tap zone */
|
|
3846
|
+
.uvf-player-wrapper::before {
|
|
4010
3847
|
content: '';
|
|
4011
3848
|
position: absolute;
|
|
4012
3849
|
top: 0;
|
|
@@ -4020,8 +3857,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
4020
3857
|
touch-action: manipulation;
|
|
4021
3858
|
}
|
|
4022
3859
|
|
|
4023
|
-
/* Bottom black section (25%) -
|
|
4024
|
-
.uvf-player-wrapper
|
|
3860
|
+
/* Bottom black section (25%) - Controls area */
|
|
3861
|
+
.uvf-player-wrapper::after {
|
|
4025
3862
|
content: '';
|
|
4026
3863
|
position: absolute;
|
|
4027
3864
|
bottom: 0;
|
|
@@ -4038,7 +3875,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
4038
3875
|
}
|
|
4039
3876
|
|
|
4040
3877
|
/* Material surface container for controls */
|
|
4041
|
-
.uvf-
|
|
3878
|
+
.uvf-controls-bar {
|
|
4042
3879
|
position: absolute;
|
|
4043
3880
|
bottom: 0;
|
|
4044
3881
|
left: 0;
|
|
@@ -4053,13 +3890,12 @@ export class WebPlayer extends BasePlayer {
|
|
|
4053
3890
|
display: flex;
|
|
4054
3891
|
flex-direction: column;
|
|
4055
3892
|
justify-content: flex-end;
|
|
4056
|
-
/* Material Design surface with tint */
|
|
4057
3893
|
backdrop-filter: blur(24px);
|
|
4058
3894
|
-webkit-backdrop-filter: blur(24px);
|
|
4059
3895
|
}
|
|
4060
3896
|
|
|
4061
3897
|
/* Material surface tint overlay */
|
|
4062
|
-
.uvf-
|
|
3898
|
+
.uvf-controls-bar::before {
|
|
4063
3899
|
content: '';
|
|
4064
3900
|
position: absolute;
|
|
4065
3901
|
inset: 0;
|
|
@@ -4070,87 +3906,53 @@ export class WebPlayer extends BasePlayer {
|
|
|
4070
3906
|
}
|
|
4071
3907
|
|
|
4072
3908
|
/* Progress bar with chapter markers */
|
|
4073
|
-
.uvf-
|
|
3909
|
+
.uvf-progress-section {
|
|
4074
3910
|
margin-bottom: 12px;
|
|
4075
3911
|
position: relative;
|
|
4076
3912
|
}
|
|
4077
3913
|
|
|
4078
|
-
.uvf-
|
|
3914
|
+
.uvf-progress-bar-wrapper {
|
|
4079
3915
|
padding: 12px 0;
|
|
4080
3916
|
position: relative;
|
|
4081
3917
|
}
|
|
4082
3918
|
|
|
4083
|
-
.uvf-
|
|
3919
|
+
.uvf-progress-bar {
|
|
4084
3920
|
height: 4px;
|
|
4085
3921
|
background: rgba(255, 255, 255, 0.2);
|
|
4086
3922
|
border-radius: 4px;
|
|
4087
3923
|
position: relative;
|
|
4088
3924
|
overflow: visible;
|
|
4089
|
-
/* Material elevation */
|
|
4090
3925
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
4091
3926
|
}
|
|
4092
3927
|
|
|
4093
|
-
.uvf-
|
|
3928
|
+
.uvf-progress-filled {
|
|
4094
3929
|
background: var(--uvf-accent-1, #ff0000);
|
|
4095
3930
|
box-shadow: 0 0 8px var(--uvf-accent-1, #ff0000);
|
|
4096
3931
|
}
|
|
4097
3932
|
|
|
4098
|
-
.uvf-
|
|
3933
|
+
.uvf-progress-handle {
|
|
4099
3934
|
width: 20px;
|
|
4100
3935
|
height: 20px;
|
|
4101
3936
|
background: var(--uvf-accent-1, #ff0000);
|
|
4102
|
-
/* Material Design state layer */
|
|
4103
3937
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3),
|
|
4104
3938
|
0 0 0 0 var(--uvf-accent-1, #ff0000);
|
|
4105
3939
|
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
4106
3940
|
}
|
|
4107
3941
|
|
|
4108
|
-
.uvf-
|
|
3942
|
+
.uvf-progress-handle:active {
|
|
4109
3943
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4),
|
|
4110
3944
|
0 0 0 12px rgba(255, 0, 0, 0.15);
|
|
4111
3945
|
transform: translate(-50%, -50%) scale(1.2);
|
|
4112
3946
|
}
|
|
4113
3947
|
|
|
4114
|
-
/* Chapter markers on progress bar */
|
|
4115
|
-
.uvf-chapter-marker {
|
|
4116
|
-
position: absolute;
|
|
4117
|
-
top: 0;
|
|
4118
|
-
height: 100%;
|
|
4119
|
-
width: 3px;
|
|
4120
|
-
background: rgba(255, 255, 255, 0.4);
|
|
4121
|
-
border-radius: 2px;
|
|
4122
|
-
transform: translateX(-50%);
|
|
4123
|
-
pointer-events: none;
|
|
4124
|
-
z-index: 1;
|
|
4125
|
-
transition: all 0.2s ease;
|
|
4126
|
-
}
|
|
4127
|
-
|
|
4128
|
-
.uvf-chapter-marker.intro {
|
|
4129
|
-
background: #4CAF50;
|
|
4130
|
-
}
|
|
4131
|
-
|
|
4132
|
-
.uvf-chapter-marker.recap {
|
|
4133
|
-
background: #FFC107;
|
|
4134
|
-
}
|
|
4135
|
-
|
|
4136
|
-
.uvf-chapter-marker.credits {
|
|
4137
|
-
background: #9C27B0;
|
|
4138
|
-
}
|
|
4139
|
-
|
|
4140
|
-
.uvf-progress-bar-wrapper:hover .uvf-chapter-marker {
|
|
4141
|
-
width: 4px;
|
|
4142
|
-
opacity: 1;
|
|
4143
|
-
}
|
|
4144
|
-
|
|
4145
3948
|
/* Material Design control buttons */
|
|
4146
|
-
.uvf-
|
|
3949
|
+
.uvf-control-btn {
|
|
4147
3950
|
width: 48px;
|
|
4148
3951
|
height: 48px;
|
|
4149
3952
|
min-width: 48px;
|
|
4150
3953
|
min-height: 48px;
|
|
4151
3954
|
background: rgba(255, 255, 255, 0.12);
|
|
4152
3955
|
border-radius: 24px;
|
|
4153
|
-
/* Material elevation level 1 */
|
|
4154
3956
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12),
|
|
4155
3957
|
0 1px 2px rgba(0, 0, 0, 0.24);
|
|
4156
3958
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
@@ -4159,7 +3961,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
4159
3961
|
}
|
|
4160
3962
|
|
|
4161
3963
|
/* Material ripple effect */
|
|
4162
|
-
.uvf-
|
|
3964
|
+
.uvf-control-btn::before {
|
|
4163
3965
|
content: '';
|
|
4164
3966
|
position: absolute;
|
|
4165
3967
|
inset: 0;
|
|
@@ -4169,24 +3971,22 @@ export class WebPlayer extends BasePlayer {
|
|
|
4169
3971
|
transition: opacity 0.2s ease;
|
|
4170
3972
|
}
|
|
4171
3973
|
|
|
4172
|
-
.uvf-
|
|
3974
|
+
.uvf-control-btn:active::before {
|
|
4173
3975
|
opacity: 1;
|
|
4174
3976
|
}
|
|
4175
3977
|
|
|
4176
|
-
.uvf-
|
|
4177
|
-
/* Material elevation level 2 */
|
|
3978
|
+
.uvf-control-btn:active {
|
|
4178
3979
|
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16),
|
|
4179
3980
|
0 3px 6px rgba(0, 0, 0, 0.23);
|
|
4180
3981
|
transform: scale(0.95);
|
|
4181
3982
|
}
|
|
4182
3983
|
|
|
4183
|
-
.uvf-
|
|
3984
|
+
.uvf-control-btn.play-pause {
|
|
4184
3985
|
width: 56px;
|
|
4185
3986
|
height: 56px;
|
|
4186
3987
|
min-width: 56px;
|
|
4187
3988
|
min-height: 56px;
|
|
4188
3989
|
border-radius: 28px;
|
|
4189
|
-
/* Material elevated button */
|
|
4190
3990
|
background: linear-gradient(135deg,
|
|
4191
3991
|
var(--uvf-accent-1, #ff0000),
|
|
4192
3992
|
var(--uvf-accent-2, #ff4d4f));
|
|
@@ -4195,21 +3995,31 @@ export class WebPlayer extends BasePlayer {
|
|
|
4195
3995
|
0 0 0 0 var(--uvf-accent-1, #ff0000);
|
|
4196
3996
|
}
|
|
4197
3997
|
|
|
4198
|
-
.uvf-
|
|
3998
|
+
.uvf-control-btn.play-pause:active {
|
|
4199
3999
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25),
|
|
4200
4000
|
0 4px 8px rgba(0, 0, 0, 0.20),
|
|
4201
4001
|
0 0 0 8px rgba(255, 0, 0, 0.12);
|
|
4202
4002
|
}
|
|
4203
4003
|
|
|
4004
|
+
.uvf-control-btn svg {
|
|
4005
|
+
width: 20px;
|
|
4006
|
+
height: 20px;
|
|
4007
|
+
}
|
|
4008
|
+
|
|
4009
|
+
.uvf-control-btn.play-pause svg {
|
|
4010
|
+
width: 24px;
|
|
4011
|
+
height: 24px;
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4204
4014
|
/* Controls row with Material spacing */
|
|
4205
|
-
.uvf-
|
|
4015
|
+
.uvf-controls-row {
|
|
4206
4016
|
gap: 16px;
|
|
4207
4017
|
padding: 0;
|
|
4208
4018
|
align-items: center;
|
|
4209
4019
|
}
|
|
4210
4020
|
|
|
4211
4021
|
/* Time display with Material surface */
|
|
4212
|
-
.uvf-
|
|
4022
|
+
.uvf-time-display {
|
|
4213
4023
|
background: rgba(255, 255, 255, 0.1);
|
|
4214
4024
|
backdrop-filter: blur(8px);
|
|
4215
4025
|
border-radius: 16px;
|
|
@@ -4217,101 +4027,20 @@ export class WebPlayer extends BasePlayer {
|
|
|
4217
4027
|
font-size: 13px;
|
|
4218
4028
|
font-weight: 500;
|
|
4219
4029
|
font-feature-settings: 'tnum';
|
|
4220
|
-
/* Material elevation */
|
|
4221
4030
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
4222
4031
|
}
|
|
4223
4032
|
|
|
4224
|
-
/*
|
|
4225
|
-
.uvf-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
height: 80px;
|
|
4231
|
-
background: rgba(255, 255, 255, 0.2);
|
|
4232
|
-
backdrop-filter: blur(10px);
|
|
4233
|
-
border-radius: 40px;
|
|
4234
|
-
display: flex;
|
|
4235
|
-
align-items: center;
|
|
4236
|
-
justify-content: center;
|
|
4237
|
-
pointer-events: none;
|
|
4238
|
-
opacity: 0;
|
|
4239
|
-
z-index: 100;
|
|
4240
|
-
transition: opacity 0.3s ease;
|
|
4241
|
-
/* Material elevation level 3 */
|
|
4242
|
-
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19),
|
|
4243
|
-
0 6px 6px rgba(0, 0, 0, 0.23);
|
|
4244
|
-
}
|
|
4245
|
-
|
|
4246
|
-
.uvf-doubletap-indicator.left {
|
|
4247
|
-
left: 15%;
|
|
4248
|
-
}
|
|
4249
|
-
|
|
4250
|
-
.uvf-doubletap-indicator.right {
|
|
4251
|
-
right: 15%;
|
|
4252
|
-
}
|
|
4253
|
-
|
|
4254
|
-
.uvf-doubletap-indicator.active {
|
|
4255
|
-
opacity: 1;
|
|
4256
|
-
animation: doubletap-pulse 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
4257
|
-
}
|
|
4258
|
-
|
|
4259
|
-
@keyframes doubletap-pulse {
|
|
4260
|
-
0% {
|
|
4261
|
-
transform: translateY(-50%) scale(0.8);
|
|
4262
|
-
opacity: 0;
|
|
4263
|
-
}
|
|
4264
|
-
50% {
|
|
4265
|
-
transform: translateY(-50%) scale(1.1);
|
|
4266
|
-
opacity: 1;
|
|
4267
|
-
}
|
|
4268
|
-
100% {
|
|
4269
|
-
transform: translateY(-50%) scale(1);
|
|
4270
|
-
opacity: 1;
|
|
4271
|
-
}
|
|
4272
|
-
}
|
|
4273
|
-
|
|
4274
|
-
.uvf-doubletap-indicator svg {
|
|
4275
|
-
width: 40px;
|
|
4276
|
-
height: 40px;
|
|
4277
|
-
fill: #fff;
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4280
|
-
/* Long-press 2x speed indicator */
|
|
4281
|
-
.uvf-longpress-indicator {
|
|
4282
|
-
position: absolute;
|
|
4283
|
-
top: 50%;
|
|
4284
|
-
left: 50%;
|
|
4285
|
-
transform: translate(-50%, -50%);
|
|
4286
|
-
background: rgba(0, 0, 0, 0.8);
|
|
4287
|
-
backdrop-filter: blur(16px);
|
|
4288
|
-
padding: 16px 24px;
|
|
4289
|
-
border-radius: 24px;
|
|
4290
|
-
color: #fff;
|
|
4291
|
-
font-size: 18px;
|
|
4292
|
-
font-weight: 600;
|
|
4293
|
-
pointer-events: none;
|
|
4294
|
-
opacity: 0;
|
|
4295
|
-
z-index: 100;
|
|
4296
|
-
transition: opacity 0.2s ease;
|
|
4297
|
-
/* Material elevation level 4 */
|
|
4298
|
-
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25),
|
|
4299
|
-
0 10px 10px rgba(0, 0, 0, 0.22);
|
|
4300
|
-
}
|
|
4301
|
-
|
|
4302
|
-
.uvf-longpress-indicator.active {
|
|
4303
|
-
opacity: 1;
|
|
4304
|
-
}
|
|
4305
|
-
|
|
4306
|
-
/* Hide desktop elements in Material You mode */
|
|
4307
|
-
.uvf-player-wrapper.uvf-material-you-mobile .uvf-top-controls,
|
|
4308
|
-
.uvf-player-wrapper.uvf-material-you-mobile .uvf-title-bar,
|
|
4309
|
-
.uvf-player-wrapper.uvf-material-you-mobile .uvf-volume-control {
|
|
4033
|
+
/* Hide desktop elements */
|
|
4034
|
+
.uvf-top-controls,
|
|
4035
|
+
.uvf-title-bar,
|
|
4036
|
+
.uvf-volume-control,
|
|
4037
|
+
#uvf-skip-back,
|
|
4038
|
+
#uvf-skip-forward {
|
|
4310
4039
|
display: none !important;
|
|
4311
4040
|
}
|
|
4312
4041
|
|
|
4313
4042
|
/* Optimize settings button for Material You */
|
|
4314
|
-
|
|
4043
|
+
#uvf-settings-btn {
|
|
4315
4044
|
width: 48px !important;
|
|
4316
4045
|
height: 48px !important;
|
|
4317
4046
|
min-width: 48px !important;
|
|
@@ -4319,405 +4048,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
4319
4048
|
border-radius: 24px !important;
|
|
4320
4049
|
}
|
|
4321
4050
|
}
|
|
4322
|
-
|
|
4323
|
-
/* Mobile devices (portrait) - Enhanced UX with Safe Areas */
|
|
4324
|
-
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
4325
|
-
.uvf-responsive-container {
|
|
4326
|
-
padding: 0;
|
|
4327
|
-
width: 100vw !important;
|
|
4328
|
-
height: calc(100vh - var(--uvf-safe-area-top) - var(--uvf-safe-area-bottom));
|
|
4329
|
-
margin: 0;
|
|
4330
|
-
position: relative;
|
|
4331
|
-
overflow: hidden;
|
|
4332
|
-
}
|
|
4333
|
-
|
|
4334
|
-
@supports (height: 100dvh) {
|
|
4335
|
-
.uvf-responsive-container {
|
|
4336
|
-
height: calc(100dvh - var(--uvf-safe-area-top) - var(--uvf-safe-area-bottom));
|
|
4337
|
-
}
|
|
4338
|
-
}
|
|
4339
|
-
|
|
4340
|
-
.uvf-responsive-container .uvf-player-wrapper {
|
|
4341
|
-
width: 100vw !important;
|
|
4342
|
-
height: 100% !important;
|
|
4343
|
-
min-height: calc(100vh - var(--uvf-safe-area-top) - var(--uvf-safe-area-bottom));
|
|
4344
|
-
}
|
|
4345
|
-
|
|
4346
|
-
@supports (height: 100dvh) {
|
|
4347
|
-
.uvf-responsive-container .uvf-player-wrapper {
|
|
4348
|
-
min-height: calc(100dvh - var(--uvf-safe-area-top) - var(--uvf-safe-area-bottom));
|
|
4349
|
-
}
|
|
4350
|
-
}
|
|
4351
|
-
|
|
4352
|
-
.uvf-responsive-container .uvf-video-container {
|
|
4353
|
-
width: 100vw !important;
|
|
4354
|
-
height: 100% !important;
|
|
4355
|
-
aspect-ratio: unset !important;
|
|
4356
|
-
min-height: inherit;
|
|
4357
|
-
}
|
|
4358
|
-
|
|
4359
|
-
/* Enhanced mobile controls bar with safe area padding - iOS Safari specific fixes */
|
|
4360
|
-
.uvf-controls-bar {
|
|
4361
|
-
position: absolute !important;
|
|
4362
|
-
bottom: 0 !important;
|
|
4363
|
-
left: 0 !important;
|
|
4364
|
-
right: 0 !important;
|
|
4365
|
-
padding: 16px 12px;
|
|
4366
|
-
padding-bottom: calc(16px + var(--uvf-safe-area-bottom, 0px));
|
|
4367
|
-
padding-left: calc(12px + var(--uvf-safe-area-left, 0px));
|
|
4368
|
-
padding-right: calc(12px + var(--uvf-safe-area-right, 0px));
|
|
4369
|
-
background: linear-gradient(to top, var(--uvf-overlay-strong) 0%, var(--uvf-overlay-medium) 80%, var(--uvf-overlay-transparent) 100%);
|
|
4370
|
-
box-sizing: border-box;
|
|
4371
|
-
z-index: 1000 !important;
|
|
4372
|
-
/* iOS Safari specific fixes */
|
|
4373
|
-
transform: translateZ(0);
|
|
4374
|
-
-webkit-transform: translateZ(0);
|
|
4375
|
-
will-change: transform;
|
|
4376
|
-
/* Ensure proper stacking */
|
|
4377
|
-
isolation: isolate;
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
|
-
.uvf-progress-section {
|
|
4381
|
-
margin-bottom: 16px;
|
|
4382
|
-
}
|
|
4383
|
-
|
|
4384
|
-
/* Mobile-first responsive controls layout */
|
|
4385
|
-
.uvf-controls-row {
|
|
4386
|
-
gap: 8px;
|
|
4387
|
-
flex-wrap: nowrap;
|
|
4388
|
-
align-items: center;
|
|
4389
|
-
justify-content: space-between;
|
|
4390
|
-
position: relative;
|
|
4391
|
-
width: 100%;
|
|
4392
|
-
}
|
|
4393
|
-
|
|
4394
|
-
/* Left side controls group */
|
|
4395
|
-
.uvf-left-controls {
|
|
4396
|
-
display: flex;
|
|
4397
|
-
align-items: center;
|
|
4398
|
-
gap: 8px;
|
|
4399
|
-
flex-shrink: 0;
|
|
4400
|
-
}
|
|
4401
|
-
|
|
4402
|
-
/* Center controls group */
|
|
4403
|
-
.uvf-center-controls {
|
|
4404
|
-
display: flex;
|
|
4405
|
-
align-items: center;
|
|
4406
|
-
gap: 8px;
|
|
4407
|
-
flex: 1;
|
|
4408
|
-
justify-content: center;
|
|
4409
|
-
}
|
|
4410
|
-
|
|
4411
|
-
/* Mobile control groups reordering */
|
|
4412
|
-
.uvf-controls-row .uvf-control-btn.play-pause,
|
|
4413
|
-
.uvf-controls-row #uvf-skip-back,
|
|
4414
|
-
.uvf-controls-row #uvf-skip-forward {
|
|
4415
|
-
order: 1;
|
|
4416
|
-
}
|
|
4417
|
-
|
|
4418
|
-
.uvf-controls-row .uvf-volume-control {
|
|
4419
|
-
order: 2;
|
|
4420
|
-
}
|
|
4421
|
-
|
|
4422
|
-
.uvf-controls-row .uvf-time-display:not(.uvf-above-seekbar) {
|
|
4423
|
-
order: 3;
|
|
4424
|
-
margin-left: auto;
|
|
4425
|
-
margin-right: 8px;
|
|
4426
|
-
}
|
|
4427
|
-
|
|
4428
|
-
.uvf-controls-row .uvf-right-controls {
|
|
4429
|
-
order: 4;
|
|
4430
|
-
margin-left: 0;
|
|
4431
|
-
}
|
|
4432
|
-
|
|
4433
|
-
/* Touch-friendly control sizing (minimum 44px touch target) */
|
|
4434
|
-
.uvf-control-btn {
|
|
4435
|
-
width: 44px;
|
|
4436
|
-
height: 44px;
|
|
4437
|
-
min-width: 44px;
|
|
4438
|
-
min-height: 44px;
|
|
4439
|
-
border-radius: 22px;
|
|
4440
|
-
background: rgba(255,255,255,0.15);
|
|
4441
|
-
backdrop-filter: blur(8px);
|
|
4442
|
-
}
|
|
4443
|
-
|
|
4444
|
-
.uvf-control-btn.play-pause {
|
|
4445
|
-
width: 52px;
|
|
4446
|
-
height: 52px;
|
|
4447
|
-
min-width: 52px;
|
|
4448
|
-
min-height: 52px;
|
|
4449
|
-
border-radius: 26px;
|
|
4450
|
-
background: linear-gradient(135deg, var(--uvf-accent-1), var(--uvf-accent-2));
|
|
4451
|
-
box-shadow: 0 4px 12px rgba(var(--uvf-accent-1), 0.3);
|
|
4452
|
-
}
|
|
4453
|
-
|
|
4454
|
-
.uvf-control-btn svg {
|
|
4455
|
-
width: 20px;
|
|
4456
|
-
height: 20px;
|
|
4457
|
-
}
|
|
4458
|
-
|
|
4459
|
-
.uvf-control-btn.play-pause svg {
|
|
4460
|
-
width: 24px;
|
|
4461
|
-
height: 24px;
|
|
4462
|
-
}
|
|
4463
|
-
|
|
4464
|
-
/* Skip buttons with clear visual hierarchy */
|
|
4465
|
-
#uvf-skip-back,
|
|
4466
|
-
#uvf-skip-forward {
|
|
4467
|
-
background: rgba(255,255,255,0.12);
|
|
4468
|
-
}
|
|
4469
|
-
|
|
4470
|
-
#uvf-skip-back svg,
|
|
4471
|
-
#uvf-skip-forward svg {
|
|
4472
|
-
width: 22px;
|
|
4473
|
-
height: 22px;
|
|
4474
|
-
}
|
|
4475
|
-
|
|
4476
|
-
/* Mobile time display - compact but readable */
|
|
4477
|
-
.uvf-time-display:not(.uvf-above-seekbar) {
|
|
4478
|
-
font-size: 12px;
|
|
4479
|
-
font-weight: 600;
|
|
4480
|
-
padding: 0 6px;
|
|
4481
|
-
text-align: center;
|
|
4482
|
-
background: rgba(0,0,0,0.3);
|
|
4483
|
-
border-radius: 12px;
|
|
4484
|
-
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
|
|
4485
|
-
flex-shrink: 0;
|
|
4486
|
-
}
|
|
4487
|
-
|
|
4488
|
-
/* Above-seekbar time display for mobile */
|
|
4489
|
-
.uvf-time-display.uvf-above-seekbar {
|
|
4490
|
-
font-size: 12px !important;
|
|
4491
|
-
font-weight: 500 !important;
|
|
4492
|
-
padding: 3px 6px !important;
|
|
4493
|
-
background: rgba(0,0,0,0.4) !important;
|
|
4494
|
-
border-radius: 10px !important;
|
|
4495
|
-
text-shadow: 0 1px 2px rgba(0,0,0,0.8) !important;
|
|
4496
|
-
backdrop-filter: blur(4px) !important;
|
|
4497
|
-
border: 1px solid rgba(255,255,255,0.1) !important;
|
|
4498
|
-
}
|
|
4499
|
-
|
|
4500
|
-
/* Simplified volume control for mobile */
|
|
4501
|
-
.uvf-volume-control {
|
|
4502
|
-
order: 3;
|
|
4503
|
-
position: relative;
|
|
4504
|
-
}
|
|
4505
|
-
|
|
4506
|
-
/* Hide volume panel on mobile - use device controls */
|
|
4507
|
-
.uvf-volume-panel {
|
|
4508
|
-
display: none;
|
|
4509
|
-
}
|
|
4510
|
-
|
|
4511
|
-
/* Mobile volume button as simple mute toggle */
|
|
4512
|
-
.uvf-volume-control .uvf-control-btn {
|
|
4513
|
-
width: 44px;
|
|
4514
|
-
height: 44px;
|
|
4515
|
-
}
|
|
4516
|
-
|
|
4517
|
-
/* Compact right controls for mobile */
|
|
4518
|
-
.uvf-right-controls {
|
|
4519
|
-
gap: 6px;
|
|
4520
|
-
display: flex;
|
|
4521
|
-
align-items: center;
|
|
4522
|
-
flex-shrink: 0;
|
|
4523
|
-
position: relative;
|
|
4524
|
-
z-index: 10;
|
|
4525
|
-
}
|
|
4526
|
-
|
|
4527
|
-
/* Ensure settings container is visible */
|
|
4528
|
-
.uvf-right-controls > div[style*="position: relative"],
|
|
4529
|
-
.uvf-settings-container {
|
|
4530
|
-
display: flex !important;
|
|
4531
|
-
position: relative !important;
|
|
4532
|
-
align-items: center !important;
|
|
4533
|
-
justify-content: center !important;
|
|
4534
|
-
min-width: 44px !important;
|
|
4535
|
-
min-height: 44px !important;
|
|
4536
|
-
}
|
|
4537
|
-
|
|
4538
|
-
/* Remove quality badge completely - not essential */
|
|
4539
|
-
.uvf-quality-badge {
|
|
4540
|
-
display: none !important;
|
|
4541
|
-
}
|
|
4542
|
-
|
|
4543
|
-
/* Settings menu - hidden by default, accessible via menu */
|
|
4544
|
-
.uvf-settings-menu {
|
|
4545
|
-
min-width: 160px;
|
|
4546
|
-
bottom: 60px;
|
|
4547
|
-
right: 12px;
|
|
4548
|
-
font-size: 14px;
|
|
4549
|
-
max-height: 50vh;
|
|
4550
|
-
}
|
|
4551
|
-
|
|
4552
|
-
.uvf-settings-option {
|
|
4553
|
-
padding: 12px 16px;
|
|
4554
|
-
font-size: 14px;
|
|
4555
|
-
min-height: 44px;
|
|
4556
|
-
display: flex;
|
|
4557
|
-
align-items: center;
|
|
4558
|
-
}
|
|
4559
|
-
|
|
4560
|
-
.uvf-settings-option:hover {
|
|
4561
|
-
background: rgba(255,255,255,0.15);
|
|
4562
|
-
padding-left: 20px;
|
|
4563
|
-
}
|
|
4564
|
-
|
|
4565
|
-
/* Simplified settings - hide complex options */
|
|
4566
|
-
.uvf-settings-group:first-child .uvf-settings-option[data-speed="0.5"],
|
|
4567
|
-
.uvf-settings-group:first-child .uvf-settings-option[data-speed="0.75"],
|
|
4568
|
-
.uvf-settings-group:first-child .uvf-settings-option[data-speed="2"] {
|
|
4569
|
-
display: none;
|
|
4570
|
-
}
|
|
4571
|
-
}
|
|
4572
|
-
|
|
4573
|
-
/* Enhanced top controls for mobile with safe area support */
|
|
4574
|
-
.uvf-top-controls {
|
|
4575
|
-
position: absolute;
|
|
4576
|
-
top: calc(12px + var(--uvf-safe-area-top));
|
|
4577
|
-
right: calc(12px + var(--uvf-safe-area-right));
|
|
4578
|
-
display: flex;
|
|
4579
|
-
align-items: center;
|
|
4580
|
-
gap: 8px;
|
|
4581
|
-
z-index: 10;
|
|
4582
|
-
}
|
|
4583
|
-
|
|
4584
|
-
/* Touch-friendly top buttons */
|
|
4585
|
-
.uvf-top-btn {
|
|
4586
|
-
width: 44px;
|
|
4587
|
-
height: 44px;
|
|
4588
|
-
min-width: 44px;
|
|
4589
|
-
min-height: 44px;
|
|
4590
|
-
background: rgba(0,0,0,0.7);
|
|
4591
|
-
backdrop-filter: blur(10px);
|
|
4592
|
-
border: 1px solid rgba(255,255,255,0.2);
|
|
4593
|
-
}
|
|
4594
|
-
|
|
4595
|
-
.uvf-top-btn svg {
|
|
4596
|
-
width: 20px;
|
|
4597
|
-
height: 20px;
|
|
4598
|
-
}
|
|
4599
|
-
|
|
4600
|
-
/* Share button - keep visible on all devices */
|
|
4601
|
-
#uvf-share-btn {
|
|
4602
|
-
display: flex;
|
|
4603
|
-
}
|
|
4604
|
-
|
|
4605
|
-
/* Enhanced title bar for mobile with safe area support */
|
|
4606
|
-
.uvf-title-bar {
|
|
4607
|
-
padding: 12px;
|
|
4608
|
-
padding-top: calc(12px + var(--uvf-safe-area-top));
|
|
4609
|
-
padding-left: calc(12px + var(--uvf-safe-area-left));
|
|
4610
|
-
padding-right: calc(12px + var(--uvf-safe-area-right));
|
|
4611
|
-
}
|
|
4612
|
-
|
|
4613
|
-
.uvf-video-title {
|
|
4614
|
-
font-size: 16px;
|
|
4615
|
-
font-weight: 700;
|
|
4616
|
-
line-height: 1.2;
|
|
4617
|
-
}
|
|
4618
|
-
|
|
4619
|
-
.uvf-video-subtitle {
|
|
4620
|
-
font-size: 12px;
|
|
4621
|
-
margin-top: 4px;
|
|
4622
|
-
opacity: 0.8;
|
|
4623
|
-
}
|
|
4624
|
-
|
|
4625
|
-
.uvf-video-thumb {
|
|
4626
|
-
width: 48px;
|
|
4627
|
-
height: 48px;
|
|
4628
|
-
border-radius: 6px;
|
|
4629
|
-
}
|
|
4630
|
-
|
|
4631
|
-
/* Touch-optimized center play button - uses same themed style as desktop */
|
|
4632
|
-
.uvf-center-play-btn {
|
|
4633
|
-
width: clamp(72px, 18vw, 96px);
|
|
4634
|
-
height: clamp(72px, 18vw, 96px);
|
|
4635
|
-
background: linear-gradient(135deg, var(--uvf-accent-1), var(--uvf-accent-2));
|
|
4636
|
-
border: 0;
|
|
4637
|
-
box-shadow: 0 10px 30px var(--uvf-accent-1-20);
|
|
4638
|
-
}
|
|
4639
|
-
|
|
4640
|
-
.uvf-center-play-btn:hover {
|
|
4641
|
-
transform: scale(1.06);
|
|
4642
|
-
filter: saturate(1.08) brightness(1.05);
|
|
4643
|
-
box-shadow: 0 14px 36px var(--uvf-accent-1-20);
|
|
4644
|
-
}
|
|
4645
|
-
|
|
4646
|
-
.uvf-center-play-btn svg {
|
|
4647
|
-
width: clamp(28px, 5.2vw, 38px);
|
|
4648
|
-
height: clamp(28px, 5.2vw, 38px);
|
|
4649
|
-
margin-left: 4px;
|
|
4650
|
-
}
|
|
4651
|
-
|
|
4652
|
-
/* Enhanced progress bar for touch */
|
|
4653
|
-
.uvf-progress-bar {
|
|
4654
|
-
height: 3px;
|
|
4655
|
-
margin-bottom: 12px;
|
|
4656
|
-
border-radius: 4px;
|
|
4657
|
-
background: rgba(255,255,255,0.15);
|
|
4658
|
-
position: relative;
|
|
4659
|
-
}
|
|
4660
|
-
|
|
4661
|
-
/* Larger touch target for progress bar */
|
|
4662
|
-
.uvf-progress-bar-wrapper::before {
|
|
4663
|
-
content: '';
|
|
4664
|
-
position: absolute;
|
|
4665
|
-
top: -10px;
|
|
4666
|
-
left: 0;
|
|
4667
|
-
right: 0;
|
|
4668
|
-
bottom: -10px;
|
|
4669
|
-
z-index: 1;
|
|
4670
|
-
}
|
|
4671
|
-
|
|
4672
|
-
.uvf-progress-handle {
|
|
4673
|
-
width: 18px;
|
|
4674
|
-
height: 18px;
|
|
4675
|
-
background: #fff;
|
|
4676
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
4677
|
-
}
|
|
4678
|
-
|
|
4679
|
-
.uvf-progress-bar-wrapper:active .uvf-progress-handle {
|
|
4680
|
-
transform: translate(-50%, -50%) scale(1.2);
|
|
4681
|
-
}
|
|
4682
|
-
|
|
4683
|
-
/* Mobile accessibility improvements */
|
|
4684
|
-
.uvf-control-btn,
|
|
4685
|
-
.uvf-top-btn {
|
|
4686
|
-
position: relative;
|
|
4687
|
-
overflow: visible;
|
|
4688
|
-
}
|
|
4689
|
-
|
|
4690
|
-
/* Enhanced focus states for mobile */
|
|
4691
|
-
.uvf-control-btn:focus,
|
|
4692
|
-
.uvf-top-btn:focus {
|
|
4693
|
-
outline: 2px solid var(--uvf-accent-1);
|
|
4694
|
-
outline-offset: 2px;
|
|
4695
|
-
}
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
/* Show PiP on all devices - modern mobile browsers support it well */
|
|
4699
|
-
#uvf-pip-btn {
|
|
4700
|
-
display: block;
|
|
4701
|
-
background: rgba(255,255,255,0.12);
|
|
4702
|
-
border: 1px solid rgba(255,255,255,0.1);
|
|
4703
|
-
}
|
|
4704
|
-
|
|
4705
|
-
/* Essential controls in right section - Settings, PiP, and Fullscreen only */
|
|
4706
|
-
.uvf-right-controls > *:not(#uvf-settings-btn):not(#uvf-fullscreen-btn):not(#uvf-pip-btn) {
|
|
4707
|
-
display: none;
|
|
4708
|
-
}
|
|
4709
|
-
|
|
4710
|
-
/* Ensure settings button is always visible and properly sized on mobile */
|
|
4711
|
-
#uvf-settings-btn {
|
|
4712
|
-
display: flex !important;
|
|
4713
|
-
width: 44px !important;
|
|
4714
|
-
height: 44px !important;
|
|
4715
|
-
min-width: 44px !important;
|
|
4716
|
-
min-height: 44px !important;
|
|
4717
|
-
backdrop-filter: blur(8px) !important;
|
|
4718
|
-
border-radius: 22px !important;
|
|
4719
|
-
align-items: center !important;
|
|
4720
|
-
justify-content: center !important;
|
|
4721
4051
|
}
|
|
4722
4052
|
|
|
4723
4053
|
#uvf-settings-btn svg {
|
|
@@ -5614,21 +4944,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
5614
4944
|
shortcutIndicator.className = 'uvf-shortcut-indicator';
|
|
5615
4945
|
shortcutIndicator.id = 'uvf-shortcut-indicator';
|
|
5616
4946
|
container.appendChild(shortcutIndicator);
|
|
5617
|
-
const doubleTapLeft = document.createElement('div');
|
|
5618
|
-
doubleTapLeft.className = 'uvf-doubletap-indicator left';
|
|
5619
|
-
doubleTapLeft.id = 'uvf-doubletap-left';
|
|
5620
|
-
doubleTapLeft.innerHTML = '<svg viewBox="0 0 24 24"><path d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/></svg><div style="margin-top:4px;font-size:14px;font-weight:600;">-10s</div>';
|
|
5621
|
-
container.appendChild(doubleTapLeft);
|
|
5622
|
-
const doubleTapRight = document.createElement('div');
|
|
5623
|
-
doubleTapRight.className = 'uvf-doubletap-indicator right';
|
|
5624
|
-
doubleTapRight.id = 'uvf-doubletap-right';
|
|
5625
|
-
doubleTapRight.innerHTML = '<svg viewBox="0 0 24 24"><path d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/></svg><div style="margin-top:4px;font-size:14px;font-weight:600;">+10s</div>';
|
|
5626
|
-
container.appendChild(doubleTapRight);
|
|
5627
|
-
const longPressIndicator = document.createElement('div');
|
|
5628
|
-
longPressIndicator.className = 'uvf-longpress-indicator';
|
|
5629
|
-
longPressIndicator.id = 'uvf-longpress-indicator';
|
|
5630
|
-
longPressIndicator.textContent = '2x';
|
|
5631
|
-
container.appendChild(longPressIndicator);
|
|
5632
4947
|
const controlsBar = document.createElement('div');
|
|
5633
4948
|
controlsBar.className = 'uvf-controls-bar';
|
|
5634
4949
|
controlsBar.id = 'uvf-controls';
|
|
@@ -5861,7 +5176,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
5861
5176
|
});
|
|
5862
5177
|
centerPlay?.addEventListener('click', () => this.togglePlayPause());
|
|
5863
5178
|
playPauseBtn?.addEventListener('click', () => this.togglePlayPause());
|
|
5864
|
-
this.
|
|
5179
|
+
this.video.addEventListener('click', () => this.togglePlayPause());
|
|
5865
5180
|
this.video.addEventListener('play', () => {
|
|
5866
5181
|
const playIcon = document.getElementById('uvf-play-icon');
|
|
5867
5182
|
const pauseIcon = document.getElementById('uvf-pause-icon');
|
|
@@ -6154,12 +5469,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
6154
5469
|
this.debugLog('Settings menu classes before toggle:', Array.from(settingsMenu?.classList || []).join(' '));
|
|
6155
5470
|
settingsMenu?.classList.toggle('active');
|
|
6156
5471
|
if (settingsMenu) {
|
|
6157
|
-
|
|
6158
|
-
if (activating) {
|
|
6159
|
-
this.isSettingsOpen = true;
|
|
6160
|
-
this.showControls();
|
|
6161
|
-
if (this.hideControlsTimeout)
|
|
6162
|
-
clearTimeout(this.hideControlsTimeout);
|
|
5472
|
+
if (settingsMenu.classList.contains('active')) {
|
|
6163
5473
|
settingsMenu.style.display = 'block';
|
|
6164
5474
|
settingsMenu.style.visibility = 'visible';
|
|
6165
5475
|
settingsMenu.style.opacity = '1';
|
|
@@ -6176,12 +5486,10 @@ export class WebPlayer extends BasePlayer {
|
|
|
6176
5486
|
this.debugLog('Applied fallback styles to show menu');
|
|
6177
5487
|
}
|
|
6178
5488
|
else {
|
|
6179
|
-
this.isSettingsOpen = false;
|
|
6180
5489
|
settingsMenu.style.display = 'none';
|
|
6181
5490
|
settingsMenu.style.visibility = 'hidden';
|
|
6182
5491
|
settingsMenu.style.opacity = '0';
|
|
6183
5492
|
this.debugLog('Applied fallback styles to hide menu');
|
|
6184
|
-
this.scheduleHideControls();
|
|
6185
5493
|
}
|
|
6186
5494
|
}
|
|
6187
5495
|
this.debugLog('Settings menu classes after toggle:', Array.from(settingsMenu?.classList || []).join(' '));
|
|
@@ -6209,19 +5517,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
6209
5517
|
this.hideSettingsMenu();
|
|
6210
5518
|
}
|
|
6211
5519
|
});
|
|
6212
|
-
if (settingsMenu) {
|
|
6213
|
-
const keepAlive = () => {
|
|
6214
|
-
if (!this.isSettingsOpen)
|
|
6215
|
-
return;
|
|
6216
|
-
this.showControls();
|
|
6217
|
-
if (this.hideControlsTimeout)
|
|
6218
|
-
clearTimeout(this.hideControlsTimeout);
|
|
6219
|
-
};
|
|
6220
|
-
settingsMenu.addEventListener('mouseenter', keepAlive);
|
|
6221
|
-
settingsMenu.addEventListener('mousemove', keepAlive);
|
|
6222
|
-
settingsMenu.addEventListener('touchstart', keepAlive, { passive: true });
|
|
6223
|
-
settingsMenu.addEventListener('touchmove', keepAlive, { passive: true });
|
|
6224
|
-
}
|
|
6225
5520
|
document.addEventListener('keydown', (e) => {
|
|
6226
5521
|
if (e.key === 'Escape' && settingsMenu?.classList.contains('active')) {
|
|
6227
5522
|
this.hideSettingsMenu();
|
|
@@ -6662,187 +5957,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
6662
5957
|
this.mute();
|
|
6663
5958
|
}
|
|
6664
5959
|
}
|
|
6665
|
-
setupMaterialYouGestures(wrapper) {
|
|
6666
|
-
if (!wrapper || !this.video)
|
|
6667
|
-
return;
|
|
6668
|
-
const doubleTapLeft = document.getElementById('uvf-doubletap-left');
|
|
6669
|
-
const doubleTapRight = document.getElementById('uvf-doubletap-right');
|
|
6670
|
-
const longPressIndicator = document.getElementById('uvf-longpress-indicator');
|
|
6671
|
-
const videoElement = this.video;
|
|
6672
|
-
const videoContainer = wrapper.querySelector('.uvf-video-container');
|
|
6673
|
-
if (!videoContainer)
|
|
6674
|
-
return;
|
|
6675
|
-
videoContainer.addEventListener('touchstart', (e) => {
|
|
6676
|
-
const touchEvent = e;
|
|
6677
|
-
const touch = touchEvent.touches[0];
|
|
6678
|
-
if (!touch || !videoElement)
|
|
6679
|
-
return;
|
|
6680
|
-
this.longPressStartTime = Date.now();
|
|
6681
|
-
this.longPressTimer = setTimeout(() => {
|
|
6682
|
-
this.longPressActive = true;
|
|
6683
|
-
this.originalPlaybackRate = videoElement.playbackRate;
|
|
6684
|
-
videoElement.playbackRate = 2.0;
|
|
6685
|
-
if (longPressIndicator) {
|
|
6686
|
-
longPressIndicator.classList.add('active');
|
|
6687
|
-
}
|
|
6688
|
-
}, 500);
|
|
6689
|
-
}, { passive: true });
|
|
6690
|
-
videoContainer.addEventListener('touchend', (e) => {
|
|
6691
|
-
const touchEvent = e;
|
|
6692
|
-
const touch = touchEvent.changedTouches[0];
|
|
6693
|
-
if (!touch || !videoElement)
|
|
6694
|
-
return;
|
|
6695
|
-
if (this.longPressTimer) {
|
|
6696
|
-
clearTimeout(this.longPressTimer);
|
|
6697
|
-
this.longPressTimer = null;
|
|
6698
|
-
}
|
|
6699
|
-
if (this.longPressActive) {
|
|
6700
|
-
videoElement.playbackRate = this.originalPlaybackRate;
|
|
6701
|
-
this.longPressActive = false;
|
|
6702
|
-
if (longPressIndicator) {
|
|
6703
|
-
longPressIndicator.classList.remove('active');
|
|
6704
|
-
}
|
|
6705
|
-
return;
|
|
6706
|
-
}
|
|
6707
|
-
const now = Date.now();
|
|
6708
|
-
const timeSinceLastTap = now - this.lastTapTime;
|
|
6709
|
-
if (timeSinceLastTap < 300) {
|
|
6710
|
-
if (this.tapTimeout) {
|
|
6711
|
-
clearTimeout(this.tapTimeout);
|
|
6712
|
-
this.tapTimeout = null;
|
|
6713
|
-
}
|
|
6714
|
-
const rect = videoContainer.getBoundingClientRect();
|
|
6715
|
-
const x = touch.clientX - rect.left;
|
|
6716
|
-
const isLeftSide = x < rect.width / 2;
|
|
6717
|
-
if (isLeftSide) {
|
|
6718
|
-
this.seek(videoElement.currentTime - 10);
|
|
6719
|
-
if (doubleTapLeft) {
|
|
6720
|
-
doubleTapLeft.classList.add('active');
|
|
6721
|
-
setTimeout(() => {
|
|
6722
|
-
doubleTapLeft.classList.remove('active');
|
|
6723
|
-
}, 400);
|
|
6724
|
-
}
|
|
6725
|
-
}
|
|
6726
|
-
else {
|
|
6727
|
-
this.seek(videoElement.currentTime + 10);
|
|
6728
|
-
if (doubleTapRight) {
|
|
6729
|
-
doubleTapRight.classList.add('active');
|
|
6730
|
-
setTimeout(() => {
|
|
6731
|
-
doubleTapRight.classList.remove('active');
|
|
6732
|
-
}, 400);
|
|
6733
|
-
}
|
|
6734
|
-
}
|
|
6735
|
-
this.tapCount = 0;
|
|
6736
|
-
this.lastTapTime = 0;
|
|
6737
|
-
}
|
|
6738
|
-
else {
|
|
6739
|
-
this.tapCount = 1;
|
|
6740
|
-
this.lastTapTime = now;
|
|
6741
|
-
this.tapTimeout = setTimeout(() => {
|
|
6742
|
-
if (this.tapCount === 1) {
|
|
6743
|
-
this.toggleControls();
|
|
6744
|
-
}
|
|
6745
|
-
this.tapCount = 0;
|
|
6746
|
-
}, 300);
|
|
6747
|
-
}
|
|
6748
|
-
}, { passive: true });
|
|
6749
|
-
videoContainer.addEventListener('touchmove', () => {
|
|
6750
|
-
if (this.longPressTimer) {
|
|
6751
|
-
clearTimeout(this.longPressTimer);
|
|
6752
|
-
this.longPressTimer = null;
|
|
6753
|
-
}
|
|
6754
|
-
}, { passive: true });
|
|
6755
|
-
videoContainer.addEventListener('touchcancel', () => {
|
|
6756
|
-
if (this.longPressTimer) {
|
|
6757
|
-
clearTimeout(this.longPressTimer);
|
|
6758
|
-
this.longPressTimer = null;
|
|
6759
|
-
}
|
|
6760
|
-
if (this.longPressActive && videoElement) {
|
|
6761
|
-
videoElement.playbackRate = this.originalPlaybackRate;
|
|
6762
|
-
this.longPressActive = false;
|
|
6763
|
-
if (longPressIndicator) {
|
|
6764
|
-
longPressIndicator.classList.remove('active');
|
|
6765
|
-
}
|
|
6766
|
-
}
|
|
6767
|
-
}, { passive: true });
|
|
6768
|
-
}
|
|
6769
|
-
toggleControls() {
|
|
6770
|
-
const wrapper = this.container?.querySelector('.uvf-player-wrapper');
|
|
6771
|
-
if (wrapper) {
|
|
6772
|
-
if (wrapper.classList.contains('controls-visible')) {
|
|
6773
|
-
this.hideControls();
|
|
6774
|
-
}
|
|
6775
|
-
else {
|
|
6776
|
-
this.showControls();
|
|
6777
|
-
if (this.state.isPlaying) {
|
|
6778
|
-
this.scheduleHideControls();
|
|
6779
|
-
}
|
|
6780
|
-
}
|
|
6781
|
-
}
|
|
6782
|
-
}
|
|
6783
|
-
applyDynamicTheming(primaryColor) {
|
|
6784
|
-
if (!this.playerWrapper)
|
|
6785
|
-
return;
|
|
6786
|
-
const color = primaryColor || this.dominantColor;
|
|
6787
|
-
const rgb = this.hexToRgb(color);
|
|
6788
|
-
if (rgb) {
|
|
6789
|
-
this.playerWrapper.style.setProperty('--uvf-accent-1', color);
|
|
6790
|
-
this.playerWrapper.style.setProperty('--uvf-accent-2', this.lightenColor(color, 10));
|
|
6791
|
-
this.playerWrapper.style.setProperty('--uvf-surface-tint', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.08)`);
|
|
6792
|
-
this.debugLog(`Applied dynamic theming with color: ${color}`);
|
|
6793
|
-
}
|
|
6794
|
-
}
|
|
6795
|
-
hexToRgb(hex) {
|
|
6796
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
6797
|
-
return result ? {
|
|
6798
|
-
r: parseInt(result[1], 16),
|
|
6799
|
-
g: parseInt(result[2], 16),
|
|
6800
|
-
b: parseInt(result[3], 16)
|
|
6801
|
-
} : null;
|
|
6802
|
-
}
|
|
6803
|
-
lightenColor(hex, percent) {
|
|
6804
|
-
const rgb = this.hexToRgb(hex);
|
|
6805
|
-
if (!rgb)
|
|
6806
|
-
return hex;
|
|
6807
|
-
const amount = Math.floor(255 * (percent / 100));
|
|
6808
|
-
const r = Math.min(255, rgb.r + amount);
|
|
6809
|
-
const g = Math.min(255, rgb.g + amount);
|
|
6810
|
-
const b = Math.min(255, rgb.b + amount);
|
|
6811
|
-
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
6812
|
-
}
|
|
6813
|
-
renderChapterMarkersOnProgressBar() {
|
|
6814
|
-
if (!this.video || !this.chapterConfig.enabled || !this.chapterConfig.showChapterMarkers) {
|
|
6815
|
-
return;
|
|
6816
|
-
}
|
|
6817
|
-
const progressBar = document.querySelector('.uvf-progress-bar');
|
|
6818
|
-
if (!progressBar)
|
|
6819
|
-
return;
|
|
6820
|
-
const existingMarkers = progressBar.querySelectorAll('.uvf-chapter-marker');
|
|
6821
|
-
existingMarkers.forEach(marker => marker.remove());
|
|
6822
|
-
const chapters = this.chapterConfig.data;
|
|
6823
|
-
if (!chapters || !Array.isArray(chapters) || chapters.length === 0) {
|
|
6824
|
-
return;
|
|
6825
|
-
}
|
|
6826
|
-
const duration = this.video.duration;
|
|
6827
|
-
if (!duration || duration === 0)
|
|
6828
|
-
return;
|
|
6829
|
-
chapters.forEach((chapter) => {
|
|
6830
|
-
if (!chapter.startTime && chapter.startTime !== 0)
|
|
6831
|
-
return;
|
|
6832
|
-
const marker = document.createElement('div');
|
|
6833
|
-
marker.className = 'uvf-chapter-marker';
|
|
6834
|
-
if (chapter.type) {
|
|
6835
|
-
marker.classList.add(chapter.type.toLowerCase());
|
|
6836
|
-
}
|
|
6837
|
-
const percent = (chapter.startTime / duration) * 100;
|
|
6838
|
-
marker.style.left = `${percent}%`;
|
|
6839
|
-
if (chapter.title) {
|
|
6840
|
-
marker.setAttribute('title', chapter.title);
|
|
6841
|
-
}
|
|
6842
|
-
progressBar.appendChild(marker);
|
|
6843
|
-
});
|
|
6844
|
-
this.debugLog(`Rendered ${chapters.length} chapter markers on progress bar`);
|
|
6845
|
-
}
|
|
6846
5960
|
isMobileDevice() {
|
|
6847
5961
|
const userAgent = navigator.userAgent.toLowerCase();
|
|
6848
5962
|
const mobileKeywords = ['android', 'iphone', 'ipad', 'ipod', 'blackberry', 'windows phone', 'mobile'];
|
|
@@ -6956,8 +6070,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
6956
6070
|
hideControls() {
|
|
6957
6071
|
if (!this.state.isPlaying)
|
|
6958
6072
|
return;
|
|
6959
|
-
if (this.isSettingsOpen)
|
|
6960
|
-
return;
|
|
6961
6073
|
const wrapper = this.container?.querySelector('.uvf-player-wrapper');
|
|
6962
6074
|
if (wrapper) {
|
|
6963
6075
|
wrapper.classList.remove('controls-visible');
|
|
@@ -6967,13 +6079,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
6967
6079
|
scheduleHideControls() {
|
|
6968
6080
|
if (!this.state.isPlaying)
|
|
6969
6081
|
return;
|
|
6970
|
-
if (this.isSettingsOpen)
|
|
6971
|
-
return;
|
|
6972
6082
|
if (this.hideControlsTimeout)
|
|
6973
6083
|
clearTimeout(this.hideControlsTimeout);
|
|
6974
6084
|
const timeout = this.isFullscreen() ? 4000 : 3000;
|
|
6975
6085
|
this.hideControlsTimeout = setTimeout(() => {
|
|
6976
|
-
if (this.state.isPlaying && !this.controlsContainer?.matches(':hover')
|
|
6086
|
+
if (this.state.isPlaying && !this.controlsContainer?.matches(':hover')) {
|
|
6977
6087
|
this.hideControls();
|
|
6978
6088
|
}
|
|
6979
6089
|
}, timeout);
|
|
@@ -8010,7 +7120,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
8010
7120
|
if (!settingsMenu)
|
|
8011
7121
|
return;
|
|
8012
7122
|
settingsMenu.classList.remove('active');
|
|
8013
|
-
this.isSettingsOpen = false;
|
|
8014
7123
|
settingsMenu.style.display = 'none';
|
|
8015
7124
|
settingsMenu.style.visibility = 'hidden';
|
|
8016
7125
|
settingsMenu.style.opacity = '0';
|
|
@@ -8018,7 +7127,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
8018
7127
|
item.classList.remove('expanded');
|
|
8019
7128
|
});
|
|
8020
7129
|
this.debugLog('Settings menu hidden via hideSettingsMenu()');
|
|
8021
|
-
this.scheduleHideControls();
|
|
8022
7130
|
}
|
|
8023
7131
|
updateAccordionAfterSelection(section) {
|
|
8024
7132
|
setTimeout(() => {
|