@ray-js/ipc-player-integration 0.0.52-beta.2 → 0.0.52-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 +6 -15
- package/lib/ui/ui.js +7 -6
- package/lib/utils/captureResult.d.ts +3 -1
- package/lib/utils/captureResult.js +55 -5
- package/lib/utils/captureResult.test.d.ts +1 -0
- package/lib/utils/captureResult.test.js +90 -0
- package/lib/widgets/recordVideo/recordVideo.js +15 -4
- package/lib/widgets/screenshot/screenshot.js +16 -10
- package/package.json +1 -1
package/lib/ctx/ctx.js
CHANGED
|
@@ -254,13 +254,9 @@ export const createUseCtx = _ref => {
|
|
|
254
254
|
});
|
|
255
255
|
};
|
|
256
256
|
const stopRecording = showError => {
|
|
257
|
-
const sessionMultiLens = recordingMultiLensRef.current;
|
|
258
257
|
return new Promise((resolve, reject) => {
|
|
259
|
-
IPCPlayerInstance.current.stopRecord(
|
|
260
|
-
saveToAlbum
|
|
261
|
-
}, sessionMultiLens ? {
|
|
262
|
-
multiLens: true
|
|
263
|
-
} : {}), {}, {
|
|
258
|
+
IPCPlayerInstance.current.stopRecord({
|
|
259
|
+
saveToAlbum,
|
|
264
260
|
success: res => {
|
|
265
261
|
recordingMultiLensRef.current = false;
|
|
266
262
|
updateAtom(recording, false);
|
|
@@ -278,7 +274,7 @@ export const createUseCtx = _ref => {
|
|
|
278
274
|
});
|
|
279
275
|
}
|
|
280
276
|
}
|
|
281
|
-
})
|
|
277
|
+
});
|
|
282
278
|
});
|
|
283
279
|
};
|
|
284
280
|
const multiCameraCtx = useMultiCameraCtx({
|
|
@@ -437,15 +433,10 @@ export const createUseCtx = _ref => {
|
|
|
437
433
|
}
|
|
438
434
|
if (!target) return stopRecording(true);
|
|
439
435
|
return new Promise((resolve, reject) => {
|
|
440
|
-
const sessionMultiLens = multiLens;
|
|
441
436
|
const startRecord = () => {
|
|
442
|
-
IPCPlayerInstance.current.startRecord(
|
|
443
|
-
saveToAlbum
|
|
444
|
-
}, sessionMultiLens ? {
|
|
445
|
-
multiLens: true
|
|
446
|
-
} : {}), {}, {
|
|
437
|
+
IPCPlayerInstance.current.startRecord({
|
|
438
|
+
saveToAlbum,
|
|
447
439
|
success: () => {
|
|
448
|
-
recordingMultiLensRef.current = sessionMultiLens;
|
|
449
440
|
updateAtom(recording, true);
|
|
450
441
|
resolve(true);
|
|
451
442
|
},
|
|
@@ -453,7 +444,7 @@ export const createUseCtx = _ref => {
|
|
|
453
444
|
eventRef.current.emit(changeIgnoreHideStopPreview, false);
|
|
454
445
|
reject(err);
|
|
455
446
|
}
|
|
456
|
-
})
|
|
447
|
+
});
|
|
457
448
|
};
|
|
458
449
|
// 写入相册
|
|
459
450
|
ty.authorizeStatus({
|
package/lib/ui/ui.js
CHANGED
|
@@ -653,8 +653,9 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
653
653
|
ipcTTTOperatorLog('hide: 调用停止录制方法');
|
|
654
654
|
setRecording(false, true);
|
|
655
655
|
setIntercom(false, true);
|
|
656
|
-
instance === null || instance === void 0 || instance.stopRecordingOnUnload().then(result => {
|
|
657
|
-
|
|
656
|
+
instance === null || instance === void 0 || instance.stopRecordingOnUnload().then(async result => {
|
|
657
|
+
var _instance$multiCamera;
|
|
658
|
+
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);
|
|
658
659
|
ipcTTTOperatorLog(summary !== null && summary !== void 0 && summary.isMultiLens ? `hide: stop recording succeeded with ${summary.count} files` : 'hide: 调用停止录制方法成功');
|
|
659
660
|
}).catch(() => {
|
|
660
661
|
ipcTTTOperatorLog('hide: 调用停止录制方法失败');
|
|
@@ -1118,17 +1119,17 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
1118
1119
|
// 这一下起,自动隐藏倒计时才开始生效
|
|
1119
1120
|
hasUserTappedPlayerRef.current = true;
|
|
1120
1121
|
if (instance.multiCameraCtx.isSupport) {
|
|
1121
|
-
var _instance$
|
|
1122
|
-
const preTapIndex = (_instance$
|
|
1122
|
+
var _instance$multiCamera2, _instance$multiCamera3;
|
|
1123
|
+
const preTapIndex = (_instance$multiCamera2 = (_instance$multiCamera3 = instance.multiCameraCtx.selectedLenInfoRef.current) === null || _instance$multiCamera3 === void 0 ? void 0 : _instance$multiCamera3.index) !== null && _instance$multiCamera2 !== void 0 ? _instance$multiCamera2 : prevSelectedIndexRef.current;
|
|
1123
1124
|
const wasHidden = componentHideState;
|
|
1124
1125
|
instance.multiCameraCtx.selectVideoFiredRef.current = false;
|
|
1125
1126
|
if (multiTapTimerRef.current) {
|
|
1126
1127
|
clearTimeout(multiTapTimerRef.current);
|
|
1127
1128
|
}
|
|
1128
1129
|
multiTapTimerRef.current = setTimeout(() => {
|
|
1129
|
-
var _instance$
|
|
1130
|
+
var _instance$multiCamera4, _instance$multiCamera5;
|
|
1130
1131
|
const selectFired = !!instance.multiCameraCtx.selectVideoFiredRef.current;
|
|
1131
|
-
const currentIndex = (_instance$
|
|
1132
|
+
const currentIndex = (_instance$multiCamera4 = (_instance$multiCamera5 = instance.multiCameraCtx.selectedLenInfoRef.current) === null || _instance$multiCamera5 === void 0 ? void 0 : _instance$multiCamera5.index) !== null && _instance$multiCamera4 !== void 0 ? _instance$multiCamera4 : preTapIndex;
|
|
1132
1133
|
if (selectFired && currentIndex === preTapIndex) {
|
|
1133
1134
|
if (wasHidden) {
|
|
1134
1135
|
showComponents();
|
|
@@ -4,4 +4,6 @@ export type CaptureResultSummary = {
|
|
|
4
4
|
isMultiLens: boolean;
|
|
5
5
|
thumbnailPath: string;
|
|
6
6
|
};
|
|
7
|
-
|
|
7
|
+
/** 从新多目高级能力配置获取当前设备的总镜头数 */
|
|
8
|
+
export declare function getMultiLensCountFromAbility(devId: string): Promise<number>;
|
|
9
|
+
export declare function getCaptureResultSummary(result: CaptureResult, fallbackCount: number | undefined, devId: string): Promise<CaptureResultSummary | null>;
|
|
@@ -1,17 +1,67 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
|
|
3
|
+
import { getDeviceInfo } from './device';
|
|
4
|
+
const MULTI_LENS_ABILITY_CODE = 'tyabimr4v3';
|
|
5
|
+
const LENS_SUFFIX_PATTERN = /_lens\d+(?=\.[^./?#]+(?:[?#].*)?$)/;
|
|
6
|
+
const FILE_EXTENSION_PATTERN = /(\.[^./?#]+)([?#].*)?$/;
|
|
7
|
+
/** 从新多目高级能力配置获取当前设备的总镜头数 */
|
|
8
|
+
export async function getMultiLensCountFromAbility(devId) {
|
|
9
|
+
if (!devId) return 0;
|
|
10
|
+
try {
|
|
11
|
+
var _devInfo$configMetas;
|
|
12
|
+
const devInfo = await getDeviceInfo(devId);
|
|
13
|
+
const raw = devInfo === null || devInfo === void 0 || (_devInfo$configMetas = devInfo.configMetas) === null || _devInfo$configMetas === void 0 ? void 0 : _devInfo$configMetas[MULTI_LENS_ABILITY_CODE];
|
|
14
|
+
if (raw) {
|
|
15
|
+
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
16
|
+
const count = Number(parsed === null || parsed === void 0 ? void 0 : parsed.total_split_num) || (Array.isArray(parsed === null || parsed === void 0 ? void 0 : parsed.split_info) ? parsed.split_info.length : 0);
|
|
17
|
+
if (count > 1) {
|
|
18
|
+
return count;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
} catch (e) {
|
|
22
|
+
// ignore
|
|
23
|
+
}
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
const normalizeMultiLensThumbnailPath = path => {
|
|
27
|
+
if (!path || LENS_SUFFIX_PATTERN.test(path)) return path;
|
|
28
|
+
return path.replace(FILE_EXTENSION_PATTERN, '_lens1$1$2');
|
|
29
|
+
};
|
|
30
|
+
const extractPath = item => {
|
|
31
|
+
if (!item) return '';
|
|
32
|
+
if (typeof item === 'string') return item;
|
|
33
|
+
if (typeof (item === null || item === void 0 ? void 0 : item.value) === 'string') return item.value;
|
|
34
|
+
return '';
|
|
35
|
+
};
|
|
36
|
+
export async function getCaptureResultSummary(result, fallbackCount, devId) {
|
|
2
37
|
if (!result || typeof result === 'boolean') return null;
|
|
3
|
-
|
|
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) {
|
|
4
41
|
const firstItem = result.items[0];
|
|
5
|
-
|
|
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;
|
|
6
43
|
return {
|
|
7
44
|
count: result.items.length,
|
|
8
45
|
isMultiLens: true,
|
|
9
|
-
thumbnailPath:
|
|
46
|
+
thumbnailPath: firstThumb
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const legacySplitCount = fallbackCount && fallbackCount > 1 ? fallbackCount : 0;
|
|
50
|
+
const multiLensAbilityCount = legacySplitCount ? 0 : await getMultiLensCountFromAbility(devId);
|
|
51
|
+
|
|
52
|
+
// Preserve the legacy split protocol as a count fallback without applying the
|
|
53
|
+
// new multi-lens file-name convention to it.
|
|
54
|
+
const multiCount = legacySplitCount || multiLensAbilityCount;
|
|
55
|
+
if (multiCount > 1) {
|
|
56
|
+
return {
|
|
57
|
+
count: multiCount,
|
|
58
|
+
isMultiLens: true,
|
|
59
|
+
thumbnailPath: multiLensAbilityCount > 1 ? normalizeMultiLensThumbnailPath(singleThumb) : singleThumb
|
|
10
60
|
};
|
|
11
61
|
}
|
|
12
62
|
return {
|
|
13
63
|
count: 1,
|
|
14
64
|
isMultiLens: false,
|
|
15
|
-
thumbnailPath:
|
|
65
|
+
thumbnailPath: singleThumb
|
|
16
66
|
};
|
|
17
67
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { getCaptureResultSummary } from './captureResult';
|
|
2
|
+
import { getDeviceInfo } from './device';
|
|
3
|
+
jest.mock('./device', () => ({
|
|
4
|
+
getDeviceInfo: jest.fn()
|
|
5
|
+
}));
|
|
6
|
+
const mockGetDeviceInfo = getDeviceInfo;
|
|
7
|
+
const basePath = 'thingfile://tmp/capture_123.jpg';
|
|
8
|
+
const createCaptureResult = tempImagePath => ({
|
|
9
|
+
tempImagePath,
|
|
10
|
+
filePath: tempImagePath
|
|
11
|
+
});
|
|
12
|
+
describe('getCaptureResultSummary', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
mockGetDeviceInfo.mockReset();
|
|
15
|
+
mockGetDeviceInfo.mockResolvedValue({
|
|
16
|
+
configMetas: {}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
it('normalizes the thumbnail path for the new multi-lens ability', async () => {
|
|
20
|
+
mockGetDeviceInfo.mockResolvedValue({
|
|
21
|
+
configMetas: {
|
|
22
|
+
tyabimr4v3: {
|
|
23
|
+
total_split_num: 4
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
await expect(getCaptureResultSummary(createCaptureResult(basePath), undefined, 'dev-1')).resolves.toEqual({
|
|
28
|
+
count: 4,
|
|
29
|
+
isMultiLens: true,
|
|
30
|
+
thumbnailPath: 'thingfile://tmp/capture_123_lens1.jpg'
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
it('does not apply the new file-name convention to the legacy split protocol', async () => {
|
|
34
|
+
await expect(getCaptureResultSummary(createCaptureResult(basePath), 4, 'dev-1')).resolves.toEqual({
|
|
35
|
+
count: 4,
|
|
36
|
+
isMultiLens: true,
|
|
37
|
+
thumbnailPath: basePath
|
|
38
|
+
});
|
|
39
|
+
expect(mockGetDeviceInfo).not.toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
it('keeps the legacy path when both multi-lens sources are present', async () => {
|
|
42
|
+
mockGetDeviceInfo.mockResolvedValue({
|
|
43
|
+
configMetas: {
|
|
44
|
+
tyabimr4v3: {
|
|
45
|
+
total_split_num: 4
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
await expect(getCaptureResultSummary(createCaptureResult(basePath), 4, 'dev-1')).resolves.toEqual({
|
|
50
|
+
count: 4,
|
|
51
|
+
isMultiLens: true,
|
|
52
|
+
thumbnailPath: basePath
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
it('does not add a duplicate lens suffix', async () => {
|
|
56
|
+
mockGetDeviceInfo.mockResolvedValue({
|
|
57
|
+
configMetas: {
|
|
58
|
+
tyabimr4v3: JSON.stringify({
|
|
59
|
+
total_split_num: 4
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const path = 'thingfile://tmp/capture_123_lens1.jpg';
|
|
64
|
+
await expect(getCaptureResultSummary(createCaptureResult(path), undefined, 'dev-1')).resolves.toEqual({
|
|
65
|
+
count: 4,
|
|
66
|
+
isMultiLens: true,
|
|
67
|
+
thumbnailPath: path
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
it('keeps a mono result unchanged', async () => {
|
|
71
|
+
await expect(getCaptureResultSummary(createCaptureResult(basePath), undefined, 'dev-1')).resolves.toEqual({
|
|
72
|
+
count: 1,
|
|
73
|
+
isMultiLens: false,
|
|
74
|
+
thumbnailPath: basePath
|
|
75
|
+
});
|
|
76
|
+
});
|
|
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({
|
|
85
|
+
count: 1,
|
|
86
|
+
isMultiLens: true,
|
|
87
|
+
thumbnailPath: basePath
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -107,8 +107,18 @@ export function RecordVideo(props) {
|
|
|
107
107
|
shotUrl: '',
|
|
108
108
|
shotCount: 0
|
|
109
109
|
});
|
|
110
|
-
const
|
|
111
|
-
|
|
110
|
+
const recordResultRequestIdRef = useRef(0);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
return () => {
|
|
113
|
+
recordResultRequestIdRef.current += 1;
|
|
114
|
+
};
|
|
115
|
+
}, []);
|
|
116
|
+
const showRecordResult = async recordInfo => {
|
|
117
|
+
var _props$multiCameraCtx;
|
|
118
|
+
const requestId = ++recordResultRequestIdRef.current;
|
|
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);
|
|
121
|
+
if (requestId !== recordResultRequestIdRef.current) return;
|
|
112
122
|
if (!summary) return;
|
|
113
123
|
setState({
|
|
114
124
|
showTimer: false,
|
|
@@ -129,7 +139,7 @@ export function RecordVideo(props) {
|
|
|
129
139
|
showTimer: false
|
|
130
140
|
});
|
|
131
141
|
const recordInfo = await setRecording(false);
|
|
132
|
-
showRecordResult(recordInfo);
|
|
142
|
+
await showRecordResult(recordInfo);
|
|
133
143
|
} catch {
|
|
134
144
|
// setRecording reports the native failure through the configured toast.
|
|
135
145
|
}
|
|
@@ -245,6 +255,7 @@ export function RecordVideo(props) {
|
|
|
245
255
|
if (recordingDisabled) {
|
|
246
256
|
return false;
|
|
247
257
|
}
|
|
258
|
+
recordResultRequestIdRef.current += 1;
|
|
248
259
|
if (state.showShot && _recording) {
|
|
249
260
|
setState({
|
|
250
261
|
showShot: false
|
|
@@ -268,7 +279,7 @@ export function RecordVideo(props) {
|
|
|
268
279
|
timeToResetRecordDisabled();
|
|
269
280
|
} else {
|
|
270
281
|
props.event ? props.event.emit(changeIgnoreHideStopPreview, false) : event.emit(changeIgnoreHideStopPreview, false);
|
|
271
|
-
showRecordResult(recordInfo);
|
|
282
|
+
await showRecordResult(recordInfo);
|
|
272
283
|
}
|
|
273
284
|
} catch (err) {
|
|
274
285
|
props.event ? props.event.emit(changeIgnoreHideStopPreview, false) : event.emit(changeIgnoreHideStopPreview, false);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import React, { useContext, useRef } from 'react';
|
|
1
|
+
import React, { useContext, useEffect, useRef } from 'react';
|
|
3
2
|
import { View, Text, showModal, openAppSystemSettingPage, getSystemInfoSync } from '@ray-js/ray';
|
|
4
3
|
import { useSetState, useUpdateEffect, useMemoizedFn } from 'ahooks';
|
|
5
4
|
import clsx from 'clsx';
|
|
@@ -40,6 +39,12 @@ export function Screenshot(props) {
|
|
|
40
39
|
shotUrl: '',
|
|
41
40
|
shotCount: 0
|
|
42
41
|
});
|
|
42
|
+
const snapshotRequestIdRef = useRef(0);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
return () => {
|
|
45
|
+
snapshotRequestIdRef.current += 1;
|
|
46
|
+
};
|
|
47
|
+
}, []);
|
|
43
48
|
useUpdateEffect(() => {
|
|
44
49
|
if (state.showShot && screenType) {
|
|
45
50
|
showShotToast();
|
|
@@ -127,14 +132,15 @@ export function Screenshot(props) {
|
|
|
127
132
|
});
|
|
128
133
|
};
|
|
129
134
|
const takeSnapshot = () => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
success: res => {
|
|
135
|
+
const requestId = ++snapshotRequestIdRef.current;
|
|
136
|
+
IPCPlayerContext.snapshot({
|
|
137
|
+
saveToAlbum,
|
|
138
|
+
success: async res => {
|
|
139
|
+
var _props$multiCameraCtx;
|
|
136
140
|
setIgnoreHideStopPreview(false);
|
|
137
|
-
const
|
|
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);
|
|
143
|
+
if (requestId !== snapshotRequestIdRef.current) return;
|
|
138
144
|
if (!summary) {
|
|
139
145
|
handleSnapshotFail({});
|
|
140
146
|
return;
|
|
@@ -146,7 +152,7 @@ export function Screenshot(props) {
|
|
|
146
152
|
});
|
|
147
153
|
},
|
|
148
154
|
fail: handleSnapshotFail
|
|
149
|
-
})
|
|
155
|
+
});
|
|
150
156
|
};
|
|
151
157
|
ty.authorizeStatus({
|
|
152
158
|
// 相册写入权限
|