@ray-js/ipc-player-integration 0.0.49 → 0.0.50-beta.1

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.
Files changed (55) hide show
  1. package/lib/ctx/ctx.composition.js +6 -1
  2. package/lib/ctx/ctx.js +11 -1
  3. package/lib/features/initPlayerWidgets/index.d.ts +5 -0
  4. package/lib/features/initPlayerWidgets/index.js +12 -0
  5. package/lib/i18n/index.d.ts +8 -0
  6. package/lib/i18n/strings.d.ts +4 -0
  7. package/lib/i18n/strings.js +4 -0
  8. package/lib/interface.d.ts +9 -1
  9. package/lib/ui/bottomLeftContent.js +23 -8
  10. package/lib/ui/constant.d.ts +10 -0
  11. package/lib/ui/constant.js +12 -1
  12. package/lib/ui/ui.js +78 -4
  13. package/lib/ui/ui.less +15 -0
  14. package/lib/utils/content/dpCode.d.ts +1 -0
  15. package/lib/utils/content/dpCode.js +5 -1
  16. package/lib/utils/storage/index.d.ts +2 -2
  17. package/lib/widgets/index.d.ts +1 -0
  18. package/lib/widgets/index.js +2 -1
  19. package/lib/widgets/realTimeMagnification/realTimeMagnification.js +18 -1
  20. package/lib/widgets/toggleVerticalFull/toggleVerticalFull.less +1 -1
  21. package/lib/widgets/zoomTurntable/constants.d.ts +92 -0
  22. package/lib/widgets/zoomTurntable/constants.js +148 -0
  23. package/lib/widgets/zoomTurntable/entryAnchor.d.ts +7 -0
  24. package/lib/widgets/zoomTurntable/entryAnchor.js +7 -0
  25. package/lib/widgets/zoomTurntable/index.d.ts +8 -0
  26. package/lib/widgets/zoomTurntable/index.js +8 -0
  27. package/lib/widgets/zoomTurntable/lensModel.d.ts +53 -0
  28. package/lib/widgets/zoomTurntable/lensModel.js +137 -0
  29. package/lib/widgets/zoomTurntable/lensModel.test.d.ts +1 -0
  30. package/lib/widgets/zoomTurntable/lensModel.test.js +336 -0
  31. package/lib/widgets/zoomTurntable/lensSkill.d.ts +89 -0
  32. package/lib/widgets/zoomTurntable/lensSkill.js +332 -0
  33. package/lib/widgets/zoomTurntable/measureVisible.d.ts +22 -0
  34. package/lib/widgets/zoomTurntable/measureVisible.js +76 -0
  35. package/lib/widgets/zoomTurntable/turntable/index.d.ts +10 -0
  36. package/lib/widgets/zoomTurntable/turntable/index.js +76 -0
  37. package/lib/widgets/zoomTurntable/turntable/index.less +11 -0
  38. package/lib/widgets/zoomTurntable/turntable/rjs/index.js +242 -0
  39. package/lib/widgets/zoomTurntable/turntable/rjs/index.json +3 -0
  40. package/lib/widgets/zoomTurntable/turntable/rjs/index.rjs +691 -0
  41. package/lib/widgets/zoomTurntable/turntable/rjs/index.tyml +7 -0
  42. package/lib/widgets/zoomTurntable/turntable/type.d.ts +95 -0
  43. package/lib/widgets/zoomTurntable/turntable/type.js +1 -0
  44. package/lib/widgets/zoomTurntable/useLensZoom.d.ts +34 -0
  45. package/lib/widgets/zoomTurntable/useLensZoom.js +421 -0
  46. package/lib/widgets/zoomTurntable/zoomTurntableDock.d.ts +17 -0
  47. package/lib/widgets/zoomTurntable/zoomTurntableDock.js +228 -0
  48. package/lib/widgets/zoomTurntable/zoomTurntableDock.less +11 -0
  49. package/lib/widgets/zoomTurntable/zoomTurntableEntry.d.ts +18 -0
  50. package/lib/widgets/zoomTurntable/zoomTurntableEntry.js +253 -0
  51. package/lib/widgets/zoomTurntable/zoomTurntableEntry.less +51 -0
  52. package/lib/widgets/zoomTurntable/zoomTurntableTip.d.ts +16 -0
  53. package/lib/widgets/zoomTurntable/zoomTurntableTip.js +76 -0
  54. package/lib/widgets/zoomTurntable/zoomTurntableTip.less +56 -0
  55. package/package.json +3 -3
@@ -4,7 +4,7 @@ const _excluded = ["title", "duration"];
4
4
  import { getCameraConfigInfo } from '@ray-js/ray-ipc-utils';
5
5
  import { IntercomMode, MuteMode, ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
6
6
  import { createUseCtx } from './ctx';
7
- import { FullSmallIntercom, VerticalSmallIntercom, BatteryFull, Battery, Screenshot, TempHumidity, Signal4G, RecordVideo, FullScreen, VideoBitKBP, Muted, Floodlight, Siren, TryExperience, Resolution, Ptz, MultiPtz, TileTip, PtzMoveableTip, LandscapeTip, TileActions, MoveablePtzControl, SwitchLayout, ToggleVerticalFull, RealTimeMagnification } from '../widgets';
7
+ import { FullSmallIntercom, VerticalSmallIntercom, BatteryFull, Battery, Screenshot, TempHumidity, Signal4G, RecordVideo, FullScreen, VideoBitKBP, Muted, Floodlight, Siren, TryExperience, Resolution, Ptz, MultiPtz, TileTip, PtzMoveableTip, LandscapeTip, TileActions, MoveablePtzControl, SwitchLayout, ToggleVerticalFull, RealTimeMagnification, ZoomTurntableEntry } from '../widgets';
8
8
  import { authorizeStatus } from '../utils/authorize';
9
9
  import { landscapeTipId, moveablePtzControlId, multiPtzId, ptzMoveableTipId, tileActionsId, tileTipId } from '../ui/constant';
10
10
  import { multiPrefix } from '../widgets/multiCamera/constants';
@@ -68,6 +68,11 @@ export const defaultBottomLeftContent = [{
68
68
  id: 'RealTimeMagnification',
69
69
  content: RealTimeMagnification,
70
70
  hidden: true
71
+ }, /* 焦距转盘入口:仅多镜头设备(ipc_multi_zoom 上报值 cnt > 1)会真正渲染 */
72
+ {
73
+ id: 'ZoomTurntableEntry',
74
+ content: ZoomTurntableEntry,
75
+ hidden: true
71
76
  }];
72
77
  export const defaultBottomRightContent = [{
73
78
  id: 'SwitchLayout',
package/lib/ctx/ctx.js CHANGED
@@ -81,6 +81,12 @@ export const createUseCtx = _ref => {
81
81
  // 最大缩放倍数
82
82
  const [maxZoomSettings, setMaxZoomSettings] = useAtom(6);
83
83
 
84
+ // 多镜头变焦能力(zoom_skill),null 表示不支持 / 尚未拉到;由 ZoomTurntableEntry 写入
85
+ const [zoomSkill, setZoomSkill] = useAtom(null);
86
+
87
+ // 当前使用的物理镜头下标,用于双层缩放换算(curM = lens.value + (d-1) * Δ)
88
+ const [zoomLensIndex, setZoomLensIndex] = useAtom(0);
89
+
84
90
  // 对讲中
85
91
  const [intercom] = useAtom(false);
86
92
  const [playState] = useAtom(PlayState.CONNECTING);
@@ -268,6 +274,10 @@ export const createUseCtx = _ref => {
268
274
  intercomMode,
269
275
  intercomSupported,
270
276
  maxZoomSettings,
277
+ zoomSkill,
278
+ setZoomSkill,
279
+ zoomLensIndex,
280
+ setZoomLensIndex,
271
281
  playState,
272
282
  setPlayState,
273
283
  setPtzControlTipDisabled,
@@ -505,7 +515,7 @@ export const createUseCtx = _ref => {
505
515
  } else if (type === 'bottomLeft') {
506
516
  updateAtom(bottomLeftContent, prevValue => prevValue.filter(item => item.id !== id));
507
517
  } else if (type === 'bottomRight') {
508
- updateAtom(bottomLeftContent, prevValue => prevValue.filter(item => item.id !== id));
518
+ updateAtom(bottomRightContent, prevValue => prevValue.filter(item => item.id !== id));
509
519
  } else {
510
520
  updateAtom(absoluteContent, prevValue => prevValue.filter(item => item.id !== id));
511
521
  }
@@ -12,6 +12,11 @@ export type InitPlayerWidgetsOptions = {
12
12
  hideSignalMenu?: boolean;
13
13
  showToggleVerticalFull?: boolean;
14
14
  showRealTimeMagnification?: boolean;
15
+ /**
16
+ * 允许展示焦距转盘入口(长按图标弹出转盘)。
17
+ * 仅为功能开关;实际渲染还要 ipc_multi_zoom 解析出 cnt > 1,单镜头设备传 true 也不出现。
18
+ */
19
+ showZoomTurntable?: boolean;
15
20
  directionControlProps?: Partial<React.ComponentProps<typeof FullScreen>['directionControlProps']>;
16
21
  hideSmartImageQualityState?: boolean;
17
22
  topLeftContent?: ComponentConfig[];
@@ -52,6 +52,18 @@ export async function initPlayerWidgets(ctx, options) {
52
52
  newDefaultBottomLeftContent[magnificationIndex].hidden = false;
53
53
  }
54
54
  }
55
+ // 焦距转盘入口:这里只放开占位,真正是否渲染由 widget 内部按
56
+ // ipc_multi_zoom 上报值解析出的 cnt > 1 决定(单镜头设备不出现)
57
+ if (options.showZoomTurntable) {
58
+ const zoomTurntableIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'ZoomTurntableEntry');
59
+ if (zoomTurntableIndex !== -1) {
60
+ newDefaultBottomLeftContent[zoomTurntableIndex].hidden = false;
61
+ // @ts-ignore
62
+ newDefaultBottomLeftContent[zoomTurntableIndex].initProps = {
63
+ showZoomTurntable: true
64
+ };
65
+ }
66
+ }
55
67
  ctx.addContent('bottomLeft', newDefaultBottomLeftContent);
56
68
  const newDefaultBottomRightContent = _cloneDeep(options.bottomRightContent || defaultBottomRightContent);
57
69
  const fullScreenIndex = newDefaultBottomRightContent.findIndex(item => item.id === 'FullScreen');
@@ -28,6 +28,8 @@ declare const Strings: kit.I18N<{
28
28
  ipc_player_tip_next: string;
29
29
  ipc_player_tip_confirm: string;
30
30
  ipc_player_ptz_moveable_tip_text: string;
31
+ ipc_player_zoom_turntable_tip_text: string;
32
+ ipc_player_zoom_turntable_switch_failed: string;
31
33
  ipc_player_flow_low_tip: string;
32
34
  ipc_player_trial_in_use: string;
33
35
  ipc_player_trial_preview_text: string;
@@ -63,6 +65,8 @@ declare const Strings: kit.I18N<{
63
65
  ipc_player_tip_next: string;
64
66
  ipc_player_tip_confirm: string;
65
67
  ipc_player_ptz_moveable_tip_text: string;
68
+ ipc_player_zoom_turntable_tip_text: string;
69
+ ipc_player_zoom_turntable_switch_failed: string;
66
70
  ipc_player_flow_low_tip: string;
67
71
  ipc_player_trial_in_use: string;
68
72
  ipc_player_trial_preview_text: string;
@@ -98,6 +102,8 @@ declare const Strings: kit.I18N<{
98
102
  ipc_player_tip_next: string;
99
103
  ipc_player_tip_confirm: string;
100
104
  ipc_player_ptz_moveable_tip_text: string;
105
+ ipc_player_zoom_turntable_tip_text: string;
106
+ ipc_player_zoom_turntable_switch_failed: string;
101
107
  ipc_player_flow_low_tip: string;
102
108
  ipc_player_trial_in_use: string;
103
109
  ipc_player_trial_preview_text: string;
@@ -132,6 +138,8 @@ declare const Strings: kit.I18N<{
132
138
  ipc_player_tip_next: string;
133
139
  ipc_player_tip_confirm: string;
134
140
  ipc_player_ptz_moveable_tip_text: string;
141
+ ipc_player_zoom_turntable_tip_text: string;
142
+ ipc_player_zoom_turntable_switch_failed: string;
135
143
  ipc_player_flow_low_tip: string;
136
144
  ipc_player_trial_in_use: string;
137
145
  ipc_player_trial_preview_text: string;
@@ -27,6 +27,8 @@ declare const _default: {
27
27
  ipc_player_tip_next: string;
28
28
  ipc_player_tip_confirm: string;
29
29
  ipc_player_ptz_moveable_tip_text: string;
30
+ ipc_player_zoom_turntable_tip_text: string;
31
+ ipc_player_zoom_turntable_switch_failed: string;
30
32
  ipc_player_flow_low_tip: string;
31
33
  ipc_player_trial_in_use: string;
32
34
  ipc_player_trial_preview_text: string;
@@ -62,6 +64,8 @@ declare const _default: {
62
64
  ipc_player_tip_next: string;
63
65
  ipc_player_tip_confirm: string;
64
66
  ipc_player_ptz_moveable_tip_text: string;
67
+ ipc_player_zoom_turntable_tip_text: string;
68
+ ipc_player_zoom_turntable_switch_failed: string;
65
69
  ipc_player_flow_low_tip: string;
66
70
  ipc_player_trial_in_use: string;
67
71
  ipc_player_trial_preview_text: string;
@@ -27,6 +27,8 @@ export default {
27
27
  ipc_player_tip_next: 'Next',
28
28
  ipc_player_tip_confirm: 'Got it',
29
29
  ipc_player_ptz_moveable_tip_text: 'Hold the middle to drag the direction control area',
30
+ ipc_player_zoom_turntable_tip_text: 'Press and hold here to switch zoom',
31
+ ipc_player_zoom_turntable_switch_failed: 'Failed to switch lens. Please try again.',
30
32
  ipc_player_flow_low_tip: 'The device’s remaining data is below 200MB. Please recharge as soon as possible.',
31
33
  ipc_player_trial_in_use: 'Trial',
32
34
  ipc_player_trial_preview_text: 'End',
@@ -62,6 +64,8 @@ export default {
62
64
  ipc_player_tip_next: '下一步',
63
65
  ipc_player_tip_confirm: '知道了',
64
66
  ipc_player_ptz_moveable_tip_text: '长按中间可拖动方向控制区域',
67
+ ipc_player_zoom_turntable_tip_text: '长按此处可切换焦距',
68
+ ipc_player_zoom_turntable_switch_failed: '切换镜头失败,请重试',
65
69
  ipc_player_flow_low_tip: '设备当前剩余流量不足200M,请尽快充值',
66
70
  ipc_player_trial_in_use: '试用中',
67
71
  ipc_player_trial_preview_text: '后结束',
@@ -2,7 +2,9 @@ import React from 'react';
2
2
  import { PrimitiveAtom } from 'jotai';
3
3
  import type { Toast, IntercomMode } from './ports.output';
4
4
  import { useMultiCameraCtx } from './ctx/multiCameraCtx';
5
+ import type { ZoomSkill } from './widgets/zoomTurntable/lensSkill';
5
6
  export { IntercomMode } from './ports.output';
7
+ export type { ZoomSkill, Lens } from './widgets/zoomTurntable/lensSkill';
6
8
  type WithInitialValue<Value> = {
7
9
  init: Value;
8
10
  };
@@ -11,7 +13,7 @@ export type IpcContext = {
11
13
  };
12
14
  export type RetAtom<T> = PrimitiveAtom<T> & WithInitialValue<T>;
13
15
  export type ScreenType = 'full' | 'vertical';
14
- export type WidgetId = 'BatteryFull' | 'TempHumidity' | 'VideoBitKBP' | 'FullSmallIntercom' | 'Screenshot' | 'RecordVideo' | 'Muted' | 'Floodlight' | 'Siren' | 'TryExperience' | 'VerticalSmallIntercom' | 'Ptz' | 'Resolution' | 'FullScreen' | 'moveablePtzControlId';
16
+ export type WidgetId = 'BatteryFull' | 'TempHumidity' | 'VideoBitKBP' | 'FullSmallIntercom' | 'Screenshot' | 'RecordVideo' | 'Muted' | 'Floodlight' | 'Siren' | 'TryExperience' | 'VerticalSmallIntercom' | 'Ptz' | 'Resolution' | 'FullScreen' | 'RealTimeMagnification' | 'ZoomTurntableEntry' | 'moveablePtzControlId';
15
17
  export declare const enum PlayerStreamStatus {
16
18
  UnknownException = -1000,
17
19
  ConnectSuccess = 1001,
@@ -62,6 +64,12 @@ export type UseCtx = (options: {
62
64
  intercomMode: RetAtom<IntercomMode>;
63
65
  intercomSupported: RetAtom<boolean>;
64
66
  maxZoomSettings: RetAtom<number>;
67
+ /** 多镜头变焦能力(zoom_skill);null 表示不支持 / 尚未拉到 */
68
+ zoomSkill: RetAtom<ZoomSkill | null>;
69
+ setZoomSkill: (value: ZoomSkill | null) => void;
70
+ /** 当前使用的物理镜头下标 */
71
+ zoomLensIndex: RetAtom<number>;
72
+ setZoomLensIndex: (value: number) => void;
65
73
  resolution: RetAtom<string>;
66
74
  resolutionList: RetAtom<string[]>;
67
75
  playState: RetAtom<PlayState>;
@@ -7,7 +7,7 @@ import clsx from 'clsx';
7
7
  import { useStore } from '../ctx/store';
8
8
  import { useComponentHideState } from './hooks';
9
9
  import { TrialBadge, useTrialBadge } from '../widgets/trialBadge';
10
- import { pauseTimeToHideAllComponent, startTimeToHideAllComponent } from './constant';
10
+ import { bottomLeftContentResize, pauseTimeToHideAllComponent, startTimeToHideAllComponent } from './constant';
11
11
 
12
12
  // 用唯一 className 在 createSelectorQuery 中区分多个实例,避免互相干扰
13
13
  let scrollClsSeq = 0;
@@ -85,6 +85,10 @@ const BottomLeftContent = _ref => {
85
85
  full: false
86
86
  });
87
87
 
88
+ // 子元素自身显隐变化(widget 数量不变、但内部从 return null 变为渲染)时的重测信号。
89
+ // 这类变化 bottomLeftContent.length 捕获不到,由 widget 主动 emit。
90
+ const [resizeSignal, setResizeSignal] = useState(0);
91
+
88
92
  // 滑动期间暂停整体的自动隐藏,滑动停止后再恢复(无原生 scrollend,用防抖判定结束)
89
93
  const scrollingRef = useRef(false);
90
94
  const scrollEndTimerRef = useRef();
@@ -173,7 +177,18 @@ const BottomLeftContent = _ref => {
173
177
  // reservedRight 决定 ScrollView 可视宽度(右下角内容异步加载后会从 0 变为实际宽度)
174
178
  reservedRight,
175
179
  // playState:视频就绪后 overlay 可能重新布局,需重新测量
176
- playState, bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.length, shouldHide, showBadge, scrollCls, contentCls, scrollResetKey]);
180
+ playState, bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.length, shouldHide, showBadge, scrollCls, contentCls, scrollResetKey, resizeSignal]);
181
+
182
+ // 子元素主动上报宽度变化 → 重跑测量,及时更新横滑箭头与右边缘淡出
183
+ useEffect(() => {
184
+ var _ctx$event;
185
+ const onResize = () => setResizeSignal(value => value + 1);
186
+ (_ctx$event = ctx.event) === null || _ctx$event === void 0 || _ctx$event.on(bottomLeftContentResize, onResize);
187
+ return () => {
188
+ var _ctx$event2;
189
+ (_ctx$event2 = ctx.event) === null || _ctx$event2 === void 0 || _ctx$event2.off(bottomLeftContentResize, onResize);
190
+ };
191
+ }, [ctx.event]);
177
192
  // 卸载时清理防抖定时器;若仍处于滑动中则恢复自动隐藏,避免遗留暂停态
178
193
  useEffect(() => {
179
194
  return () => {
@@ -181,9 +196,9 @@ const BottomLeftContent = _ref => {
181
196
  clearTimeout(scrollEndTimerRef.current);
182
197
  }
183
198
  if (scrollingRef.current) {
184
- var _ctx$event3;
199
+ var _ctx$event5;
185
200
  scrollingRef.current = false;
186
- (_ctx$event3 = ctx.event) === null || _ctx$event3 === void 0 || _ctx$event3.emit(startTimeToHideAllComponent);
201
+ (_ctx$event5 = ctx.event) === null || _ctx$event5 === void 0 || _ctx$event5.emit(startTimeToHideAllComponent);
187
202
  }
188
203
  };
189
204
  }, [ctx.event]);
@@ -253,17 +268,17 @@ const BottomLeftContent = _ref => {
253
268
  var _e$detail;
254
269
  // 滑动开始时暂停自动隐藏(仅在一次滑动会话内触发一次),滑动停止后恢复
255
270
  if (!scrollingRef.current) {
256
- var _ctx$event;
271
+ var _ctx$event3;
257
272
  scrollingRef.current = true;
258
- (_ctx$event = ctx.event) === null || _ctx$event === void 0 || _ctx$event.emit(pauseTimeToHideAllComponent);
273
+ (_ctx$event3 = ctx.event) === null || _ctx$event3 === void 0 || _ctx$event3.emit(pauseTimeToHideAllComponent);
259
274
  }
260
275
  if (scrollEndTimerRef.current) {
261
276
  clearTimeout(scrollEndTimerRef.current);
262
277
  }
263
278
  scrollEndTimerRef.current = setTimeout(() => {
264
- var _ctx$event2;
279
+ var _ctx$event4;
265
280
  scrollingRef.current = false;
266
- (_ctx$event2 = ctx.event) === null || _ctx$event2 === void 0 || _ctx$event2.emit(startTimeToHideAllComponent);
281
+ (_ctx$event4 = ctx.event) === null || _ctx$event4 === void 0 || _ctx$event4.emit(startTimeToHideAllComponent);
267
282
  }, 200);
268
283
 
269
284
  // Ray ScrollView 在不同实现下,scrollLeft 可能直接挂在事件上,也可能在 detail 内
@@ -48,7 +48,17 @@ export declare const widgetLabs: {
48
48
  readonly FULL_TRAVEL_ROUTE_CONTROL: "FullTravelRouteControl";
49
49
  readonly FULL_SCREEN: "FullScreen";
50
50
  readonly VERTICAL_SCREEN: "VerticalScreen";
51
+ readonly ZOOM_TURNTABLE: "ZoomTurntable";
52
+ readonly ZOOM_TURNTABLE_TIP: "ZoomTurntableTip";
51
53
  };
54
+ /**
55
+ * 左下角内容宽度可能已变化,请求重新测量横滑状态。
56
+ *
57
+ * 用于「widget 数量没变、但某个 widget 从 return null 变成真正渲染」的场景
58
+ * (如焦距转盘入口要等 Skill 异步就绪后才出现),
59
+ * 这类变化 bottomLeftContent.length 捕获不到。
60
+ */
61
+ export declare const bottomLeftContentResize = "bottomLeftContentResize";
52
62
  export declare const zoomLevelChange = "zoomLevelChange";
53
63
  export declare const setScaleMultipleEvent = "setScaleMultipleEvent";
54
64
  export declare const decodeClarityDic: {
@@ -49,8 +49,19 @@ export const widgetLabs = {
49
49
  FULL_VOICE_INTERCOM: 'FullVoiceIntercom',
50
50
  FULL_TRAVEL_ROUTE_CONTROL: 'FullTravelRouteControl',
51
51
  FULL_SCREEN: 'FullScreen',
52
- VERTICAL_SCREEN: 'VerticalScreen'
52
+ VERTICAL_SCREEN: 'VerticalScreen',
53
+ ZOOM_TURNTABLE: 'ZoomTurntable',
54
+ ZOOM_TURNTABLE_TIP: 'ZoomTurntableTip'
53
55
  };
56
+
57
+ /**
58
+ * 左下角内容宽度可能已变化,请求重新测量横滑状态。
59
+ *
60
+ * 用于「widget 数量没变、但某个 widget 从 return null 变成真正渲染」的场景
61
+ * (如焦距转盘入口要等 Skill 异步就绪后才出现),
62
+ * 这类变化 bottomLeftContent.length 捕获不到。
63
+ */
64
+ export const bottomLeftContentResize = 'bottomLeftContentResize';
54
65
  export const zoomLevelChange = 'zoomLevelChange';
55
66
  export const setScaleMultipleEvent = 'setScaleMultipleEvent';
56
67
  export const decodeClarityDic = {
package/lib/ui/ui.js CHANGED
@@ -24,6 +24,7 @@ import { Storage } from '../utils/storage';
24
24
  import './ui.less';
25
25
  import { updatePlayerWidgetProps } from '../features';
26
26
  import { getNgRawData, getSmartImageQualityState, isLowPhone } from '../utils/ttt';
27
+ import { lensCount } from '../widgets/zoomTurntable/lensSkill';
27
28
  function getCtxInstance(instance, devId) {
28
29
  if (instance) return instance;
29
30
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -47,6 +48,15 @@ const defaultCSSVariable = {
47
48
  '--fontSize': '12px'
48
49
  };
49
50
  const HIDE_COMPONENT_TIME = 5000;
51
+
52
+ /** 下发缩放前「先对齐画面实际值」与「再设目标值」之间的间隔(ms),太短会被 setData 合并 */
53
+ const SET_SCALE_ALIGN_DELAY = 120;
54
+
55
+ /** 对齐态最长抑制时长(ms):目标值迟迟不回读时兜底恢复,避免回读被永久吞掉 */
56
+ const SET_SCALE_ALIGN_TIMEOUT = 1500;
57
+
58
+ /** 回读值与对齐值 / 目标值的比对容差 */
59
+ const SCALE_MATCH_EPS = 0.01;
50
60
  export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
51
61
  const {
52
62
  className,
@@ -107,8 +117,23 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
107
117
  const reGetOrientationTimer = useRef(null);
108
118
  // 统一调整为1倍缩放,保证画面展示完全
109
119
  const [scaleMultiple, setScaleMultiple] = useState(1);
120
+ const scaleMultipleRef = useRef(1);
110
121
  // 统一调整为1倍缩放,保证画面展示完全
111
122
  const [currentZoomLevel, setCurrentZoomLevel] = useState(1);
123
+ /** 画面实际缩放(onZoomChange 回读),手势缩放不经过 scaleMultiple,故单独记一份 */
124
+ const currentZoomLevelRef = useRef(1);
125
+ /** 下发缩放的对齐态:{ 对齐值, 目标值, 兜底恢复时刻 },用于抑制中间态回读 */
126
+ const alignPendingRef = useRef(null);
127
+ const applyScaleMultiple = value => {
128
+ console.log('[scaleMultiple] setState', `${scaleMultipleRef.current} -> ${value}`);
129
+ scaleMultipleRef.current = value;
130
+ setScaleMultiple(value);
131
+ };
132
+
133
+ // 属性真的变了才会重渲染并下发给原生播放器;没有这条日志就说明属性没变化
134
+ useEffect(() => {
135
+ console.log('[scaleMultiple] 属性已下发给播放器 scaleMultiple =', scaleMultiple);
136
+ }, [scaleMultiple]);
112
137
  const [createCtx, setCreateCtx] = useState(false);
113
138
  // 是否需要忽略进入后台停止预览
114
139
  const [ignoreStopOnHide, setIgnoreStopOnHide] = useState(ignoreHideStopPreview);
@@ -241,7 +266,9 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
241
266
  layoutStyle,
242
267
  ptzStatus,
243
268
  selectedLenInfo,
244
- isVerticalFullLayout
269
+ isVerticalFullLayout,
270
+ maxZoomSettings,
271
+ zoomSkill
245
272
  } = useStore({
246
273
  topLeftContent: instance.topLeftContent,
247
274
  topRightContent: instance.topRightContent,
@@ -256,9 +283,21 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
256
283
  layoutStyle: instance.multiCameraCtx.layoutStyle,
257
284
  ptzStatus: instance.multiCameraCtx.ptzStatus,
258
285
  selectedLenInfo: instance.multiCameraCtx.selectedLenInfo,
259
- isVerticalFullLayout: instance.isVerticalFullLayout
286
+ isVerticalFullLayout: instance.isVerticalFullLayout,
287
+ maxZoomSettings: instance.maxZoomSettings,
288
+ zoomSkill: instance.zoomSkill
260
289
  });
261
290
 
291
+ // 默认最大缩放倍数下发给播放器;多镜头设备的上限要按当前镜头换算,交给 zoomTurntable 下发
292
+ useEffect(() => {
293
+ var _instance$IPCPlayerIn;
294
+ if (lensCount(zoomSkill) > 1) return;
295
+ if (typeof ((_instance$IPCPlayerIn = instance.IPCPlayerInstance) === null || _instance$IPCPlayerIn === void 0 ? void 0 : _instance$IPCPlayerIn.setMaxScaleMultiple) !== 'function') return;
296
+ instance.IPCPlayerInstance.setMaxScaleMultiple({
297
+ maxScaleMultiple: maxZoomSettings
298
+ });
299
+ }, [maxZoomSettings, zoomSkill]);
300
+
262
301
  /* ---------------------------------多目相关副作用统一处理开始----------------------------------------- */
263
302
  useEffect(() => {
264
303
  if (!instance.multiCameraCtx.isSupport) return;
@@ -754,7 +793,7 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
754
793
  console.log(scaleMultiple, 'scaleMultiple');
755
794
  console.log(hasPlayedRef.current, 'hasPlayedRef.current');
756
795
  if (hasPlayedRef.current) {
757
- setScaleMultiple(currentZoomLevel);
796
+ applyScaleMultiple(currentZoomLevel);
758
797
  }
759
798
  }
760
799
  if (playState === PlayState.PLAYING) {
@@ -834,7 +873,25 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
834
873
  setIgnoreStopOnHide(state);
835
874
  };
836
875
  const onSetScaleMultiple = value => {
837
- setScaleMultiple(value);
876
+ // 手势缩放只走 onZoomChange 回读、不写本 state,属性会停在旧值(甚至恰好等于目标值),
877
+ // 直接设目标时「值没变化」,播放器收不到。
878
+ // 故下发前先把属性对齐画面实际值 currentZoomLevel,再设目标值,保证属性确实变化一次。
879
+ // 两次更新要拉开间隔,挨太近会被 setData 合并,原生层看到的还是「没变化」。
880
+ const actual = currentZoomLevelRef.current;
881
+ console.log('[scaleMultiple] 收到 setScaleMultipleEvent', `目标=${value}`, `当前属性=${scaleMultipleRef.current}`, `画面实际=${actual}`);
882
+ if (actual === value) {
883
+ // 画面已在目标缩放,对齐属性即可
884
+ applyScaleMultiple(value);
885
+ return;
886
+ }
887
+ // 对齐这一步是我们自己制造的中间态,回读时不要广播出去(否则倍率读数会先闪一下 actual)
888
+ alignPendingRef.current = {
889
+ align: actual,
890
+ target: value,
891
+ expireAt: Date.now() + SET_SCALE_ALIGN_TIMEOUT
892
+ };
893
+ applyScaleMultiple(actual);
894
+ setTimeout(() => applyScaleMultiple(value), SET_SCALE_ALIGN_DELAY);
838
895
  };
839
896
  const onTrialCountdownEnd = useMemoizedFn(() => {
840
897
  // updatePlayerWidgetProps(instance, 'bottomLeft', 'TryExperience' as any, {
@@ -899,7 +956,24 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
899
956
  // }
900
957
 
901
958
  // 直接记录当前缩放比例
959
+ console.log('[scaleMultiple] onZoomChange 回读画面实际缩放 =', zoomLevel);
960
+ currentZoomLevelRef.current = zoomLevel;
902
961
  setCurrentZoomLevel(zoomLevel);
962
+
963
+ // 抑制「先对齐再设目标」这一步产生的中间态回读:广播出去会让倍率读数先闪一下对齐值
964
+ const pending = alignPendingRef.current;
965
+ if (pending) {
966
+ if (Date.now() > pending.expireAt) {
967
+ // 目标值迟迟没回来,兜底恢复,别把后续回读一直吞掉
968
+ console.warn('[scaleMultiple] 对齐态超时恢复', JSON.stringify(pending));
969
+ alignPendingRef.current = null;
970
+ } else if (Math.abs(zoomLevel - pending.align) < SCALE_MATCH_EPS) {
971
+ console.log('[scaleMultiple] 中间态回读已抑制,不广播', zoomLevel);
972
+ return false;
973
+ } else if (Math.abs(zoomLevel - pending.target) < SCALE_MATCH_EPS) {
974
+ alignPendingRef.current = null;
975
+ }
976
+ }
903
977
  instance.event.emit(zoomLevelChange, zoomLevel);
904
978
  return false;
905
979
  });
package/lib/ui/ui.less CHANGED
@@ -43,6 +43,21 @@
43
43
  .ipc-player-plugin-realtime-magnification {
44
44
  background-color: rgba(0, 0, 0, 0.2);
45
45
  }
46
+
47
+ // 焦距 tab:底部条变白底后整体反相 —— 未选中用浅灰底(同上面两个控件),
48
+ // 选中态不能沿用白底(会与白色底部条糊在一起),改为深色底 + 白字。
49
+ // 文字默认色走 --iconColor,已在上面被覆盖为 #000,无需单独处理。
50
+ .ipc-player-plugin-zoom-turntable-tab {
51
+ background-color: rgba(0, 0, 0, 0.2);
52
+ }
53
+
54
+ .ipc-player-plugin-zoom-turntable-tab-active {
55
+ background-color: rgba(0, 0, 0, 0.85);
56
+
57
+ .ipc-player-plugin-zoom-turntable-tab-text {
58
+ color: #fff;
59
+ }
60
+ }
46
61
  }
47
62
  }
48
63
 
@@ -11,3 +11,4 @@ export declare const ZOOM_CONTROL = "zoom_control";
11
11
  export declare const MULTI_GUN_BALL = "ipc_multi_locate_coors";
12
12
  export declare const MULTI_PTZ_CONTROL = "ipc_multi_ptz_control";
13
13
  export declare const MULTI_ZOOM_CONTROL = "ipc_multi_zoom_control";
14
+ export declare const MULTI_ZOOM = "ipc_multi_zoom";
@@ -22,4 +22,8 @@ export const MULTI_GUN_BALL = 'ipc_multi_locate_coors'; // 多目枪球联动-
22
22
 
23
23
  export const MULTI_PTZ_CONTROL = 'ipc_multi_ptz_control'; // 多目 PTZ 控制
24
24
 
25
- export const MULTI_ZOOM_CONTROL = 'ipc_multi_zoom_control'; // 多目 变焦控制
25
+ export const MULTI_ZOOM_CONTROL = 'ipc_multi_zoom_control'; // 多目 变焦控制
26
+
27
+ // 多镜头变焦(切换焦距)门控 DP:存在才拉 zoom_skill、才显示转盘入口,不解析其内容。
28
+ // 注意与上面的 ipc_multi_zoom_control 不是同一个 DP。
29
+ export const MULTI_ZOOM = 'ipc_multi_zoom';
@@ -3,8 +3,8 @@ export declare class Storage {
3
3
  constructor(prefix: string);
4
4
  get(key: string): Promise<any>;
5
5
  getSync(key: string): any;
6
- set(key: string, value: any): Promise<null>;
7
- remove(key: string): Promise<null>;
6
+ set(key: string, value: any): Promise<any>;
7
+ remove(key: string): Promise<any>;
8
8
  private getFullKey;
9
9
  }
10
10
  export declare const storage: Storage;
@@ -23,3 +23,4 @@ export * from './smallIntercom';
23
23
  export * from './toggleVerticalFull';
24
24
  export * from './flowLowTip';
25
25
  export * from './realTimeMagnification';
26
+ export * from './zoomTurntable';
@@ -22,4 +22,5 @@ export * from './multiCamera';
22
22
  export * from './smallIntercom';
23
23
  export * from './toggleVerticalFull';
24
24
  export * from './flowLowTip';
25
- export * from './realTimeMagnification';
25
+ export * from './realTimeMagnification';
26
+ export * from './zoomTurntable';
@@ -3,13 +3,19 @@ import { View, Text } from '@ray-js/ray';
3
3
  import clsx from 'clsx';
4
4
  import { PlayState } from '../../interface';
5
5
  import { useStore } from '../../ctx/store';
6
+ import { useDpSupport } from '../../hooks/useDpSupport';
6
7
  import { zoomLevelChange, setScaleMultipleEvent, pauseTimeToHideAllComponent, startTimeToHideAllComponent } from '../../ui/constant';
8
+ import { MULTI_ZOOM_DP_CODE } from '../zoomTurntable/lensSkill';
7
9
  import './realTimeMagnification.less';
8
10
 
9
11
  /** 全量档位列表 */
10
12
  const ALL_ZOOM_LEVELS = [1, 2, 4, 6, 8, 12];
13
+
14
+ /** 放模块级:useDpSupport 把 dpCodes 直接当 effect 依赖,行内数组会每次渲染重查一遍 schema */
15
+ const MULTI_ZOOM_DP_CODES = [MULTI_ZOOM_DP_CODE];
11
16
  export const RealTimeMagnification = props => {
12
17
  const {
18
+ devId,
13
19
  playState,
14
20
  event,
15
21
  className,
@@ -27,6 +33,17 @@ export const RealTimeMagnification = props => {
27
33
  });
28
34
  const [currentZoom, setCurrentZoom] = useState(1);
29
35
 
36
+ /**
37
+ * 设备带 ipc_multi_zoom(多镜头变焦能力 DP)时本组件让位:
38
+ * 倍率的显示与交互都交给焦距转盘(ZoomTurntableEntry / Dock),两者同时出现会给两套读数。
39
+ * 这里只看设备 schema 里有没有这个 DP,不解析值、也不管业务侧的 showZoomTurntable 开关。
40
+ */
41
+ const dpSupportMap = useDpSupport({
42
+ devId,
43
+ dpCodes: MULTI_ZOOM_DP_CODES
44
+ });
45
+ const hasMultiZoomDp = dpSupportMap[MULTI_ZOOM_DP_CODE];
46
+
30
47
  /** 根据 maxZoomSettings 动态生成可用档位列表 */
31
48
  const zoomLevels = useMemo(() => {
32
49
  const max = maxZoomSettings || 6;
@@ -75,7 +92,7 @@ export const RealTimeMagnification = props => {
75
92
  event.emit(setScaleMultipleEvent, nextZoom);
76
93
  event.emit(startTimeToHideAllComponent);
77
94
  }, [getNextZoom, event, currentZoom]);
78
- if (currentPlayState !== PlayState.PLAYING) {
95
+ if (currentPlayState !== PlayState.PLAYING || hasMultiZoomDp) {
79
96
  return null;
80
97
  }
81
98
  return /*#__PURE__*/React.createElement(View, {
@@ -1,4 +1,4 @@
1
1
  .toggle-vertical-full {
2
- font-size: var(--iconPlayerSize);
2
+ font-size: calc(var(--iconPlayerSize) * var(--ipc-player-size-scale, 1)) !important;
3
3
  color: var(--iconColor);
4
4
  }