@ray-js/ipc-player-integration 0.0.35-beta.1 → 0.0.35-beta.3
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.composition.js +5 -1
- package/lib/features/initPlayerWidgets/index.d.ts +1 -0
- package/lib/features/initPlayerWidgets/index.js +9 -0
- package/lib/i18n/index.d.ts +20 -0
- package/lib/i18n/strings.d.ts +10 -0
- package/lib/i18n/strings.js +12 -2
- package/lib/interface.d.ts +1 -1
- package/lib/res/try/try_close.png +0 -0
- package/lib/res/try/try_en.png +0 -0
- package/lib/res/try/try_open.png +0 -0
- package/lib/res/try/try_zh.png +0 -0
- package/lib/ui/bottomLeftContent.d.ts +3 -1
- package/lib/ui/bottomLeftContent.js +86 -8
- package/lib/ui/bottomRightContent.d.ts +3 -1
- package/lib/ui/bottomRightContent.js +11 -4
- package/lib/ui/constant.d.ts +8 -0
- package/lib/ui/constant.js +10 -0
- package/lib/ui/index.d.ts +1 -1
- package/lib/ui/index.js +1 -1
- package/lib/ui/ui.js +31 -3
- package/lib/ui/ui.less +5 -1
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +3 -1
- package/lib/utils/navigation.d.ts +6 -0
- package/lib/utils/navigation.js +20 -0
- package/lib/utils/ttt.d.ts +39 -0
- package/lib/utils/ttt.js +87 -0
- package/lib/widgets/index.d.ts +2 -0
- package/lib/widgets/index.js +2 -0
- package/lib/widgets/trialBadge/index.d.ts +17 -0
- package/lib/widgets/trialBadge/index.js +88 -0
- package/lib/widgets/trialBadge/index.less +57 -0
- package/lib/widgets/trialBadge/useTrialBadge.d.ts +8 -0
- package/lib/widgets/trialBadge/useTrialBadge.js +48 -0
- package/lib/widgets/tryExperience/index.d.ts +1 -0
- package/lib/widgets/tryExperience/index.js +1 -0
- package/lib/widgets/tryExperience/tryExperience.d.ts +10 -0
- package/lib/widgets/tryExperience/tryExperience.js +68 -0
- package/lib/widgets/tryExperience/tryExperience.less +13 -0
- package/package.json +2 -2
|
@@ -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, 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 } 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';
|
|
@@ -47,6 +47,10 @@ export const defaultBottomLeftContent = [{
|
|
|
47
47
|
}, {
|
|
48
48
|
id: 'Siren',
|
|
49
49
|
content: Siren
|
|
50
|
+
}, /* TryExperience 必须紧跟 Muted,在 VerticalSmallIntercom 之前 */
|
|
51
|
+
{
|
|
52
|
+
id: 'TryExperience',
|
|
53
|
+
content: TryExperience
|
|
50
54
|
}, {
|
|
51
55
|
id: 'VerticalSmallIntercom',
|
|
52
56
|
content: VerticalSmallIntercom
|
|
@@ -13,6 +13,7 @@ export type InitPlayerWidgetsOptions = {
|
|
|
13
13
|
showToggleVerticalFull?: boolean;
|
|
14
14
|
showRealTimeMagnification?: boolean;
|
|
15
15
|
directionControlProps?: Partial<React.ComponentProps<typeof FullScreen>['directionControlProps']>;
|
|
16
|
+
hideSmartImageQualityState?: boolean;
|
|
16
17
|
topLeftContent?: ComponentConfig[];
|
|
17
18
|
topRightContent?: ComponentConfig[];
|
|
18
19
|
bottomLeftContent?: ComponentConfig[];
|
|
@@ -17,8 +17,16 @@ export async function initPlayerWidgets(ctx, options) {
|
|
|
17
17
|
}
|
|
18
18
|
ctx.addContent('topRight', newDefaultTopRightContent);
|
|
19
19
|
const resolutionIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'Resolution');
|
|
20
|
+
const tryExperienceIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'TryExperience');
|
|
20
21
|
const screenShotIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'Screenshot');
|
|
21
22
|
const recordVideoIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'RecordVideo');
|
|
23
|
+
if (tryExperienceIndex !== -1) {
|
|
24
|
+
var _options$hideSmartIma;
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
newDefaultBottomLeftContent[tryExperienceIndex].initProps = {
|
|
27
|
+
hideTryExperienceMenu: (_options$hideSmartIma = options.hideSmartImageQualityState) !== null && _options$hideSmartIma !== void 0 ? _options$hideSmartIma : true
|
|
28
|
+
};
|
|
29
|
+
}
|
|
22
30
|
if (resolutionIndex !== -1) {
|
|
23
31
|
// @ts-ignore
|
|
24
32
|
newDefaultBottomLeftContent[resolutionIndex].initProps = {
|
|
@@ -44,6 +52,7 @@ export async function initPlayerWidgets(ctx, options) {
|
|
|
44
52
|
newDefaultBottomLeftContent[magnificationIndex].hidden = false;
|
|
45
53
|
}
|
|
46
54
|
}
|
|
55
|
+
console.log('res===1', newDefaultBottomLeftContent);
|
|
47
56
|
ctx.addContent('bottomLeft', newDefaultBottomLeftContent);
|
|
48
57
|
const newDefaultBottomRightContent = _cloneDeep(options.bottomRightContent || defaultBottomRightContent);
|
|
49
58
|
const fullScreenIndex = newDefaultBottomRightContent.findIndex(item => item.id === 'FullScreen');
|
package/lib/i18n/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ declare const Strings: kit.I18N<{
|
|
|
20
20
|
ipc_player_authorize_confirm_text: string;
|
|
21
21
|
ipc_player_error_record_tip: string;
|
|
22
22
|
ipc_player_change_resolution_success: string;
|
|
23
|
+
ipc_player_try_experience: string;
|
|
23
24
|
ipc_player_ptz_control_tip: string;
|
|
24
25
|
ipc_player_ptz_close_control_tip: string;
|
|
25
26
|
ipc_player_tile_tip_text_step1: string;
|
|
@@ -28,6 +29,10 @@ declare const Strings: kit.I18N<{
|
|
|
28
29
|
ipc_player_tip_confirm: string;
|
|
29
30
|
ipc_player_ptz_moveable_tip_text: string;
|
|
30
31
|
ipc_player_flow_low_tip: string;
|
|
32
|
+
ipc_player_trial_in_use: string;
|
|
33
|
+
ipc_player_trial_preview_text: string;
|
|
34
|
+
ipc_player_trial_subscribe: string;
|
|
35
|
+
ipc_player_fetch_error: string;
|
|
31
36
|
};
|
|
32
37
|
zh: {
|
|
33
38
|
ipc_player_resolution_HD: string;
|
|
@@ -49,6 +54,7 @@ declare const Strings: kit.I18N<{
|
|
|
49
54
|
ipc_player_authorize_confirm_text: string;
|
|
50
55
|
ipc_player_error_record_tip: string;
|
|
51
56
|
ipc_player_change_resolution_success: string;
|
|
57
|
+
ipc_player_try_experience: string;
|
|
52
58
|
ipc_player_ptz_control_tip: string;
|
|
53
59
|
ipc_player_ptz_close_control_tip: string;
|
|
54
60
|
ipc_player_tile_tip_text_step1: string;
|
|
@@ -57,6 +63,10 @@ declare const Strings: kit.I18N<{
|
|
|
57
63
|
ipc_player_tip_confirm: string;
|
|
58
64
|
ipc_player_ptz_moveable_tip_text: string;
|
|
59
65
|
ipc_player_flow_low_tip: string;
|
|
66
|
+
ipc_player_trial_in_use: string;
|
|
67
|
+
ipc_player_trial_preview_text: string;
|
|
68
|
+
ipc_player_trial_subscribe: string;
|
|
69
|
+
ipc_player_fetch_error: string;
|
|
60
70
|
};
|
|
61
71
|
}, {
|
|
62
72
|
ipc_player_resolution_HD: string;
|
|
@@ -78,6 +88,7 @@ declare const Strings: kit.I18N<{
|
|
|
78
88
|
ipc_player_authorize_confirm_text: string;
|
|
79
89
|
ipc_player_error_record_tip: string;
|
|
80
90
|
ipc_player_change_resolution_success: string;
|
|
91
|
+
ipc_player_try_experience: string;
|
|
81
92
|
ipc_player_ptz_control_tip: string;
|
|
82
93
|
ipc_player_ptz_close_control_tip: string;
|
|
83
94
|
ipc_player_tile_tip_text_step1: string;
|
|
@@ -86,6 +97,10 @@ declare const Strings: kit.I18N<{
|
|
|
86
97
|
ipc_player_tip_confirm: string;
|
|
87
98
|
ipc_player_ptz_moveable_tip_text: string;
|
|
88
99
|
ipc_player_flow_low_tip: string;
|
|
100
|
+
ipc_player_trial_in_use: string;
|
|
101
|
+
ipc_player_trial_preview_text: string;
|
|
102
|
+
ipc_player_trial_subscribe: string;
|
|
103
|
+
ipc_player_fetch_error: string;
|
|
89
104
|
} | {
|
|
90
105
|
ipc_player_resolution_HD: string;
|
|
91
106
|
ipc_player_resolution_SD: string;
|
|
@@ -106,6 +121,7 @@ declare const Strings: kit.I18N<{
|
|
|
106
121
|
ipc_player_authorize_confirm_text: string;
|
|
107
122
|
ipc_player_error_record_tip: string;
|
|
108
123
|
ipc_player_change_resolution_success: string;
|
|
124
|
+
ipc_player_try_experience: string;
|
|
109
125
|
ipc_player_ptz_control_tip: string;
|
|
110
126
|
ipc_player_ptz_close_control_tip: string;
|
|
111
127
|
ipc_player_tile_tip_text_step1: string;
|
|
@@ -114,5 +130,9 @@ declare const Strings: kit.I18N<{
|
|
|
114
130
|
ipc_player_tip_confirm: string;
|
|
115
131
|
ipc_player_ptz_moveable_tip_text: string;
|
|
116
132
|
ipc_player_flow_low_tip: string;
|
|
133
|
+
ipc_player_trial_in_use: string;
|
|
134
|
+
ipc_player_trial_preview_text: string;
|
|
135
|
+
ipc_player_trial_subscribe: string;
|
|
136
|
+
ipc_player_fetch_error: string;
|
|
117
137
|
}>;
|
|
118
138
|
export default Strings;
|
package/lib/i18n/strings.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ declare const _default: {
|
|
|
19
19
|
ipc_player_authorize_confirm_text: string;
|
|
20
20
|
ipc_player_error_record_tip: string;
|
|
21
21
|
ipc_player_change_resolution_success: string;
|
|
22
|
+
ipc_player_try_experience: string;
|
|
22
23
|
ipc_player_ptz_control_tip: string;
|
|
23
24
|
ipc_player_ptz_close_control_tip: string;
|
|
24
25
|
ipc_player_tile_tip_text_step1: string;
|
|
@@ -27,6 +28,10 @@ declare const _default: {
|
|
|
27
28
|
ipc_player_tip_confirm: string;
|
|
28
29
|
ipc_player_ptz_moveable_tip_text: string;
|
|
29
30
|
ipc_player_flow_low_tip: string;
|
|
31
|
+
ipc_player_trial_in_use: string;
|
|
32
|
+
ipc_player_trial_preview_text: string;
|
|
33
|
+
ipc_player_trial_subscribe: string;
|
|
34
|
+
ipc_player_fetch_error: string;
|
|
30
35
|
};
|
|
31
36
|
zh: {
|
|
32
37
|
ipc_player_resolution_HD: string;
|
|
@@ -48,6 +53,7 @@ declare const _default: {
|
|
|
48
53
|
ipc_player_authorize_confirm_text: string;
|
|
49
54
|
ipc_player_error_record_tip: string;
|
|
50
55
|
ipc_player_change_resolution_success: string;
|
|
56
|
+
ipc_player_try_experience: string;
|
|
51
57
|
ipc_player_ptz_control_tip: string;
|
|
52
58
|
ipc_player_ptz_close_control_tip: string;
|
|
53
59
|
ipc_player_tile_tip_text_step1: string;
|
|
@@ -56,6 +62,10 @@ declare const _default: {
|
|
|
56
62
|
ipc_player_tip_confirm: string;
|
|
57
63
|
ipc_player_ptz_moveable_tip_text: string;
|
|
58
64
|
ipc_player_flow_low_tip: string;
|
|
65
|
+
ipc_player_trial_in_use: string;
|
|
66
|
+
ipc_player_trial_preview_text: string;
|
|
67
|
+
ipc_player_trial_subscribe: string;
|
|
68
|
+
ipc_player_fetch_error: string;
|
|
59
69
|
};
|
|
60
70
|
};
|
|
61
71
|
export default _default;
|
package/lib/i18n/strings.js
CHANGED
|
@@ -19,6 +19,7 @@ export default {
|
|
|
19
19
|
ipc_player_authorize_confirm_text: 'Go to Settings',
|
|
20
20
|
ipc_player_error_record_tip: 'The recording has failed, please try again later.',
|
|
21
21
|
ipc_player_change_resolution_success: 'Switch successful',
|
|
22
|
+
ipc_player_try_experience: 'Try it',
|
|
22
23
|
ipc_player_ptz_control_tip: 'Swipe up, down, left, or right to control the PTZ direction.',
|
|
23
24
|
ipc_player_ptz_close_control_tip: 'Close',
|
|
24
25
|
ipc_player_tile_tip_text_step1: 'Click here to expand/collapse the player',
|
|
@@ -26,7 +27,11 @@ export default {
|
|
|
26
27
|
ipc_player_tip_next: 'Next',
|
|
27
28
|
ipc_player_tip_confirm: 'Got it',
|
|
28
29
|
ipc_player_ptz_moveable_tip_text: 'Hold the middle to drag the direction control area',
|
|
29
|
-
ipc_player_flow_low_tip: 'The device’s remaining data is below 200MB. Please recharge as soon as possible.'
|
|
30
|
+
ipc_player_flow_low_tip: 'The device’s remaining data is below 200MB. Please recharge as soon as possible.',
|
|
31
|
+
ipc_player_trial_in_use: 'Trial',
|
|
32
|
+
ipc_player_trial_preview_text: 'End',
|
|
33
|
+
ipc_player_trial_subscribe: 'Open',
|
|
34
|
+
ipc_player_fetch_error: 'Failed to fetch data'
|
|
30
35
|
},
|
|
31
36
|
zh: {
|
|
32
37
|
ipc_player_resolution_HD: '高清',
|
|
@@ -48,6 +53,7 @@ export default {
|
|
|
48
53
|
ipc_player_authorize_confirm_text: '去设置',
|
|
49
54
|
ipc_player_error_record_tip: '录制出错了,请稍后再试',
|
|
50
55
|
ipc_player_change_resolution_success: '切换成功',
|
|
56
|
+
ipc_player_try_experience: '去体验',
|
|
51
57
|
ipc_player_ptz_control_tip: '上下左右滑动,控制云台方向',
|
|
52
58
|
ipc_player_ptz_close_control_tip: '关闭',
|
|
53
59
|
ipc_player_tile_tip_text_step1: '点击此处可展开/收起播放窗口',
|
|
@@ -55,6 +61,10 @@ export default {
|
|
|
55
61
|
ipc_player_tip_next: '下一步',
|
|
56
62
|
ipc_player_tip_confirm: '知道了',
|
|
57
63
|
ipc_player_ptz_moveable_tip_text: '长按中间可拖动方向控制区域',
|
|
58
|
-
ipc_player_flow_low_tip: '设备当前剩余流量不足200M,请尽快充值'
|
|
64
|
+
ipc_player_flow_low_tip: '设备当前剩余流量不足200M,请尽快充值',
|
|
65
|
+
ipc_player_trial_in_use: '试用中',
|
|
66
|
+
ipc_player_trial_preview_text: '后结束',
|
|
67
|
+
ipc_player_trial_subscribe: '开通',
|
|
68
|
+
ipc_player_fetch_error: '获取异常'
|
|
59
69
|
}
|
|
60
70
|
};
|
package/lib/interface.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type IpcContext = {
|
|
|
11
11
|
};
|
|
12
12
|
export type RetAtom<T> = PrimitiveAtom<T> & WithInitialValue<T>;
|
|
13
13
|
export type ScreenType = 'full' | 'vertical';
|
|
14
|
-
export type WidgetId = 'BatteryFull' | 'TempHumidity' | 'VideoBitKBP' | 'FullSmallIntercom' | 'Screenshot' | 'RecordVideo' | 'Muted' | 'Floodlight' | 'Siren' | 'VerticalSmallIntercom' | 'Ptz' | 'Resolution' | 'FullScreen' | 'moveablePtzControlId';
|
|
14
|
+
export type WidgetId = 'BatteryFull' | 'TempHumidity' | 'VideoBitKBP' | 'FullSmallIntercom' | 'Screenshot' | 'RecordVideo' | 'Muted' | 'Floodlight' | 'Siren' | 'TryExperience' | 'VerticalSmallIntercom' | 'Ptz' | 'Resolution' | 'FullScreen' | 'moveablePtzControlId';
|
|
15
15
|
export declare const enum PlayerStreamStatus {
|
|
16
16
|
UnknownException = -1000,
|
|
17
17
|
ConnectSuccess = 1001,
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3,6 +3,8 @@ import { UseCtx } from '../interface';
|
|
|
3
3
|
type Props = {
|
|
4
4
|
ctx: ReturnType<UseCtx>;
|
|
5
5
|
children: React.ReactNode;
|
|
6
|
+
/** 右下角组件占据的宽度(px),左下角通过该值约束自身可视宽度,避免与右下角重叠 */
|
|
7
|
+
reservedRight?: number;
|
|
6
8
|
};
|
|
7
|
-
declare const BottomLeftContent: ({ ctx, children }: Props) => React.JSX.Element;
|
|
9
|
+
declare const BottomLeftContent: ({ ctx, children, reservedRight }: Props) => React.JSX.Element;
|
|
8
10
|
export default BottomLeftContent;
|
|
@@ -1,30 +1,108 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
3
|
+
import "core-js/modules/esnext.iterator.find.js";
|
|
4
|
+
import React, { useMemo } from 'react';
|
|
2
5
|
import { CoverView, View } from '@ray-js/ray';
|
|
3
6
|
import clsx from 'clsx';
|
|
4
7
|
import { useStore } from '../ctx/store';
|
|
5
8
|
import { useComponentHideState } from './hooks';
|
|
9
|
+
import { TrialBadge, useTrialBadge } from '../widgets/trialBadge';
|
|
10
|
+
/** 右侧透明渐变宽度,用于提示横向可滑动 */
|
|
11
|
+
const FADE_MASK = 'linear-gradient(to right, #000 calc(100% - 16px), transparent 100%)';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 试用徽章在不同 screenType 下的容器样式。
|
|
15
|
+
* 「贴在底栏顶部」的策略一致(bottom: 100%),只是 left / marginBottom
|
|
16
|
+
* 等数值按横竖屏不同的边距规则做差异化处理。
|
|
17
|
+
*/
|
|
18
|
+
const TRIAL_BADGE_WRAP_STYLE_VERTICAL = {
|
|
19
|
+
position: 'absolute',
|
|
20
|
+
left: '0px',
|
|
21
|
+
bottom: '100%',
|
|
22
|
+
marginBottom: 4,
|
|
23
|
+
zIndex: 2,
|
|
24
|
+
width: 'max-content'
|
|
25
|
+
};
|
|
26
|
+
const TRIAL_BADGE_WRAP_STYLE_FULL = {
|
|
27
|
+
position: 'absolute',
|
|
28
|
+
left: '25px',
|
|
29
|
+
bottom: '100%',
|
|
30
|
+
marginBottom: 8,
|
|
31
|
+
zIndex: 2,
|
|
32
|
+
width: 'max-content'
|
|
33
|
+
};
|
|
6
34
|
const BottomLeftContent = _ref => {
|
|
7
35
|
let {
|
|
8
36
|
ctx,
|
|
9
|
-
children
|
|
37
|
+
children,
|
|
38
|
+
reservedRight = 0
|
|
10
39
|
} = _ref;
|
|
11
40
|
const {
|
|
12
|
-
screenType
|
|
41
|
+
screenType,
|
|
42
|
+
brandColor,
|
|
43
|
+
bottomLeftContent
|
|
13
44
|
} = useStore({
|
|
14
45
|
screenType: ctx.screenType,
|
|
15
|
-
playState: ctx.playState
|
|
46
|
+
playState: ctx.playState,
|
|
47
|
+
brandColor: ctx.brandColor,
|
|
48
|
+
bottomLeftContent: ctx.bottomLeftContent
|
|
16
49
|
});
|
|
50
|
+
const showSmartImageQuality = useMemo(() => {
|
|
51
|
+
var _tryExp$initProps;
|
|
52
|
+
const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
|
|
53
|
+
return !(tryExp !== null && tryExp !== void 0 && (_tryExp$initProps = tryExp.initProps) !== null && _tryExp$initProps !== void 0 && _tryExp$initProps.hideTryExperienceMenu);
|
|
54
|
+
}, [bottomLeftContent]);
|
|
55
|
+
const trialRemainingSec = useMemo(() => {
|
|
56
|
+
var _trialRemainingSec, _tryExp$initProps2;
|
|
57
|
+
const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
|
|
58
|
+
return (_trialRemainingSec = tryExp === null || tryExp === void 0 || (_tryExp$initProps2 = tryExp.initProps) === null || _tryExp$initProps2 === void 0 ? void 0 : _tryExp$initProps2.trialRemainingSec) !== null && _trialRemainingSec !== void 0 ? _trialRemainingSec : 0;
|
|
59
|
+
}, [bottomLeftContent]);
|
|
60
|
+
const refreshToken = useMemo(() => {
|
|
61
|
+
var _refreshToken, _tryExp$initProps3;
|
|
62
|
+
const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
|
|
63
|
+
return (_refreshToken = tryExp === null || tryExp === void 0 || (_tryExp$initProps3 = tryExp.initProps) === null || _tryExp$initProps3 === void 0 ? void 0 : _tryExp$initProps3.refreshToken) !== null && _refreshToken !== void 0 ? _refreshToken : 0;
|
|
64
|
+
}, [bottomLeftContent]);
|
|
17
65
|
const [shouldHide] = useComponentHideState();
|
|
66
|
+
const {
|
|
67
|
+
showTrialBadge,
|
|
68
|
+
handleTrialSubscribe,
|
|
69
|
+
handleCountdownEnd
|
|
70
|
+
} = useTrialBadge(ctx.event, ctx.devId, trialRemainingSec);
|
|
71
|
+
const paddingLeftPx = screenType === 'vertical' ? 0 : 25;
|
|
72
|
+
const trialBadgeWrapStyle = screenType === 'vertical' ? TRIAL_BADGE_WRAP_STYLE_VERTICAL : TRIAL_BADGE_WRAP_STYLE_FULL;
|
|
18
73
|
return /*#__PURE__*/React.createElement(CoverView, {
|
|
19
|
-
className: clsx('ipc-player-bottom-left-content-wrap')
|
|
74
|
+
className: clsx('ipc-player-bottom-left-content-wrap')
|
|
75
|
+
// 注意:不要在这里覆盖 position,CSS 类已经设置 position: absolute; left: 0; bottom: 0
|
|
76
|
+
// 否则 children 会失去贴底定位,从而与 bottomRightContent 不对齐
|
|
77
|
+
,
|
|
20
78
|
style: {
|
|
21
|
-
|
|
79
|
+
right: `${reservedRight}px`,
|
|
22
80
|
height: screenType === 'vertical' ? shouldHide ? '41px' : '40px' : shouldHide ? '57px' : '58px'
|
|
23
81
|
}
|
|
24
|
-
}, /*#__PURE__*/React.createElement(View, {
|
|
82
|
+
}, showSmartImageQuality && showTrialBadge && /*#__PURE__*/React.createElement(View, {
|
|
83
|
+
className: clsx('bottom-left-item-container'),
|
|
84
|
+
style: _objectSpread(_objectSpread({}, trialBadgeWrapStyle), {}, {
|
|
85
|
+
transform: shouldHide ? 'translateY(40px)' : 'translateY(0)',
|
|
86
|
+
opacity: shouldHide ? 0 : 1,
|
|
87
|
+
transition: 'transform 0.3s ease-in-out, opacity 0.3s ease-in-out'
|
|
88
|
+
})
|
|
89
|
+
}, /*#__PURE__*/React.createElement(TrialBadge, {
|
|
90
|
+
brandColor: brandColor,
|
|
91
|
+
trialRemainingSec: trialRemainingSec,
|
|
92
|
+
refreshToken: refreshToken,
|
|
93
|
+
onSubscribe: handleTrialSubscribe,
|
|
94
|
+
onCountdownEnd: handleCountdownEnd
|
|
95
|
+
})), /*#__PURE__*/React.createElement(View, {
|
|
25
96
|
style: {
|
|
26
97
|
paddingBottom: screenType === 'vertical' ? '14px' : '32px',
|
|
27
|
-
paddingLeft:
|
|
98
|
+
paddingLeft: `${paddingLeftPx}px`,
|
|
99
|
+
width: '100%',
|
|
100
|
+
overflowX: 'auto',
|
|
101
|
+
overflowY: 'hidden',
|
|
102
|
+
whiteSpace: 'nowrap',
|
|
103
|
+
WebkitOverflowScrolling: 'touch',
|
|
104
|
+
WebkitMaskImage: FADE_MASK,
|
|
105
|
+
maskImage: FADE_MASK
|
|
28
106
|
},
|
|
29
107
|
className: clsx('ipc-player-bottom-left-content-container', {
|
|
30
108
|
// 'ipc-player-bottom-left-content-hide': shouldHide,
|
|
@@ -3,6 +3,8 @@ import { UseCtx } from '../interface';
|
|
|
3
3
|
type Props = {
|
|
4
4
|
ctx: ReturnType<UseCtx>;
|
|
5
5
|
children: React.ReactNode;
|
|
6
|
+
/** 由 ui.tsx 计算得到的右下角组件宽度(与左下角的 reservedRight 保持一致) */
|
|
7
|
+
width?: number;
|
|
6
8
|
};
|
|
7
|
-
declare const BottomRightContent: ({ ctx, children }: Props) => React.JSX.Element;
|
|
9
|
+
declare const BottomRightContent: ({ ctx, children, width }: Props) => React.JSX.Element;
|
|
8
10
|
export default BottomRightContent;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import { CoverView, View } from '@ray-js/ray';
|
|
3
4
|
import clsx from 'clsx';
|
|
@@ -6,7 +7,8 @@ import { useComponentHideState } from './hooks';
|
|
|
6
7
|
const BottomRightContent = _ref => {
|
|
7
8
|
let {
|
|
8
9
|
ctx,
|
|
9
|
-
children
|
|
10
|
+
children,
|
|
11
|
+
width
|
|
10
12
|
} = _ref;
|
|
11
13
|
const {
|
|
12
14
|
screenType
|
|
@@ -17,14 +19,19 @@ const BottomRightContent = _ref => {
|
|
|
17
19
|
const [shouldHide] = useComponentHideState();
|
|
18
20
|
return /*#__PURE__*/React.createElement(CoverView, {
|
|
19
21
|
className: clsx('ipc-player-bottom-right-content-wrap'),
|
|
20
|
-
style: {
|
|
22
|
+
style: _objectSpread({
|
|
21
23
|
paddingLeft: screenType === 'vertical' ? '10px' : '0',
|
|
22
24
|
height: screenType === 'vertical' ? shouldHide ? '41px' : '40px' : shouldHide ? '57px' : '58px'
|
|
23
|
-
}
|
|
25
|
+
}, typeof width === 'number' && width > 0 ? {
|
|
26
|
+
width: `${width}px`,
|
|
27
|
+
boxSizing: 'border-box'
|
|
28
|
+
} : null)
|
|
24
29
|
}, /*#__PURE__*/React.createElement(View, {
|
|
25
30
|
style: {
|
|
26
31
|
paddingBottom: screenType === 'vertical' ? '14px' : '32px',
|
|
27
|
-
paddingRight: screenType === 'vertical' ? 0 : '25px'
|
|
32
|
+
paddingRight: screenType === 'vertical' ? 0 : '25px',
|
|
33
|
+
width: '100%',
|
|
34
|
+
justifyContent: 'flex-end'
|
|
28
35
|
},
|
|
29
36
|
className: clsx('ipc-player-bottom-right-content-container', {
|
|
30
37
|
// 'ipc-player-bottom-right-content-hide': shouldHide,
|
package/lib/ui/constant.d.ts
CHANGED
|
@@ -21,11 +21,19 @@ export declare const landscapeTipId = "landscapeTipId";
|
|
|
21
21
|
export declare const multiPtzId = "multiPtzId";
|
|
22
22
|
/** 控件点击统一事件:任意播放器内控件被点击时触发,可用于埋点或统一处理 */
|
|
23
23
|
export declare const widgetClick = "widgetClick";
|
|
24
|
+
/** 「去体验」按钮业务事件,与清晰度 resolutionBtnControlClick 用法一致 */
|
|
25
|
+
export declare const tryExperienceBtnClick = "tryExperienceBtnClick";
|
|
26
|
+
/**
|
|
27
|
+
* 试看倒计时结束事件:试看徽章倒计时归零时触发,
|
|
28
|
+
* 业务侧/相关控件可监听此事件刷新自己的状态(例如 TryExperience 重新拉取状态)
|
|
29
|
+
*/
|
|
30
|
+
export declare const trialCountdownEnd = "trialCountdownEnd";
|
|
24
31
|
/** 控件点击事件用的 widgetId,统一在此维护 */
|
|
25
32
|
export declare const widgetLabs: {
|
|
26
33
|
readonly SCREENSHOT: "Screenshot";
|
|
27
34
|
readonly RECORD_VIDEO: "RecordVideo";
|
|
28
35
|
readonly RESOLUTION: "Resolution";
|
|
36
|
+
readonly TRY_EXPERIENCE: "TryExperience";
|
|
29
37
|
readonly FULL_RESOLUTION_CONTROL: "FullResolutionControl";
|
|
30
38
|
readonly MUTED: "Muted";
|
|
31
39
|
readonly FLOODLIGHT: "Floodlight";
|
package/lib/ui/constant.js
CHANGED
|
@@ -22,11 +22,21 @@ export const multiPtzId = 'multiPtzId';
|
|
|
22
22
|
/** 控件点击统一事件:任意播放器内控件被点击时触发,可用于埋点或统一处理 */
|
|
23
23
|
export const widgetClick = 'widgetClick';
|
|
24
24
|
|
|
25
|
+
/** 「去体验」按钮业务事件,与清晰度 resolutionBtnControlClick 用法一致 */
|
|
26
|
+
export const tryExperienceBtnClick = 'tryExperienceBtnClick';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 试看倒计时结束事件:试看徽章倒计时归零时触发,
|
|
30
|
+
* 业务侧/相关控件可监听此事件刷新自己的状态(例如 TryExperience 重新拉取状态)
|
|
31
|
+
*/
|
|
32
|
+
export const trialCountdownEnd = 'trialCountdownEnd';
|
|
33
|
+
|
|
25
34
|
/** 控件点击事件用的 widgetId,统一在此维护 */
|
|
26
35
|
export const widgetLabs = {
|
|
27
36
|
SCREENSHOT: 'Screenshot',
|
|
28
37
|
RECORD_VIDEO: 'RecordVideo',
|
|
29
38
|
RESOLUTION: 'Resolution',
|
|
39
|
+
TRY_EXPERIENCE: 'TryExperience',
|
|
30
40
|
FULL_RESOLUTION_CONTROL: 'FullResolutionControl',
|
|
31
41
|
MUTED: 'Muted',
|
|
32
42
|
FLOODLIGHT: 'Floodlight',
|
package/lib/ui/index.d.ts
CHANGED
package/lib/ui/index.js
CHANGED
package/lib/ui/ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
2
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
3
|
+
import "core-js/modules/esnext.iterator.filter.js";
|
|
3
4
|
import "core-js/modules/esnext.iterator.map.js";
|
|
4
5
|
import React, { useContext, useState, useRef, useMemo, useEffect, useImperativeHandle } from 'react';
|
|
5
6
|
import { View, CoverView, getSystemInfoSync, usePageEvent, setNavigationBarBack, setPageOrientation, getCurrentPages } from '@ray-js/ray';
|
|
@@ -22,6 +23,7 @@ import { Storage } from '../utils/storage';
|
|
|
22
23
|
import './ui.less';
|
|
23
24
|
import { updatePlayerWidgetProps } from '../features';
|
|
24
25
|
import { isSmallScreen } from '../utils';
|
|
26
|
+
import { getSmartImageQualityState } from '../utils/ttt';
|
|
25
27
|
function getCtxInstance(instance, devId) {
|
|
26
28
|
if (instance) return instance;
|
|
27
29
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -423,6 +425,19 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
423
425
|
setBrandColor(brandColor);
|
|
424
426
|
setVerticalMic(verticalMic);
|
|
425
427
|
}, [brandColor, verticalMic]);
|
|
428
|
+
const refreshSmartImageQuality = useMemoizedFn(() => {
|
|
429
|
+
getSmartImageQualityState(devId).then(res => {
|
|
430
|
+
console.log('res===getSmartImageQualityState', res);
|
|
431
|
+
updatePlayerWidgetProps(instance, 'bottomLeft', 'TryExperience', {
|
|
432
|
+
buttonState: res.buttonState,
|
|
433
|
+
trialRemainingSec: res.trialRemainingSec,
|
|
434
|
+
refreshToken: Date.now()
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
useEffect(() => {
|
|
439
|
+
refreshSmartImageQuality();
|
|
440
|
+
}, [instance]);
|
|
426
441
|
const refreshBottomLeft = () => {
|
|
427
442
|
event.current.emit(startTimeToHideAllComponent);
|
|
428
443
|
event.current.emit(showAllComponent);
|
|
@@ -622,7 +637,18 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
622
637
|
// 添加通用变量单独组件类名
|
|
623
638
|
className: clsx('bottom-right-item-container')
|
|
624
639
|
})));
|
|
625
|
-
}, [
|
|
640
|
+
}, [bottomRightContent, instance]);
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* 右下角可见按钮数 → 右下角组件宽度(左下角同时用作右侧预留宽度)
|
|
644
|
+
* 1 个按钮: 115px / 2 个按钮: 132px / 0 个按钮: 0
|
|
645
|
+
*/
|
|
646
|
+
const bottomRightWidth = useMemo(() => {
|
|
647
|
+
const visibleCount = (bottomRightContent || []).filter(item => !item.hidden).length;
|
|
648
|
+
if (visibleCount <= 0) return 0;
|
|
649
|
+
if (visibleCount === 1) return 115;
|
|
650
|
+
return 132;
|
|
651
|
+
}, [bottomRightContent]);
|
|
626
652
|
|
|
627
653
|
/**
|
|
628
654
|
* 视频流加载状态封装
|
|
@@ -945,9 +971,11 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
|
|
|
945
971
|
height: screenType === 'vertical' ? '48px' : '72px'
|
|
946
972
|
}
|
|
947
973
|
}, /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(BottomLeftContent, {
|
|
948
|
-
ctx: instance
|
|
974
|
+
ctx: instance,
|
|
975
|
+
reservedRight: bottomRightWidth
|
|
949
976
|
}, renderBottomLeftContent), /*#__PURE__*/React.createElement(BottomRightContent, {
|
|
950
|
-
ctx: instance
|
|
977
|
+
ctx: instance,
|
|
978
|
+
width: bottomRightWidth
|
|
951
979
|
}, renderBottomRightContent))), (() => {
|
|
952
980
|
if (!absoluteContent || !(absoluteContent !== null && absoluteContent !== void 0 && absoluteContent.length)) return null;
|
|
953
981
|
return absoluteContent.map(item => {
|
package/lib/ui/ui.less
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
.ipc-player-bottom-content-hide {
|
|
61
|
-
transform: translate(0,
|
|
61
|
+
transform: translate(0, 100%);
|
|
62
62
|
transition: transform 0.3s ease-in-out;
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -214,6 +214,9 @@
|
|
|
214
214
|
display: flex;
|
|
215
215
|
justify-content: center;
|
|
216
216
|
align-items: center;
|
|
217
|
+
// 左下角支持横向滚动;不允许子项被压缩,否则在 width:100% 的滚动容器里
|
|
218
|
+
// 子项会被挤而不是触发横滑
|
|
219
|
+
flex-shrink: 0;
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
.bottom-left-item-container:first-of-type {
|
|
@@ -231,6 +234,7 @@
|
|
|
231
234
|
// 左下角全屏子元素容器
|
|
232
235
|
.bottom-left-item-full-container {
|
|
233
236
|
padding: 0 24px !important;
|
|
237
|
+
flex-shrink: 0;
|
|
234
238
|
}
|
|
235
239
|
|
|
236
240
|
.bottom-left-item-full-container:first-of-type {
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -15,3 +15,5 @@ export declare const promisify: <TParams extends Record<string, any>, TSuccessRe
|
|
|
15
15
|
complete?: (() => void) | undefined;
|
|
16
16
|
}) => void) => (params: Omit<TParams, "complete" | "success" | "fail">) => Promise<TSuccessResult>;
|
|
17
17
|
export * from './videoSplitHelper';
|
|
18
|
+
export * from './navigation';
|
|
19
|
+
export * from './ttt';
|
package/lib/utils/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const miniIdLabs: {
|
|
2
|
+
aiDrawMini: string;
|
|
3
|
+
securityCloudService: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function gotoAIDrawMiniProgram(devId: string, brandColor: string): void;
|
|
6
|
+
export declare function gotoSecurityCloudService(homeId: string, uuid: string): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { goToMiniProgramByShortLink } from '@ray-js/ray-ipc-utils';
|
|
2
|
+
import Color from 'color';
|
|
3
|
+
|
|
4
|
+
// 小程序ID集合
|
|
5
|
+
export const miniIdLabs = {
|
|
6
|
+
// ai智能画质
|
|
7
|
+
aiDrawMini: 'tyjo8cvir22cc0yech',
|
|
8
|
+
// security_cloud_service, 增值服务商城小程序ID
|
|
9
|
+
securityCloudService: 'tyeavwo0j4oocvdrf1'
|
|
10
|
+
};
|
|
11
|
+
export function gotoAIDrawMiniProgram(devId, brandColor) {
|
|
12
|
+
const color = new Color(brandColor);
|
|
13
|
+
const rgbColor = color.rgb().toString();
|
|
14
|
+
const url = `godzilla://${miniIdLabs.aiDrawMini}${'/pages/home/index'}?deviceId=${devId}&themeColor=${rgbColor}`;
|
|
15
|
+
goToMiniProgramByShortLink(url, 'right');
|
|
16
|
+
}
|
|
17
|
+
export async function gotoSecurityCloudService(homeId, uuid) {
|
|
18
|
+
const url = `godzilla://${miniIdLabs.securityCloudService}${'/pages/serviceList/index'}?homeId=${homeId}&deviceId=${uuid}&categoryCode=${'security_cloud_service'}`;
|
|
19
|
+
goToMiniProgramByShortLink(url, 'right');
|
|
20
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type SmartImageQualityResult = {
|
|
2
|
+
isPurchase: boolean;
|
|
3
|
+
buttonState: number;
|
|
4
|
+
trialRemainingSec: number;
|
|
5
|
+
canOpenSettings: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function getSmartImageQualityState(devId: string): Promise<SmartImageQualityResult>;
|
|
8
|
+
export type AIFrameFeatureScope = {
|
|
9
|
+
inPreview: boolean;
|
|
10
|
+
inMessage: boolean;
|
|
11
|
+
inPlayback: boolean;
|
|
12
|
+
inCloudData: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type AIFrameFeatureDetail = {
|
|
15
|
+
srModelStatus: number;
|
|
16
|
+
lightModelStatus: number;
|
|
17
|
+
filterStatus: number;
|
|
18
|
+
};
|
|
19
|
+
export type AIFrameFeatureConfig = {
|
|
20
|
+
scope: AIFrameFeatureScope;
|
|
21
|
+
feature: AIFrameFeatureDetail;
|
|
22
|
+
exportEnabled: boolean;
|
|
23
|
+
};
|
|
24
|
+
export type SetAIFrameFeatureParams = {
|
|
25
|
+
devId: string;
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
aiFrameFeature: AIFrameFeatureConfig;
|
|
28
|
+
};
|
|
29
|
+
export type GetAIFrameFeatureResult = {
|
|
30
|
+
enabled: boolean;
|
|
31
|
+
aiFrameFeature: AIFrameFeatureConfig;
|
|
32
|
+
requestId: string;
|
|
33
|
+
localPath: string;
|
|
34
|
+
thingFileUri: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function getAIFrameFeature(devId: string): Promise<GetAIFrameFeatureResult>;
|
|
37
|
+
export declare function setAIFrameFeature(devId: string, params: Omit<SetAIFrameFeatureParams, 'devId'>): Promise<any>;
|
|
38
|
+
export declare function getDeviceInfoRay(devId: string): Promise<unknown>;
|
|
39
|
+
export declare function getCurrentHomeInfoRay(): Promise<unknown>;
|
package/lib/utils/ttt.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
export function getSmartImageQualityState(devId) {
|
|
3
|
+
// const mockData: SmartImageQualityResult = {
|
|
4
|
+
// isPurchase: false,
|
|
5
|
+
// buttonState: 1,
|
|
6
|
+
// trialRemainingSec: 200,
|
|
7
|
+
// canOpenSettings: false,
|
|
8
|
+
// };
|
|
9
|
+
// if (typeof ty?.ipc?.getSmartImageQualityState !== 'function') {
|
|
10
|
+
// console.log('res===getSmartImageQualityState not exist, use mockData', mockData);
|
|
11
|
+
// return Promise.resolve(mockData);
|
|
12
|
+
// }
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
ty.ipc.getSmartImageQualityState({
|
|
15
|
+
params: {
|
|
16
|
+
devId
|
|
17
|
+
},
|
|
18
|
+
success: data => {
|
|
19
|
+
console.log('res===getSmartImageQualityState data', data);
|
|
20
|
+
resolve(data);
|
|
21
|
+
},
|
|
22
|
+
fail: e => {
|
|
23
|
+
console.warn('res===getSmartImageQualityState fail', e);
|
|
24
|
+
reject(e);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function getAIFrameFeature(devId) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
ty.ipc.getAIFrameFeature({
|
|
32
|
+
params: {
|
|
33
|
+
devId
|
|
34
|
+
},
|
|
35
|
+
success: data => {
|
|
36
|
+
console.log('res===getAIFrameFeature data', data);
|
|
37
|
+
resolve(data);
|
|
38
|
+
},
|
|
39
|
+
fail: e => {
|
|
40
|
+
console.warn('res===getAIFrameFeature fail', e);
|
|
41
|
+
reject(e);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function setAIFrameFeature(devId, params) {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
ty.ipc.setAIFrameFeature({
|
|
49
|
+
params: _objectSpread({
|
|
50
|
+
devId
|
|
51
|
+
}, params),
|
|
52
|
+
success: data => {
|
|
53
|
+
console.log('res===setAIFrameFeature data', data);
|
|
54
|
+
resolve(data);
|
|
55
|
+
},
|
|
56
|
+
fail: e => {
|
|
57
|
+
console.warn('res===setAIFrameFeature fail', e);
|
|
58
|
+
reject(e);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
export function getDeviceInfoRay(devId) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
ty.device.getDeviceInfo({
|
|
66
|
+
deviceId: devId,
|
|
67
|
+
success: res => {
|
|
68
|
+
resolve(res);
|
|
69
|
+
},
|
|
70
|
+
fail: error => {
|
|
71
|
+
reject(error);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export function getCurrentHomeInfoRay() {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
ty.home.getCurrentHomeInfo({
|
|
79
|
+
success: res => {
|
|
80
|
+
resolve(res);
|
|
81
|
+
},
|
|
82
|
+
fail: error => {
|
|
83
|
+
reject(error);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
package/lib/widgets/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export * from './voiceIntercom';
|
|
|
10
10
|
export * from './muted';
|
|
11
11
|
export * from './floodlight';
|
|
12
12
|
export * from './siren';
|
|
13
|
+
export * from './tryExperience';
|
|
14
|
+
export * from './trialBadge';
|
|
13
15
|
export * from './ptz';
|
|
14
16
|
export * from './resolution';
|
|
15
17
|
export * from './fullSmallIntercom';
|
package/lib/widgets/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export * from './voiceIntercom';
|
|
|
10
10
|
export * from './muted';
|
|
11
11
|
export * from './floodlight';
|
|
12
12
|
export * from './siren';
|
|
13
|
+
export * from './tryExperience';
|
|
14
|
+
export * from './trialBadge';
|
|
13
15
|
export * from './ptz';
|
|
14
16
|
export * from './resolution';
|
|
15
17
|
export * from './fullSmallIntercom';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './index.less';
|
|
3
|
+
type Props = {
|
|
4
|
+
className?: string;
|
|
5
|
+
/** 主题色(用于「开通」按钮背景)。默认与 player brandColor 一致 */
|
|
6
|
+
brandColor?: string;
|
|
7
|
+
/** 试看倒计时初始秒数,来源于 smartImageQualityState.trialRemainingSec */
|
|
8
|
+
trialRemainingSec?: number;
|
|
9
|
+
/** 刷新令牌,变化时重置倒计时状态 */
|
|
10
|
+
refreshToken?: number;
|
|
11
|
+
/** 点击「开通」按钮回调 */
|
|
12
|
+
onSubscribe?: () => void;
|
|
13
|
+
/** 倒计时归零时触发,本组件保证整个生命周期内只回调一次 */
|
|
14
|
+
onCountdownEnd?: () => void;
|
|
15
|
+
};
|
|
16
|
+
export declare const TrialBadge: ({ className, brandColor, trialRemainingSec, refreshToken, onSubscribe, onCountdownEnd, }: Props) => React.JSX.Element;
|
|
17
|
+
export { useTrialBadge } from './useTrialBadge';
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Image, Text, View } from '@ray-js/ray';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import Strings from '../../i18n';
|
|
5
|
+
import tryOpen from '../../res/try/try_open.png';
|
|
6
|
+
import './index.less';
|
|
7
|
+
/** 兜底主题色,与 player ctx 中 brandColor 默认值保持一致 */
|
|
8
|
+
const FALLBACK_BRAND_COLOR = '#FF592A';
|
|
9
|
+
|
|
10
|
+
/** 将秒数格式化为 mm:ss */
|
|
11
|
+
const formatCountdown = seconds => {
|
|
12
|
+
const safe = Math.max(0, Math.floor(seconds));
|
|
13
|
+
const m = Math.floor(safe / 60);
|
|
14
|
+
return `${String(m).padStart(2, '0')}:${String(safe % 60).padStart(2, '0')}`;
|
|
15
|
+
};
|
|
16
|
+
export const TrialBadge = _ref => {
|
|
17
|
+
let {
|
|
18
|
+
className,
|
|
19
|
+
brandColor = FALLBACK_BRAND_COLOR,
|
|
20
|
+
trialRemainingSec = 0,
|
|
21
|
+
refreshToken,
|
|
22
|
+
onSubscribe,
|
|
23
|
+
onCountdownEnd
|
|
24
|
+
} = _ref;
|
|
25
|
+
const [remainingSec, setRemainingSec] = useState(Math.max(0, Math.floor(trialRemainingSec)));
|
|
26
|
+
/** 防止 onCountdownEnd 被重复触发;同时持有最新回调,避免依赖变化导致 effect 重跑 */
|
|
27
|
+
const endedRef = useRef(false);
|
|
28
|
+
const onCountdownEndRef = useRef(onCountdownEnd);
|
|
29
|
+
onCountdownEndRef.current = onCountdownEnd;
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
endedRef.current = false;
|
|
32
|
+
setRemainingSec(Math.max(0, Math.floor(trialRemainingSec)));
|
|
33
|
+
}, [trialRemainingSec, refreshToken]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (remainingSec <= 0) {
|
|
36
|
+
if (!endedRef.current) {
|
|
37
|
+
var _onCountdownEndRef$cu;
|
|
38
|
+
endedRef.current = true;
|
|
39
|
+
(_onCountdownEndRef$cu = onCountdownEndRef.current) === null || _onCountdownEndRef$cu === void 0 || _onCountdownEndRef$cu.call(onCountdownEndRef);
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const timer = setInterval(() => {
|
|
44
|
+
setRemainingSec(prev => {
|
|
45
|
+
const next = prev - 1;
|
|
46
|
+
if (next <= 0) {
|
|
47
|
+
clearInterval(timer);
|
|
48
|
+
if (!endedRef.current) {
|
|
49
|
+
var _onCountdownEndRef$cu2;
|
|
50
|
+
endedRef.current = true;
|
|
51
|
+
(_onCountdownEndRef$cu2 = onCountdownEndRef.current) === null || _onCountdownEndRef$cu2 === void 0 || _onCountdownEndRef$cu2.call(onCountdownEndRef);
|
|
52
|
+
}
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
return next;
|
|
56
|
+
});
|
|
57
|
+
}, 1000);
|
|
58
|
+
return () => clearInterval(timer);
|
|
59
|
+
}, [trialRemainingSec, refreshToken]);
|
|
60
|
+
const countdownText = formatCountdown(remainingSec);
|
|
61
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
62
|
+
className: clsx('ipc-player-trial-badge', className)
|
|
63
|
+
}, /*#__PURE__*/React.createElement(Image, {
|
|
64
|
+
className: "ipc-player-trial-badge-icon",
|
|
65
|
+
src: tryOpen,
|
|
66
|
+
mode: "heightFix"
|
|
67
|
+
}), /*#__PURE__*/React.createElement(Text, {
|
|
68
|
+
className: "ipc-player-trial-badge-status"
|
|
69
|
+
}, Strings.getLang('ipc_player_trial_in_use')), /*#__PURE__*/React.createElement(Text, {
|
|
70
|
+
className: "ipc-player-trial-badge-divider"
|
|
71
|
+
}, "|"), /*#__PURE__*/React.createElement(Text, {
|
|
72
|
+
className: "ipc-player-trial-badge-preview"
|
|
73
|
+
}, `${countdownText} ${Strings.getLang('ipc_player_trial_preview_text')}`), /*#__PURE__*/React.createElement(View, {
|
|
74
|
+
className: "ipc-player-trial-badge-cta",
|
|
75
|
+
style: {
|
|
76
|
+
backgroundColor: brandColor
|
|
77
|
+
},
|
|
78
|
+
onClick: e => {
|
|
79
|
+
if (e && typeof e.stopPropagation === 'function') {
|
|
80
|
+
e.stopPropagation();
|
|
81
|
+
}
|
|
82
|
+
onSubscribe === null || onSubscribe === void 0 || onSubscribe();
|
|
83
|
+
}
|
|
84
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
85
|
+
className: "ipc-player-trial-badge-cta-text"
|
|
86
|
+
}, Strings.getLang('ipc_player_trial_subscribe'))));
|
|
87
|
+
};
|
|
88
|
+
export { useTrialBadge } from './useTrialBadge';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
.ipc-player-trial-badge {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
height: 28px;
|
|
5
|
+
padding: 0 4px 0 8px;
|
|
6
|
+
border-radius: 6px;
|
|
7
|
+
background: rgba(0, 0, 0, 0.65);
|
|
8
|
+
flex-shrink: 0;
|
|
9
|
+
vertical-align: middle;
|
|
10
|
+
white-space: nowrap;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ipc-player-trial-badge-icon {
|
|
14
|
+
display: block;
|
|
15
|
+
height: 20px;
|
|
16
|
+
width: auto;
|
|
17
|
+
margin-right: 6px;
|
|
18
|
+
flex-shrink: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ipc-player-trial-badge-status {
|
|
22
|
+
font-size: 12px;
|
|
23
|
+
color: #ffffff;
|
|
24
|
+
font-weight: 500;
|
|
25
|
+
line-height: 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ipc-player-trial-badge-divider {
|
|
29
|
+
margin: 0 6px;
|
|
30
|
+
font-size: 12px;
|
|
31
|
+
color: rgba(255, 255, 255, 0.45);
|
|
32
|
+
line-height: 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ipc-player-trial-badge-preview {
|
|
36
|
+
font-size: 12px;
|
|
37
|
+
color: rgba(255, 255, 255, 0.78);
|
|
38
|
+
line-height: 1;
|
|
39
|
+
margin-right: 8px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ipc-player-trial-badge-cta {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
height: 22px;
|
|
47
|
+
padding: 0 10px;
|
|
48
|
+
border-radius: 11px;
|
|
49
|
+
flex-shrink: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.ipc-player-trial-badge-cta-text {
|
|
53
|
+
font-size: 12px;
|
|
54
|
+
color: #ffffff;
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
line-height: 1;
|
|
57
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { EventInstance } from '../../interface';
|
|
3
|
+
export declare const useTrialBadge: (event: EventInstance, devId: string, trialRemainingSec: number) => {
|
|
4
|
+
showTrialBadge: boolean;
|
|
5
|
+
setShowTrialBadge: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
6
|
+
handleTrialSubscribe: () => Promise<void>;
|
|
7
|
+
handleCountdownEnd: () => Promise<void>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { getAIFrameFeature, getCurrentHomeInfoRay, getDeviceInfoRay, setAIFrameFeature } from '../../utils/ttt';
|
|
3
|
+
import { gotoSecurityCloudService } from '../../utils';
|
|
4
|
+
import Strings from '../../i18n';
|
|
5
|
+
export const useTrialBadge = (event, devId, trialRemainingSec) => {
|
|
6
|
+
const [showTrialBadge, setShowTrialBadge] = useState(false);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (trialRemainingSec > 0 && trialRemainingSec < 300) {
|
|
9
|
+
setShowTrialBadge(true);
|
|
10
|
+
}
|
|
11
|
+
}, [trialRemainingSec]);
|
|
12
|
+
const handleTrialSubscribe = useCallback(async () => {
|
|
13
|
+
try {
|
|
14
|
+
const homeInfo = await getCurrentHomeInfoRay();
|
|
15
|
+
const deviceInfo = await getDeviceInfoRay(devId);
|
|
16
|
+
console.log('res===', deviceInfo, homeInfo);
|
|
17
|
+
gotoSecurityCloudService(homeInfo.homeId, deviceInfo.uuid);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.log('res===handleTrialSubscribe error', error);
|
|
20
|
+
ty.showToast({
|
|
21
|
+
title: Strings.getLang('ipc_player_fetch_error'),
|
|
22
|
+
icon: 'none'
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}, [devId]);
|
|
26
|
+
const handleCountdownEnd = useCallback(async () => {
|
|
27
|
+
try {
|
|
28
|
+
const getAI = await getAIFrameFeature(devId);
|
|
29
|
+
console.log('res===handleCountdownEnd', getAI);
|
|
30
|
+
setAIFrameFeature(devId, {
|
|
31
|
+
enabled: false,
|
|
32
|
+
aiFrameFeature: getAI.aiFrameFeature
|
|
33
|
+
});
|
|
34
|
+
setShowTrialBadge(false);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
ty.showToast({
|
|
37
|
+
title: Strings.getLang('ipc_player_fetch_error'),
|
|
38
|
+
icon: 'none'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}, [devId, event]);
|
|
42
|
+
return {
|
|
43
|
+
showTrialBadge,
|
|
44
|
+
setShowTrialBadge,
|
|
45
|
+
handleTrialSubscribe,
|
|
46
|
+
handleCountdownEnd
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './tryExperience';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './tryExperience';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ComponentConfigProps } from '../../interface';
|
|
3
|
+
import './tryExperience.less';
|
|
4
|
+
type Props = ComponentConfigProps & {
|
|
5
|
+
className?: string;
|
|
6
|
+
hideTryExperienceMenu?: boolean;
|
|
7
|
+
buttonState?: number;
|
|
8
|
+
};
|
|
9
|
+
export declare const TryExperience: (props: Props) => React.JSX.Element | null;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { View, Image, getSystemInfoSync } from '@ray-js/ray';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useStore } from '../../ctx/store';
|
|
5
|
+
import { gotoAIDrawMiniProgram } from '../../utils';
|
|
6
|
+
import tryZh from '../../res/try/try_zh.png';
|
|
7
|
+
import tryEn from '../../res/try/try_en.png';
|
|
8
|
+
import tryOpen from '../../res/try/try_open.png';
|
|
9
|
+
import tryClose from '../../res/try/try_close.png';
|
|
10
|
+
import './tryExperience.less';
|
|
11
|
+
/** ty.ipc.test1 返回的体验状态 */
|
|
12
|
+
var TryExperienceStatus = /*#__PURE__*/function (TryExperienceStatus) {
|
|
13
|
+
TryExperienceStatus[TryExperienceStatus["Default"] = 0] = "Default";
|
|
14
|
+
TryExperienceStatus[TryExperienceStatus["Open"] = 1] = "Open";
|
|
15
|
+
TryExperienceStatus[TryExperienceStatus["Close"] = 2] = "Close";
|
|
16
|
+
return TryExperienceStatus;
|
|
17
|
+
}(TryExperienceStatus || {});
|
|
18
|
+
const ZH_LANG_REGEX = /^zh(_|-|$)/i;
|
|
19
|
+
const getDefaultLangIcon = () => {
|
|
20
|
+
try {
|
|
21
|
+
const {
|
|
22
|
+
language = ''
|
|
23
|
+
} = getSystemInfoSync() || {};
|
|
24
|
+
return ZH_LANG_REGEX.test(String(language)) ? tryZh : tryEn;
|
|
25
|
+
} catch {
|
|
26
|
+
return tryEn;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const pickIconByStatus = buttonState => {
|
|
30
|
+
switch (buttonState) {
|
|
31
|
+
case TryExperienceStatus.Open:
|
|
32
|
+
return tryOpen;
|
|
33
|
+
case TryExperienceStatus.Close:
|
|
34
|
+
return tryClose;
|
|
35
|
+
case TryExperienceStatus.Default:
|
|
36
|
+
default:
|
|
37
|
+
return getDefaultLangIcon();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
export const TryExperience = props => {
|
|
41
|
+
const {
|
|
42
|
+
className,
|
|
43
|
+
hideTryExperienceMenu,
|
|
44
|
+
buttonState = 0
|
|
45
|
+
} = props;
|
|
46
|
+
const {
|
|
47
|
+
brandColor
|
|
48
|
+
} = useStore({
|
|
49
|
+
brandColor: props.brandColor
|
|
50
|
+
});
|
|
51
|
+
const iconUrl = pickIconByStatus(buttonState);
|
|
52
|
+
if (hideTryExperienceMenu) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
56
|
+
className: clsx(className),
|
|
57
|
+
onClick: () => {
|
|
58
|
+
console.log('res===onTryExperience', props.devId, brandColor);
|
|
59
|
+
gotoAIDrawMiniProgram(props.devId, brandColor);
|
|
60
|
+
}
|
|
61
|
+
}, /*#__PURE__*/React.createElement(View, {
|
|
62
|
+
className: "try-experience-box"
|
|
63
|
+
}, /*#__PURE__*/React.createElement(Image, {
|
|
64
|
+
className: "try-experience-icon",
|
|
65
|
+
src: iconUrl,
|
|
66
|
+
mode: "heightFix"
|
|
67
|
+
})));
|
|
68
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.try-experience-box {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
justify-content: center;
|
|
4
|
+
align-items: center;
|
|
5
|
+
min-height: calc(var(--iconBoxSize) * var(--ipc-player-size-scale, 1));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.try-experience-icon {
|
|
9
|
+
display: block;
|
|
10
|
+
height: calc(var(--iconBoxSize) * var(--ipc-player-size-scale, 1));
|
|
11
|
+
width: auto;
|
|
12
|
+
flex-shrink: 0;
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ray-js/ipc-player-integration",
|
|
3
|
-
"version": "0.0.35-beta.
|
|
3
|
+
"version": "0.0.35-beta.3",
|
|
4
4
|
"description": "IPC 融合播放器",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@ray-js/direction-control": "^0.0.8",
|
|
39
39
|
"@ray-js/ipc-ptz-zoom": "^0.0.3",
|
|
40
|
-
"@ray-js/ray-ipc-player": "2.1.1-beta.
|
|
40
|
+
"@ray-js/ray-ipc-player": "2.1.1-beta.3",
|
|
41
41
|
"@ray-js/ray-ipc-utils": "^1.1.15",
|
|
42
42
|
"@ray-js/svg": "0.2.0",
|
|
43
43
|
"clsx": "^1.2.1",
|