@ray-js/ipc-player-integration 0.0.53-beta.2 → 0.0.53-beta.4

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/ctx/ctx.js CHANGED
@@ -12,6 +12,7 @@ import { changeIgnoreHideStopPreview } from '../ui/constant';
12
12
  import { ClarityType } from '@ray-js/ray-ipc-utils/lib/interface';
13
13
  import { getEventInstance } from './event';
14
14
  import { isMultiCameraTileSupported, useMultiCameraCtx } from './multiCameraCtx';
15
+ import { isClarityChangedSupported } from '../utils/ttt';
15
16
  const SAVE_TO_ALBUM = 1;
16
17
  export const createUseCtx = _ref => {
17
18
  let {
@@ -111,12 +112,21 @@ export const createUseCtx = _ref => {
111
112
  }
112
113
 
113
114
  /**
114
- * 自动清晰度作为独立档位并入清晰度列表:
115
+ * 只有宿主支持自动清晰度事件,且接口返回的清晰度档位数量不少于 2 个时,才展示 AUTO:
115
116
  * 竖屏宿主弹框(由 resolutionList 构建 actionData)与横屏 FullResolutionControl 共用。
116
117
  */
118
+ const canShowAutoClarity = function () {
119
+ let list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
120
+ return isClarityChangedSupported() && list.length >= 2;
121
+ };
117
122
  const withAutoClarity = function () {
118
123
  let list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
119
- return list.includes(ClarityType.AUTO) ? list : [...list, ClarityType.AUTO];
124
+ const withoutAuto = list.filter(clarity => clarity !== ClarityType.AUTO);
125
+ return canShowAutoClarity(list) ? [...withoutAuto, ClarityType.AUTO] : withoutAuto;
126
+ };
127
+ const normalizeResolution = (resolution, list) => {
128
+ if (resolution !== ClarityType.AUTO || canShowAutoClarity(list)) return resolution;
129
+ return list.find(clarity => clarity !== ClarityType.AUTO) || ClarityType.HD;
120
130
  };
121
131
  useEffect(() => {
122
132
  // 初始化获取缓存值
@@ -127,7 +137,7 @@ export const createUseCtx = _ref => {
127
137
  var _res$maxZoomSettings;
128
138
  const res = await getMemoryState(devId);
129
139
  setResolutionList(withAutoClarity(res.resolutionList));
130
- _setResolution(res.resolution, true);
140
+ _setResolution(normalizeResolution(res.resolution, res.resolutionList), true);
131
141
  _setMute(res.mute, true);
132
142
  setIntercomMode(res.intercomMode);
133
143
  setIntercomSupported(res.isIntercomSupported);
@@ -144,7 +154,7 @@ export const createUseCtx = _ref => {
144
154
  var _res$maxZoomSettings2;
145
155
  setResolutionList(withAutoClarity(res.resolutionList));
146
156
  // 传true表示值即可,会取播放器的值
147
- _setResolution(res.resolution, true);
157
+ _setResolution(normalizeResolution(res.resolution, res.resolutionList), true);
148
158
  _setMute(res.mute, true);
149
159
  setIntercomMode(res.intercomMode);
150
160
  setIntercomSupported(res.isIntercomSupported);
@@ -143,12 +143,7 @@ export type CaptureFileInfo = {
143
143
  height?: number;
144
144
  data?: string;
145
145
  };
146
- export type MultiCaptureFileInfo = CaptureFileInfo & {
147
- index: number;
148
- };
149
- export type CaptureResult = boolean | CaptureFileInfo | {
150
- items: MultiCaptureFileInfo[];
151
- };
146
+ export type CaptureResult = boolean | CaptureFileInfo;
152
147
  export type RecordInfoData = CaptureResult;
153
148
  /**
154
149
  * 多目屏幕模式
package/lib/ui/ui.js CHANGED
@@ -661,8 +661,12 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
661
661
  setRecording(false, true);
662
662
  setIntercom(false, true);
663
663
  instance === null || instance === void 0 || instance.stopRecordingOnUnload().then(async result => {
664
- var _instance$multiCamera;
665
- const summary = await getCaptureResultSummary(result, instance === null || instance === void 0 || (_instance$multiCamera = instance.multiCameraCtx) === null || _instance$multiCamera === void 0 || (_instance$multiCamera = _instance$multiCamera.protocol) === null || _instance$multiCamera === void 0 ? void 0 : _instance$multiCamera.total_split_num, devId);
664
+ var _instance$multiLens, _instance$multiCamera;
665
+ const summary = await getCaptureResultSummary(result, {
666
+ multiLens: (_instance$multiLens = instance === null || instance === void 0 ? void 0 : instance.multiLens) !== null && _instance$multiLens !== void 0 ? _instance$multiLens : false,
667
+ protocolCount: instance === null || instance === void 0 || (_instance$multiCamera = instance.multiCameraCtx) === null || _instance$multiCamera === void 0 || (_instance$multiCamera = _instance$multiCamera.protocol) === null || _instance$multiCamera === void 0 ? void 0 : _instance$multiCamera.total_split_num,
668
+ devId
669
+ });
666
670
  ipcTTTOperatorLog(summary !== null && summary !== void 0 && summary.isMultiLens ? `hide: stop recording succeeded with ${summary.count} files` : 'hide: 调用停止录制方法成功');
667
671
  }).catch(() => {
668
672
  ipcTTTOperatorLog('hide: 调用停止录制方法失败');
@@ -4,6 +4,11 @@ export type CaptureResultSummary = {
4
4
  isMultiLens: boolean;
5
5
  thumbnailPath: string;
6
6
  };
7
+ export type CaptureResultOptions = {
8
+ multiLens: boolean;
9
+ protocolCount?: number | string;
10
+ devId: string;
11
+ };
7
12
  /** 从新多目高级能力配置获取当前设备的总镜头数 */
8
13
  export declare function getMultiLensCountFromAbility(devId: string): Promise<number>;
9
- export declare function getCaptureResultSummary(result: CaptureResult, fallbackCount: number | undefined, devId: string): Promise<CaptureResultSummary | null>;
14
+ export declare function getCaptureResultSummary(result: CaptureResult, { multiLens, protocolCount, devId }: CaptureResultOptions): Promise<CaptureResultSummary | null>;
@@ -33,36 +33,38 @@ const extractPath = item => {
33
33
  if (typeof (item === null || item === void 0 ? void 0 : item.value) === 'string') return item.value;
34
34
  return '';
35
35
  };
36
- export async function getCaptureResultSummary(result, fallbackCount, devId) {
36
+ export async function getCaptureResultSummary(result, _ref) {
37
+ let {
38
+ multiLens,
39
+ protocolCount,
40
+ devId
41
+ } = _ref;
37
42
  if (!result || typeof result === 'boolean') return null;
38
- const rawResult = result;
39
- const singleThumb = extractPath(rawResult.tempImagePath) || extractPath(rawResult.thumbPath) || extractPath(rawResult.filePath) || '';
40
- if ('items' in result && Array.isArray(result.items) && result.items.length > 0) {
41
- const firstItem = result.items[0];
42
- const firstThumb = extractPath(firstItem === null || firstItem === void 0 ? void 0 : firstItem.tempImagePath) || extractPath(firstItem === null || firstItem === void 0 ? void 0 : firstItem.thumbPath) || extractPath(firstItem === null || firstItem === void 0 ? void 0 : firstItem.filePath) || singleThumb;
43
+ const thumbnailPath = extractPath(result.tempImagePath) || extractPath(result.thumbPath) || extractPath(result.filePath) || '';
44
+ if (!multiLens) {
43
45
  return {
44
- count: result.items.length,
45
- isMultiLens: true,
46
- thumbnailPath: firstThumb
46
+ count: 1,
47
+ isMultiLens: false,
48
+ thumbnailPath
47
49
  };
48
50
  }
49
- const legacySplitCount = fallbackCount && fallbackCount > 1 ? fallbackCount : 0;
51
+ const splitCount = Number(protocolCount) > 1 ? Number(protocolCount) : 0;
50
52
  const multiLensAbilityCount = await getMultiLensCountFromAbility(devId);
51
53
 
52
54
  // The native multi-lens snapshot can return one object while writing lens-specific
53
55
  // files. Use the ability result to distinguish that file-name convention from the
54
56
  // legacy split protocol.
55
- const multiCount = legacySplitCount || multiLensAbilityCount;
57
+ const multiCount = splitCount || multiLensAbilityCount;
56
58
  if (multiCount > 1) {
57
59
  return {
58
60
  count: multiCount,
59
61
  isMultiLens: true,
60
- thumbnailPath: multiLensAbilityCount > 1 ? normalizeMultiLensThumbnailPath(singleThumb) : singleThumb
62
+ thumbnailPath: multiLensAbilityCount > 1 ? normalizeMultiLensThumbnailPath(thumbnailPath) : thumbnailPath
61
63
  };
62
64
  }
63
65
  return {
64
66
  count: 1,
65
67
  isMultiLens: false,
66
- thumbnailPath: singleThumb
68
+ thumbnailPath
67
69
  };
68
70
  }
@@ -24,14 +24,33 @@ describe('getCaptureResultSummary', () => {
24
24
  }
25
25
  }
26
26
  });
27
- await expect(getCaptureResultSummary(createCaptureResult(basePath), undefined, 'dev-1')).resolves.toEqual({
27
+ await expect(getCaptureResultSummary(createCaptureResult(basePath), {
28
+ multiLens: true,
29
+ devId: 'dev-1'
30
+ })).resolves.toEqual({
28
31
  count: 4,
29
32
  isMultiLens: true,
30
33
  thumbnailPath: 'thingfile://tmp/capture_123_lens1.jpg'
31
34
  });
32
35
  });
33
- it('keeps the legacy path when the ability is unavailable', async () => {
34
- await expect(getCaptureResultSummary(createCaptureResult(basePath), 4, 'dev-1')).resolves.toEqual({
36
+ it('keeps the single-lens result for a legacy multi-camera device', async () => {
37
+ await expect(getCaptureResultSummary(createCaptureResult(basePath), {
38
+ multiLens: false,
39
+ protocolCount: 4,
40
+ devId: 'dev-1'
41
+ })).resolves.toEqual({
42
+ count: 1,
43
+ isMultiLens: false,
44
+ thumbnailPath: basePath
45
+ });
46
+ expect(mockGetDeviceInfo).not.toHaveBeenCalled();
47
+ });
48
+ it('uses the protocol count when the multi-lens mode is enabled', async () => {
49
+ await expect(getCaptureResultSummary(createCaptureResult(basePath), {
50
+ multiLens: true,
51
+ protocolCount: 4,
52
+ devId: 'dev-1'
53
+ })).resolves.toEqual({
35
54
  count: 4,
36
55
  isMultiLens: true,
37
56
  thumbnailPath: basePath
@@ -46,7 +65,11 @@ describe('getCaptureResultSummary', () => {
46
65
  }
47
66
  }
48
67
  });
49
- await expect(getCaptureResultSummary(createCaptureResult(basePath), 4, 'dev-1')).resolves.toEqual({
68
+ await expect(getCaptureResultSummary(createCaptureResult(basePath), {
69
+ multiLens: true,
70
+ protocolCount: 4,
71
+ devId: 'dev-1'
72
+ })).resolves.toEqual({
50
73
  count: 4,
51
74
  isMultiLens: true,
52
75
  thumbnailPath: 'thingfile://tmp/capture_123_lens1.jpg'
@@ -61,29 +84,33 @@ describe('getCaptureResultSummary', () => {
61
84
  }
62
85
  });
63
86
  const path = 'thingfile://tmp/capture_123_lens1.jpg';
64
- await expect(getCaptureResultSummary(createCaptureResult(path), undefined, 'dev-1')).resolves.toEqual({
87
+ await expect(getCaptureResultSummary(createCaptureResult(path), {
88
+ multiLens: true,
89
+ devId: 'dev-1'
90
+ })).resolves.toEqual({
65
91
  count: 4,
66
92
  isMultiLens: true,
67
93
  thumbnailPath: path
68
94
  });
69
95
  });
70
96
  it('keeps a mono result unchanged', async () => {
71
- await expect(getCaptureResultSummary(createCaptureResult(basePath), undefined, 'dev-1')).resolves.toEqual({
97
+ await expect(getCaptureResultSummary(createCaptureResult(basePath), {
98
+ multiLens: false,
99
+ devId: 'dev-1'
100
+ })).resolves.toEqual({
72
101
  count: 1,
73
102
  isMultiLens: false,
74
103
  thumbnailPath: basePath
75
104
  });
76
105
  });
77
- it('keeps item paths unchanged', async () => {
78
- await expect(getCaptureResultSummary({
79
- items: [{
80
- index: 1,
81
- tempImagePath: basePath,
82
- filePath: basePath
83
- }]
84
- }, undefined, 'dev-1')).resolves.toEqual({
106
+ it('keeps a single-lens result when multi-lens mode has one lens', async () => {
107
+ await expect(getCaptureResultSummary(createCaptureResult(basePath), {
108
+ multiLens: true,
109
+ protocolCount: 1,
110
+ devId: 'dev-1'
111
+ })).resolves.toEqual({
85
112
  count: 1,
86
- isMultiLens: true,
113
+ isMultiLens: false,
87
114
  thumbnailPath: basePath
88
115
  });
89
116
  });
@@ -5,7 +5,7 @@ import { Image, Text, View } from '@ray-js/ray';
5
5
  import clsx from 'clsx';
6
6
  import Strings from '../../i18n';
7
7
  import './captureResult.less';
8
- const THUMBNAIL_LAYERS = ['back', 'middle', 'front'];
8
+ const BACKDROP_LAYERS = ['back', 'middle'];
9
9
  const TEXT_KEYS = {
10
10
  record: {
11
11
  check: 'ipc_player_record_success_check',
@@ -55,18 +55,17 @@ export function CaptureResultToast(_ref) {
55
55
  const textKeys = TEXT_KEYS[kind];
56
56
  const legacyCls = LEGACY_CLASS_MAP[kind];
57
57
  const imageClassName = clsx('ipc-player-plugin-capture-result-image', legacyCls.image);
58
+ const backdropLayers = BACKDROP_LAYERS.slice(-Math.min(count - 1, BACKDROP_LAYERS.length));
58
59
  return /*#__PURE__*/React.createElement(View, {
59
60
  className: clsx('ipc-player-plugin-capture-result-toast', legacyCls.toast, className)
60
61
  }, /*#__PURE__*/React.createElement(View, {
61
62
  className: clsx('ipc-player-plugin-capture-result-image-box', legacyCls.imageBox, isMultiLens && ['ipc-player-plugin-capture-result-image-box-multi', legacyCls.imageBoxMulti])
62
- }, isMultiLens ? THUMBNAIL_LAYERS.slice(0, count).map((layer, index) => /*#__PURE__*/React.createElement(Image, {
63
+ }, isMultiLens ? /*#__PURE__*/React.createElement(React.Fragment, null, backdropLayers.map(layer => /*#__PURE__*/React.createElement(View, {
63
64
  key: layer,
64
- className: imageClassName,
65
- src: thumbnailPath,
66
- style: {
67
- left: `${index * 5}px`,
68
- zIndex: index + 1
69
- }
65
+ className: clsx('ipc-player-plugin-capture-result-backdrop', `ipc-player-plugin-capture-result-image-${layer}`)
66
+ })), /*#__PURE__*/React.createElement(Image, {
67
+ className: clsx(imageClassName, 'ipc-player-plugin-capture-result-image-front'),
68
+ src: thumbnailPath
70
69
  })) : /*#__PURE__*/React.createElement(Image, {
71
70
  className: imageClassName,
72
71
  src: thumbnailPath
@@ -29,17 +29,47 @@
29
29
  object-fit: cover;
30
30
  }
31
31
 
32
- .ipc-player-plugin-capture-result-image-box-multi .ipc-player-plugin-capture-result-image,
33
- .ipc-player-plugin-record-success-toast-image-box-multi .ipc-player-plugin-record-success-toast-image,
34
- .ipc-player-plugin-screenshot-toast-image-box-multi .ipc-player-plugin-screenshot-toast-image {
32
+ .ipc-player-plugin-capture-result-image-box-multi,
33
+ .ipc-player-plugin-record-success-toast-image-box-multi,
34
+ .ipc-player-plugin-screenshot-toast-image-box-multi {
35
+ height: calc(39px * var(--ipc-player-size-scale, 1));
36
+ }
37
+
38
+ .ipc-player-plugin-capture-result-backdrop,
39
+ .ipc-player-plugin-capture-result-image-front {
35
40
  position: absolute;
36
- top: 0;
37
- width: calc(56px * var(--ipc-player-size-scale, 1));
38
41
  box-sizing: border-box;
39
- border: 1px solid var(--shot-card-bg-color);
40
42
  border-radius: calc(4px * var(--ipc-player-size-scale, 1));
41
43
  }
42
44
 
45
+ .ipc-player-plugin-capture-result-backdrop {
46
+ background: rgba(255, 255, 255, 0.2);
47
+ }
48
+
49
+ .ipc-player-plugin-capture-result-image-back {
50
+ top: 0;
51
+ left: calc(7px * var(--ipc-player-size-scale, 1));
52
+ z-index: 1;
53
+ width: calc(52px * var(--ipc-player-size-scale, 1));
54
+ height: calc(28px * var(--ipc-player-size-scale, 1));
55
+ }
56
+
57
+ .ipc-player-plugin-capture-result-image-middle {
58
+ top: calc(3px * var(--ipc-player-size-scale, 1));
59
+ left: calc(2.5px * var(--ipc-player-size-scale, 1));
60
+ z-index: 2;
61
+ width: calc(61px * var(--ipc-player-size-scale, 1));
62
+ height: calc(30.5px * var(--ipc-player-size-scale, 1));
63
+ }
64
+
65
+ .ipc-player-plugin-capture-result-image-front {
66
+ top: calc(6px * var(--ipc-player-size-scale, 1));
67
+ left: 0;
68
+ z-index: 3;
69
+ width: calc(66px * var(--ipc-player-size-scale, 1));
70
+ height: calc(33px * var(--ipc-player-size-scale, 1));
71
+ }
72
+
43
73
  .ipc-player-plugin-capture-result-play-icon-box,
44
74
  .ipc-player-plugin-record-success-play-icon-box {
45
75
  position: absolute;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import { renderToStaticMarkup } from 'react-dom/server';
3
+ jest.mock('@ray-js/ray', () => {
4
+ const React = require('react');
5
+ return {
6
+ Image: _ref => {
7
+ let {
8
+ className,
9
+ src
10
+ } = _ref;
11
+ return /*#__PURE__*/React.createElement("img", {
12
+ alt: "",
13
+ className: className,
14
+ src: src
15
+ });
16
+ },
17
+ Text: _ref2 => {
18
+ let {
19
+ children,
20
+ className
21
+ } = _ref2;
22
+ return /*#__PURE__*/React.createElement("span", {
23
+ className: className
24
+ }, children);
25
+ },
26
+ View: _ref3 => {
27
+ let {
28
+ children,
29
+ className
30
+ } = _ref3;
31
+ return /*#__PURE__*/React.createElement("div", {
32
+ className: className
33
+ }, children);
34
+ }
35
+ };
36
+ });
37
+ jest.mock('../../i18n', () => ({
38
+ __esModule: true,
39
+ default: {
40
+ getLang: key => key,
41
+ formatString: (template, count) => `${template}:${count}`
42
+ }
43
+ }));
44
+ jest.mock('./captureResult.less', () => ({}));
45
+ const {
46
+ CaptureResultToast
47
+ } = require('./captureResult');
48
+ const renderToast = count => renderToStaticMarkup(/*#__PURE__*/React.createElement(CaptureResultToast, {
49
+ brandColor: "#ff592a",
50
+ count: count,
51
+ kind: "screenshot",
52
+ onCheck: () => undefined,
53
+ thumbnailPath: "thingfile://capture.jpg"
54
+ }));
55
+ const countClass = (markup, className) => [...markup.matchAll(/class="([^"]*)"/g)].filter(_ref4 => {
56
+ let [, names] = _ref4;
57
+ return names.split(/\s+/).includes(className);
58
+ }).length;
59
+ describe('CaptureResultToast', () => {
60
+ it('keeps the single-item thumbnail unchanged', () => {
61
+ const markup = renderToast(1);
62
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-backdrop')).toBe(0);
63
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image-front')).toBe(0);
64
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image')).toBe(1);
65
+ });
66
+ it('renders one backdrop for two captured items', () => {
67
+ const markup = renderToast(2);
68
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-backdrop')).toBe(1);
69
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image-middle')).toBe(1);
70
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image-front')).toBe(1);
71
+ });
72
+ it('caps the backdrop count at two', () => {
73
+ const markup = renderToast(4);
74
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-backdrop')).toBe(2);
75
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image-back')).toBe(1);
76
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image-middle')).toBe(1);
77
+ expect(countClass(markup, 'ipc-player-plugin-capture-result-image-front')).toBe(1);
78
+ });
79
+ });
@@ -117,7 +117,11 @@ export function RecordVideo(props) {
117
117
  var _props$multiCameraCtx;
118
118
  const requestId = ++recordResultRequestIdRef.current;
119
119
  const splitNum = (_props$multiCameraCtx = props.multiCameraCtx) === null || _props$multiCameraCtx === void 0 || (_props$multiCameraCtx = _props$multiCameraCtx.protocol) === null || _props$multiCameraCtx === void 0 ? void 0 : _props$multiCameraCtx.total_split_num;
120
- const summary = await getCaptureResultSummary(recordInfo, splitNum, devId);
120
+ const summary = await getCaptureResultSummary(recordInfo, {
121
+ multiLens: props.multiLens,
122
+ protocolCount: splitNum,
123
+ devId
124
+ });
121
125
  if (requestId !== recordResultRequestIdRef.current) return;
122
126
  if (!summary) return;
123
127
  setState({
@@ -139,7 +139,11 @@ export function Screenshot(props) {
139
139
  var _props$multiCameraCtx;
140
140
  setIgnoreHideStopPreview(false);
141
141
  const splitNum = (_props$multiCameraCtx = props.multiCameraCtx) === null || _props$multiCameraCtx === void 0 || (_props$multiCameraCtx = _props$multiCameraCtx.protocol) === null || _props$multiCameraCtx === void 0 ? void 0 : _props$multiCameraCtx.total_split_num;
142
- const summary = await getCaptureResultSummary(res, splitNum, devId);
142
+ const summary = await getCaptureResultSummary(res, {
143
+ multiLens: props.multiLens,
144
+ protocolCount: splitNum,
145
+ devId
146
+ });
143
147
  if (requestId !== snapshotRequestIdRef.current) return;
144
148
  if (!summary) {
145
149
  handleSnapshotFail({});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/ipc-player-integration",
3
- "version": "0.0.53-beta.2",
3
+ "version": "0.0.53-beta.4",
4
4
  "description": "IPC 融合播放器",
5
5
  "main": "lib/index",
6
6
  "files": [