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 - address bar handling and control positioning */
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
- /* Universal mobile fixes for all browsers */
3895
- @media screen and (max-width: 767px) {
3896
- html, body {
3897
- overflow-x: hidden;
3898
- }
3899
-
3900
- .uvf-player-wrapper {
3901
- /* Prevent scroll bounce on iOS */
3902
- -webkit-overflow-scrolling: touch;
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
- /* Hide PiP button on mobile - not supported on most mobile browsers */
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
- .uvf-player-wrapper.uvf-material-you-mobile .uvf-video-container {
3986
- /* Video occupies middle 50% */
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-player-wrapper.uvf-material-you-mobile .uvf-video {
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 overlay */
4009
- .uvf-player-wrapper.uvf-material-you-mobile::before {
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%) - Surface container */
4024
- .uvf-player-wrapper.uvf-material-you-mobile::after {
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-player-wrapper.uvf-material-you-mobile .uvf-controls-bar {
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-player-wrapper.uvf-material-you-mobile .uvf-controls-bar::before {
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-player-wrapper.uvf-material-you-mobile .uvf-progress-section {
3909
+ .uvf-progress-section {
4074
3910
  margin-bottom: 12px;
4075
3911
  position: relative;
4076
3912
  }
4077
3913
 
4078
- .uvf-player-wrapper.uvf-material-you-mobile .uvf-progress-bar-wrapper {
3914
+ .uvf-progress-bar-wrapper {
4079
3915
  padding: 12px 0;
4080
3916
  position: relative;
4081
3917
  }
4082
3918
 
4083
- .uvf-player-wrapper.uvf-material-you-mobile .uvf-progress-bar {
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-player-wrapper.uvf-material-you-mobile .uvf-progress-filled {
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-player-wrapper.uvf-material-you-mobile .uvf-progress-handle {
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-player-wrapper.uvf-material-you-mobile .uvf-progress-handle:active {
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-player-wrapper.uvf-material-you-mobile .uvf-control-btn {
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-player-wrapper.uvf-material-you-mobile .uvf-control-btn::before {
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-player-wrapper.uvf-material-you-mobile .uvf-control-btn:active::before {
3974
+ .uvf-control-btn:active::before {
4173
3975
  opacity: 1;
4174
3976
  }
4175
3977
 
4176
- .uvf-player-wrapper.uvf-material-you-mobile .uvf-control-btn:active {
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-player-wrapper.uvf-material-you-mobile .uvf-control-btn.play-pause {
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-player-wrapper.uvf-material-you-mobile .uvf-control-btn.play-pause:active {
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-player-wrapper.uvf-material-you-mobile .uvf-controls-row {
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-player-wrapper.uvf-material-you-mobile .uvf-time-display {
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
- /* Double-tap overlay indicators */
4225
- .uvf-doubletap-indicator {
4226
- position: absolute;
4227
- top: 50%;
4228
- transform: translateY(-50%);
4229
- width: 80px;
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
- .uvf-player-wrapper.uvf-material-you-mobile #uvf-settings-btn {
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.setupMaterialYouGestures(wrapper);
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
- const activating = settingsMenu.classList.contains('active');
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') && !this.isSettingsOpen) {
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(() => {