@ray-js/ipc-player-integration 0.0.50-beta.5 → 0.0.50
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.
- package/lib/ui/bottomLeftContent.js +69 -26
- package/lib/ui/bottomRightContent.js +3 -1
- package/lib/ui/ui.js +11 -4
- package/lib/ui/ui.less +25 -1
- package/package.json +1 -1
|
@@ -27,6 +27,12 @@ const VERTICAL_PEEK_WIDTH = 34;
|
|
|
27
27
|
// 平铺档内容与右下角按钮之间的最小安全间距
|
|
28
28
|
const VERTICAL_FLAT_SAFE_GAP = 8;
|
|
29
29
|
|
|
30
|
+
// 收紧态(.ipc-player-bottom-left-content-container-tight)下每项省下的宽度:
|
|
31
|
+
// 竖屏 item 左右 padding 由 12px 收到 10px,中间项左右各省 2px;
|
|
32
|
+
// 首项只省右侧 2px —— 左侧 16px 是内容起始留白,要和其余三个角落对齐,不能动。
|
|
33
|
+
const TIGHT_SAVE_FIRST = 2;
|
|
34
|
+
const TIGHT_SAVE_OTHER = 4;
|
|
35
|
+
|
|
30
36
|
// 左下角子元素统一类名(由 ui.tsx 渲染时挂上),用于 selectAll 逐项测量
|
|
31
37
|
const ITEM_CLASS = 'bottom-left-item-container';
|
|
32
38
|
const BottomLeftContent = _ref => {
|
|
@@ -113,13 +119,16 @@ const BottomLeftContent = _ref => {
|
|
|
113
119
|
// 这类变化 bottomLeftContent.length 捕获不到,由 widget 主动 emit。
|
|
114
120
|
const [resizeSignal, setResizeSignal] = useState(0);
|
|
115
121
|
|
|
122
|
+
// 是否收紧 item 间距(窄屏专用,判定见下方 useEffect)。
|
|
123
|
+
// 只升不降:收紧后各项变窄 → 重测 → 可能又判成“放得下”→ 取消收紧 → 又放不下,
|
|
124
|
+
// 那就是一个自激振荡。锁存住,只在横竖屏切换时随其余测量值一起清零。
|
|
125
|
+
const [tightened, setTightened] = useState(false);
|
|
126
|
+
|
|
116
127
|
// 滑动期间暂停整体的自动隐藏,滑动停止后再恢复(无原生 scrollend,用防抖判定结束)
|
|
117
128
|
const scrollingRef = useRef(false);
|
|
118
129
|
const scrollEndTimerRef = useRef();
|
|
119
130
|
// 测量时需要叠加当前滚动量,用 ref 避免闭包拿到过期值
|
|
120
131
|
const scrollLeftRef = useRef(0);
|
|
121
|
-
// 仅用于在可见项数变化时打一条日志,便于真机核对分档结果
|
|
122
|
-
const lastCountRef = useRef(-1);
|
|
123
132
|
useEffect(() => {
|
|
124
133
|
setScrollResetKey(k => k + 1);
|
|
125
134
|
setScrollLeft(0);
|
|
@@ -130,6 +139,7 @@ const BottomLeftContent = _ref => {
|
|
|
130
139
|
setContentWidth(0);
|
|
131
140
|
setWrapWidth(0);
|
|
132
141
|
setItemWidths([]);
|
|
142
|
+
setTightened(false);
|
|
133
143
|
}, [screenType]);
|
|
134
144
|
|
|
135
145
|
// 程序化滚动目标只在动画期间短暂受控,之后释放为非受控,避免回弹影响手动拖动
|
|
@@ -168,11 +178,13 @@ const BottomLeftContent = _ref => {
|
|
|
168
178
|
// 避免估算失准把本来放得下的元素裁掉。
|
|
169
179
|
const isFlat = isVertical && (measuredCount > 0 ? measuredCount <= VERTICAL_FLAT_MAX && contentFits : contentFits);
|
|
170
180
|
const isCompact = isVertical && !isFlat && measuredCount > 0 && measuredCount <= VERTICAL_FLAT_MAX;
|
|
181
|
+
const isScrollMode = isVertical && !isFlat && !isCompact;
|
|
182
|
+
|
|
171
183
|
// 前 4 项实际累计宽(元素按自身内容撑开,不做等分)
|
|
172
184
|
const firstFourWidth = itemWidths.slice(0, VERTICAL_FLAT_MAX).reduce((sum, w) => sum + w, 0);
|
|
173
185
|
// 滚动档可视宽 = 前 4 项宽 + 第 5 项的露出区(箭头就压在这段上)
|
|
174
186
|
const verticalScrollWidth = (() => {
|
|
175
|
-
if (!
|
|
187
|
+
if (!isScrollMode || measuredCount === 0) return 0;
|
|
176
188
|
const want = firstFourWidth + VERTICAL_PEEK_WIDTH;
|
|
177
189
|
if (!(availableWidth > 0)) return want;
|
|
178
190
|
// 前 4 项 + 露出区塞不下 —— 前 4 项里有宽 widget(焦距转盘的倍率胶囊、清晰度文案)时很常见。
|
|
@@ -180,7 +192,48 @@ const BottomLeftContent = _ref => {
|
|
|
180
192
|
if (want > availableWidth) return 0;
|
|
181
193
|
return want;
|
|
182
194
|
})();
|
|
183
|
-
|
|
195
|
+
/**
|
|
196
|
+
* 收紧后前 4 项能省下多少(估算:按每项的 padding 差值累加)。
|
|
197
|
+
* 逐项宽是实测值,收紧后的真实宽度未必精确等于这个差值,作为“够不够”的预判足够。
|
|
198
|
+
*/
|
|
199
|
+
const tightenSaving = (() => {
|
|
200
|
+
const n = Math.min(measuredCount, VERTICAL_FLAT_MAX);
|
|
201
|
+
if (n <= 0) return 0;
|
|
202
|
+
return TIGHT_SAVE_FIRST + TIGHT_SAVE_OTHER * (n - 1);
|
|
203
|
+
})();
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 是否要把 item 间距从 12px 收到 10px。
|
|
207
|
+
*
|
|
208
|
+
* 两头都不收:
|
|
209
|
+
* - **本来就放得下**(宽屏):不动,保持 12px 的宽松间距 —— 不为个别窄屏机型
|
|
210
|
+
* 让全量机型的图标挤在一起;
|
|
211
|
+
* - **收紧了也放不下**(更窄的屏 / 3 镜头的转盘胶囊):白挤一遍换不回箭头的
|
|
212
|
+
* 专属落位区,不如保住观感,让箭头压在第 4 项右缘上(见下方 hasArrowRoom)。
|
|
213
|
+
*
|
|
214
|
+
* 只有“差一点、收紧刚好够”这一段才收 —— 这正是真机上遇到的那一档。
|
|
215
|
+
*/
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (tightened) return;
|
|
218
|
+
if (!isScrollMode || measuredCount === 0 || !(availableWidth > 0)) return;
|
|
219
|
+
const want = firstFourWidth + VERTICAL_PEEK_WIDTH;
|
|
220
|
+
if (want <= availableWidth) return;
|
|
221
|
+
if (want - tightenSaving > availableWidth) return;
|
|
222
|
+
setTightened(true);
|
|
223
|
+
}, [tightened, isScrollMode, measuredCount, availableWidth, firstFourWidth, tightenSaving]);
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 竖屏 scroll 档一律出箭头。
|
|
227
|
+
*
|
|
228
|
+
* 曾要求「锁宽成功(verticalScrollWidth > 0)才出箭头」,理由是没锁宽时箭头会盖到前 4 项上。
|
|
229
|
+
* 真机上这条判断反而更糟:前 4 项里有宽 widget(焦距转盘胶囊 2 镜头约 100px、
|
|
230
|
+
* 3 镜头约 138px)时,`前 4 项 + 34` 很容易超过可用宽,于是箭头连同窄渐变一起消失 ——
|
|
231
|
+
* 右边还藏着两三个 widget,却没有任何可滑提示(6 个 widget、可用宽 256、内容宽 359 的实测 case)。
|
|
232
|
+
*
|
|
233
|
+
* 宁可让箭头压在第 4 项右缘那 26px 上:那块本来就落在淡出渐变里,
|
|
234
|
+
* 观感是「内容淡出 + 箭头」,正好是「右边还有」的暗示。
|
|
235
|
+
* 想既保住前 4 项完整、又给箭头留出专属位,在窄屏上物理上做不到。
|
|
236
|
+
*/
|
|
184
237
|
|
|
185
238
|
// 滚动末端的安全距离:滑到最右时最后一个元素与右边缘留更宽松的间距(横屏更宽)。
|
|
186
239
|
// 只有真正锁宽滚动的那一档需要;平铺 / 紧凑 / 塞不下而没锁宽的情况,
|
|
@@ -230,10 +283,6 @@ const BottomLeftContent = _ref => {
|
|
|
230
283
|
}
|
|
231
284
|
if (Array.isArray(itemRects)) {
|
|
232
285
|
const widths = itemRects.map(r => (r === null || r === void 0 ? void 0 : r.width) || 0).filter(w => w > 0);
|
|
233
|
-
if (widths.length !== lastCountRef.current) {
|
|
234
|
-
lastCountRef.current = widths.length;
|
|
235
|
-
console.log('[ipc-player] 左下角可见 widget 数 =', widths.length, widths);
|
|
236
|
-
}
|
|
237
286
|
// 值没变时保持同一引用,避免轮询期间无谓重渲染
|
|
238
287
|
setItemWidths(prev => prev.length === widths.length && prev.every((w, i) => w === widths[i]) ? prev : widths);
|
|
239
288
|
}
|
|
@@ -271,7 +320,9 @@ const BottomLeftContent = _ref => {
|
|
|
271
320
|
// reservedRight 决定 ScrollView 可视宽度(右下角内容异步加载后会从 0 变为实际宽度)
|
|
272
321
|
reservedRight,
|
|
273
322
|
// playState:视频就绪后 overlay 可能重新布局,需重新测量
|
|
274
|
-
playState, bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.length, shouldHide, showBadge, wrapCls, scrollCls, contentCls, scrollResetKey, resizeSignal
|
|
323
|
+
playState, bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.length, shouldHide, showBadge, wrapCls, scrollCls, contentCls, scrollResetKey, resizeSignal,
|
|
324
|
+
// 收紧后各项 padding 变小,必须重测一遍逐项宽,否则分档还在用收紧前的旧值
|
|
325
|
+
tightened]);
|
|
275
326
|
|
|
276
327
|
// 子元素主动上报宽度变化 → 重跑测量,及时更新横滑箭头与右边缘淡出
|
|
277
328
|
useEffect(() => {
|
|
@@ -337,19 +388,6 @@ const BottomLeftContent = _ref => {
|
|
|
337
388
|
if (!(availableWidth > 0) || !(scrollViewWidth > 0)) return 4;
|
|
338
389
|
return Math.max(availableWidth - scrollViewWidth + 4, 4);
|
|
339
390
|
})();
|
|
340
|
-
|
|
341
|
-
// 真机核对分档结果用,确认无误后可摘掉
|
|
342
|
-
useEffect(() => {
|
|
343
|
-
if (!isVertical) return;
|
|
344
|
-
console.log('[ipc-player] 左下角分档', {
|
|
345
|
-
个数: measuredCount,
|
|
346
|
-
档位: isFlat ? 'flat 平铺' : isCompact ? 'compact 紧凑' : 'scroll 滚动',
|
|
347
|
-
可用宽: availableWidth,
|
|
348
|
-
内容宽: naturalWidth,
|
|
349
|
-
可视宽: verticalScrollWidth || availableWidth,
|
|
350
|
-
逐项宽: itemWidths
|
|
351
|
-
});
|
|
352
|
-
}, [isVertical, measuredCount, isFlat, isCompact, availableWidth, naturalWidth, verticalScrollWidth, itemWidths]);
|
|
353
391
|
return /*#__PURE__*/React.createElement(CoverView, {
|
|
354
392
|
className: clsx('ipc-player-bottom-left-content-wrap', wrapCls),
|
|
355
393
|
style: {
|
|
@@ -408,8 +446,11 @@ const BottomLeftContent = _ref => {
|
|
|
408
446
|
},
|
|
409
447
|
className: clsx(scrollCls, {
|
|
410
448
|
'ipc-player-bottom-left-scroll-fademask': fadeRightEdge,
|
|
411
|
-
//
|
|
412
|
-
|
|
449
|
+
// 竖屏 scroll 档一律用窄渐变(34px,只覆盖箭头那块)。
|
|
450
|
+
// 原条件是「锁宽成功」,可没锁宽时可视区右缘同样压着第 4 项,
|
|
451
|
+
// 72px 的宽渐变会把宽 widget(转盘胶囊约 100px)淡掉一大半。
|
|
452
|
+
// 横屏 isScrollMode 恒为 false,仍走 72px 宽渐变,行为不变。
|
|
453
|
+
'ipc-player-bottom-left-scroll-fademask--narrow': fadeRightEdge && isScrollMode
|
|
413
454
|
}),
|
|
414
455
|
style: {
|
|
415
456
|
paddingBottom: `${paddingBottomPx}px`,
|
|
@@ -421,7 +462,9 @@ const BottomLeftContent = _ref => {
|
|
|
421
462
|
whiteSpace: 'nowrap'
|
|
422
463
|
}
|
|
423
464
|
}, /*#__PURE__*/React.createElement(View, {
|
|
424
|
-
className: clsx('ipc-player-bottom-left-content-container', contentCls
|
|
465
|
+
className: clsx('ipc-player-bottom-left-content-container', contentCls, {
|
|
466
|
+
'ipc-player-bottom-left-content-container-tight': tightened
|
|
467
|
+
}),
|
|
425
468
|
style: {
|
|
426
469
|
display: 'inline-flex',
|
|
427
470
|
flexDirection: 'row',
|
|
@@ -436,7 +479,7 @@ const BottomLeftContent = _ref => {
|
|
|
436
479
|
height: '1px',
|
|
437
480
|
flexShrink: 0
|
|
438
481
|
}
|
|
439
|
-
}))), isOverflow && !atEnd && !isCompact && (!isVertical ||
|
|
482
|
+
}))), isOverflow && !atEnd && !isCompact && (!isVertical || isScrollMode) && (isButtonHint || !isDismissed) && /*#__PURE__*/React.createElement(CoverView, {
|
|
440
483
|
className: clsx('ipc-player-bottom-left-scroll-hint', {
|
|
441
484
|
'ipc-player-bottom-left-scroll-hint--button': isButtonHint
|
|
442
485
|
}),
|
|
@@ -69,7 +69,9 @@ const BottomRightContent = _ref => {
|
|
|
69
69
|
return /*#__PURE__*/React.createElement(CoverView, {
|
|
70
70
|
className: clsx('ipc-player-bottom-right-content-wrap', wrapCls),
|
|
71
71
|
style: _objectSpread({
|
|
72
|
-
|
|
72
|
+
// 竖屏归 0:这 10px 是纯空白,且计入实测宽后又被 reservedRight 带给左下角,
|
|
73
|
+
// 等于左下角白让 10px。与右下角按钮的间距统一由 BOTTOM_RIGHT_SAFE_GAP 负责。
|
|
74
|
+
paddingLeft: '0',
|
|
73
75
|
height: screenType === 'vertical' ? shouldHide ? '49px' : '48px' : shouldHide ? '59px' : '58px'
|
|
74
76
|
}, widthStyle)
|
|
75
77
|
}, /*#__PURE__*/React.createElement(View, {
|
package/lib/ui/ui.js
CHANGED
|
@@ -59,7 +59,10 @@ const SET_SCALE_ALIGN_TIMEOUT = 1500;
|
|
|
59
59
|
const SCALE_MATCH_EPS = 0.01;
|
|
60
60
|
|
|
61
61
|
/** 竖屏左下角内容与右下角按钮之间的安全间距(px) */
|
|
62
|
-
|
|
62
|
+
// 左下角内容右缘与右下角按钮之间的安全间距。
|
|
63
|
+
// 原为 12px:右下角 wrap 当时还带 10px paddingLeft,两段叠起来是 22px 空白,窄屏上太奢侈。
|
|
64
|
+
// paddingLeft 已归 0,这里收到 4px —— 右下角按钮自身还有 16px 的右留白撑着,不会显挤。
|
|
65
|
+
const BOTTOM_RIGHT_SAFE_GAP = 4;
|
|
63
66
|
export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
64
67
|
const {
|
|
65
68
|
className,
|
|
@@ -803,13 +806,17 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
803
806
|
if (screenType === 'full') {
|
|
804
807
|
return bottomRightWidth;
|
|
805
808
|
}
|
|
809
|
+
// 安卓上 CoverView 的 boundingClientRect 可能一直测不出宽度,轮询跑完仍是 0
|
|
810
|
+
if (!(bottomRightMeasuredWidth > 0)) {
|
|
811
|
+
return bottomRightWidth;
|
|
812
|
+
}
|
|
806
813
|
// 封顶保护:个别宿主里不设宽度的 CoverView 可能撑满整行,实测值会异常放大,
|
|
807
814
|
// 那样左下角会被挤没。超过屏宽一半就当测量不可信,退回常量估算。
|
|
808
815
|
const maxReserved = windowWidthRef.current ? windowWidthRef.current / 2 : 0;
|
|
809
|
-
if (
|
|
810
|
-
return
|
|
816
|
+
if (maxReserved && bottomRightMeasuredWidth > maxReserved) {
|
|
817
|
+
return bottomRightWidth;
|
|
811
818
|
}
|
|
812
|
-
return
|
|
819
|
+
return Math.ceil(bottomRightMeasuredWidth) + BOTTOM_RIGHT_SAFE_GAP;
|
|
813
820
|
}, [screenType, bottomRightWidth, bottomRightMeasuredWidth]);
|
|
814
821
|
|
|
815
822
|
/**
|
package/lib/ui/ui.less
CHANGED
|
@@ -311,7 +311,7 @@
|
|
|
311
311
|
padding: 0 16px 0 0;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
//
|
|
314
|
+
// 左下角子元素容器(竖屏;横屏另叠 .bottom-left-item-full-container 且带 !important)
|
|
315
315
|
.bottom-left-item-container {
|
|
316
316
|
padding: 0 12px;
|
|
317
317
|
display: flex;
|
|
@@ -334,6 +334,30 @@
|
|
|
334
334
|
padding: 0 0 0 16px;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
// 收紧态:左右各 10px(默认 12px)。
|
|
338
|
+
//
|
|
339
|
+
// 只有窄屏上「前 4 项 + 34 露出区」放不下、且收紧后刚好放得下时才挂这个类
|
|
340
|
+
// (判定见 bottomLeftContent.tsx 的 tightened)。宽屏本来就放得下,
|
|
341
|
+
// 保持 12px 的宽松间距,不为个别机型让全量机型变紧。
|
|
342
|
+
//
|
|
343
|
+
// 中间项左右各省 2px = 4px;首项只省右侧 2px —— 左侧 16px 是内容起始留白,
|
|
344
|
+
// 要和其余三个角落对齐,不能动。10px 是不显挤的下限。
|
|
345
|
+
//
|
|
346
|
+
// 横屏叠的 .bottom-left-item-full-container 带 !important,优先级更高,不受影响。
|
|
347
|
+
.ipc-player-bottom-left-content-container-tight {
|
|
348
|
+
.bottom-left-item-container {
|
|
349
|
+
padding: 0 10px;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.bottom-left-item-container:first-of-type {
|
|
353
|
+
padding: 0 10px 0 16px;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.bottom-left-item-container:last-of-type {
|
|
357
|
+
padding: 0 0 0 10px;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
337
361
|
// 左下角全屏子元素容器
|
|
338
362
|
.bottom-left-item-full-container {
|
|
339
363
|
padding: 0 16px !important;
|