@ray-js/ipc-player-integration 0.0.35-beta.2 → 0.0.35-beta.21

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.
@@ -8,18 +8,12 @@ export type InitPlayerWidgetsOptions = {
8
8
  hideScreenShotMenu?: boolean;
9
9
  hideRecordVideoMenu?: boolean;
10
10
  hideResolutionMenu?: boolean;
11
- hideTryExperienceMenu?: boolean;
12
11
  hideKbsMenu?: boolean;
13
12
  hideSignalMenu?: boolean;
14
13
  showToggleVerticalFull?: boolean;
15
14
  showRealTimeMagnification?: boolean;
16
15
  directionControlProps?: Partial<React.ComponentProps<typeof FullScreen>['directionControlProps']>;
17
- smartImageQualityState?: {
18
- isPurchase: boolean;
19
- buttonState: number;
20
- trialRemainingSec: number;
21
- canOpenSettings: boolean;
22
- };
16
+ hideSmartImageQualityState?: boolean;
23
17
  topLeftContent?: ComponentConfig[];
24
18
  topRightContent?: ComponentConfig[];
25
19
  bottomLeftContent?: ComponentConfig[];
@@ -21,12 +21,10 @@ export async function initPlayerWidgets(ctx, options) {
21
21
  const screenShotIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'Screenshot');
22
22
  const recordVideoIndex = newDefaultBottomLeftContent.findIndex(item => item.id === 'RecordVideo');
23
23
  if (tryExperienceIndex !== -1) {
24
- var _options$smartImageQu, _options$smartImageQu2;
24
+ var _options$hideSmartIma;
25
25
  // @ts-ignore
26
26
  newDefaultBottomLeftContent[tryExperienceIndex].initProps = {
27
- hideTryExperienceMenu: options.hideTryExperienceMenu,
28
- buttonState: (_options$smartImageQu = options.smartImageQualityState) === null || _options$smartImageQu === void 0 ? void 0 : _options$smartImageQu.buttonState,
29
- trialRemainingSec: (_options$smartImageQu2 = options.smartImageQualityState) === null || _options$smartImageQu2 === void 0 ? void 0 : _options$smartImageQu2.trialRemainingSec
27
+ hideTryExperienceMenu: (_options$hideSmartIma = options.hideSmartImageQualityState) !== null && _options$hideSmartIma !== void 0 ? _options$hideSmartIma : true
30
28
  };
31
29
  }
32
30
  if (resolutionIndex !== -1) {
@@ -54,7 +52,6 @@ export async function initPlayerWidgets(ctx, options) {
54
52
  newDefaultBottomLeftContent[magnificationIndex].hidden = false;
55
53
  }
56
54
  }
57
- console.log('res===1', newDefaultBottomLeftContent);
58
55
  ctx.addContent('bottomLeft', newDefaultBottomLeftContent);
59
56
  const newDefaultBottomRightContent = _cloneDeep(options.bottomRightContent || defaultBottomRightContent);
60
57
  const fullScreenIndex = newDefaultBottomRightContent.findIndex(item => item.id === 'FullScreen');
@@ -32,6 +32,8 @@ declare const Strings: kit.I18N<{
32
32
  ipc_player_trial_in_use: string;
33
33
  ipc_player_trial_preview_text: string;
34
34
  ipc_player_trial_subscribe: string;
35
+ ipc_player_fetch_error: string;
36
+ ipc_player_low_phone_not_support: string;
35
37
  };
36
38
  zh: {
37
39
  ipc_player_resolution_HD: string;
@@ -65,6 +67,8 @@ declare const Strings: kit.I18N<{
65
67
  ipc_player_trial_in_use: string;
66
68
  ipc_player_trial_preview_text: string;
67
69
  ipc_player_trial_subscribe: string;
70
+ ipc_player_fetch_error: string;
71
+ ipc_player_low_phone_not_support: string;
68
72
  };
69
73
  }, {
70
74
  ipc_player_resolution_HD: string;
@@ -98,6 +102,8 @@ declare const Strings: kit.I18N<{
98
102
  ipc_player_trial_in_use: string;
99
103
  ipc_player_trial_preview_text: string;
100
104
  ipc_player_trial_subscribe: string;
105
+ ipc_player_fetch_error: string;
106
+ ipc_player_low_phone_not_support: string;
101
107
  } | {
102
108
  ipc_player_resolution_HD: string;
103
109
  ipc_player_resolution_SD: string;
@@ -130,5 +136,7 @@ declare const Strings: kit.I18N<{
130
136
  ipc_player_trial_in_use: string;
131
137
  ipc_player_trial_preview_text: string;
132
138
  ipc_player_trial_subscribe: string;
139
+ ipc_player_fetch_error: string;
140
+ ipc_player_low_phone_not_support: string;
133
141
  }>;
134
142
  export default Strings;
@@ -31,6 +31,8 @@ declare const _default: {
31
31
  ipc_player_trial_in_use: string;
32
32
  ipc_player_trial_preview_text: string;
33
33
  ipc_player_trial_subscribe: string;
34
+ ipc_player_fetch_error: string;
35
+ ipc_player_low_phone_not_support: string;
34
36
  };
35
37
  zh: {
36
38
  ipc_player_resolution_HD: string;
@@ -64,6 +66,8 @@ declare const _default: {
64
66
  ipc_player_trial_in_use: string;
65
67
  ipc_player_trial_preview_text: string;
66
68
  ipc_player_trial_subscribe: string;
69
+ ipc_player_fetch_error: string;
70
+ ipc_player_low_phone_not_support: string;
67
71
  };
68
72
  };
69
73
  export default _default;
@@ -29,8 +29,10 @@ export default {
29
29
  ipc_player_ptz_moveable_tip_text: 'Hold the middle to drag the direction control area',
30
30
  ipc_player_flow_low_tip: 'The device’s remaining data is below 200MB. Please recharge as soon as possible.',
31
31
  ipc_player_trial_in_use: 'Trial',
32
- ipc_player_trial_preview_text: 'Preview',
33
- ipc_player_trial_subscribe: 'Open'
32
+ ipc_player_trial_preview_text: 'End',
33
+ ipc_player_trial_subscribe: 'Open',
34
+ ipc_player_fetch_error: 'Failed to fetch data',
35
+ ipc_player_low_phone_not_support: 'This feature is not supported on this device'
34
36
  },
35
37
  zh: {
36
38
  ipc_player_resolution_HD: '高清',
@@ -62,7 +64,9 @@ export default {
62
64
  ipc_player_ptz_moveable_tip_text: '长按中间可拖动方向控制区域',
63
65
  ipc_player_flow_low_tip: '设备当前剩余流量不足200M,请尽快充值',
64
66
  ipc_player_trial_in_use: '试用中',
65
- ipc_player_trial_preview_text: '试看剩余',
66
- ipc_player_trial_subscribe: '开通'
67
+ ipc_player_trial_preview_text: '后结束',
68
+ ipc_player_trial_subscribe: '开通',
69
+ ipc_player_fetch_error: '获取异常',
70
+ ipc_player_low_phone_not_support: '当前设备不支持此功能'
67
71
  }
68
72
  };
@@ -5,6 +5,7 @@ type Props = {
5
5
  children: React.ReactNode;
6
6
  /** 右下角组件占据的宽度(px),左下角通过该值约束自身可视宽度,避免与右下角重叠 */
7
7
  reservedRight?: number;
8
+ canOpenSettings?: boolean;
8
9
  };
9
- declare const BottomLeftContent: ({ ctx, children, reservedRight }: Props) => React.JSX.Element;
10
+ declare const BottomLeftContent: ({ ctx, children, reservedRight, canOpenSettings }: Props) => React.JSX.Element;
10
11
  export default BottomLeftContent;
@@ -1,4 +1,3 @@
1
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
1
  import "core-js/modules/esnext.iterator.constructor.js";
3
2
  import "core-js/modules/esnext.iterator.find.js";
4
3
  import React, { useMemo } from 'react';
@@ -8,34 +7,17 @@ import { useStore } from '../ctx/store';
8
7
  import { useComponentHideState } from './hooks';
9
8
  import { TrialBadge, useTrialBadge } from '../widgets/trialBadge';
10
9
  /** 右侧透明渐变宽度,用于提示横向可滑动 */
11
- const FADE_MASK = 'linear-gradient(to right, #000 calc(100% - 16px), transparent 100%)';
10
+ const FADE_MASK = 'linear-gradient(to right, #000 calc(100% - 48px), transparent 100%)';
12
11
 
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
- };
12
+ /** TrialBadge 组件高度 40px + 间距 */
13
+ const BADGE_HEIGHT_VERTICAL = 44;
14
+ const BADGE_HEIGHT_FULL = 48;
34
15
  const BottomLeftContent = _ref => {
35
16
  let {
36
17
  ctx,
37
18
  children,
38
- reservedRight = 0
19
+ reservedRight = 0,
20
+ canOpenSettings = true
39
21
  } = _ref;
40
22
  const {
41
23
  screenType,
@@ -47,38 +29,59 @@ const BottomLeftContent = _ref => {
47
29
  brandColor: ctx.brandColor,
48
30
  bottomLeftContent: ctx.bottomLeftContent
49
31
  });
32
+ const showSmartImageQuality = useMemo(() => {
33
+ var _tryExp$initProps;
34
+ const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
35
+ return !(tryExp !== null && tryExp !== void 0 && (_tryExp$initProps = tryExp.initProps) !== null && _tryExp$initProps !== void 0 && _tryExp$initProps.hideTryExperienceMenu);
36
+ }, [bottomLeftContent]);
50
37
  const trialRemainingSec = useMemo(() => {
51
- var _trialRemainingSec, _tryExp$initProps;
38
+ var _trialRemainingSec, _tryExp$initProps2;
39
+ const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
40
+ 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;
41
+ }, [bottomLeftContent]);
42
+ const buttonState = useMemo(() => {
43
+ var _tryExp$initProps3;
44
+ const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
45
+ return tryExp === null || tryExp === void 0 || (_tryExp$initProps3 = tryExp.initProps) === null || _tryExp$initProps3 === void 0 ? void 0 : _tryExp$initProps3.buttonState;
46
+ }, [bottomLeftContent]);
47
+ const isLowPhone = useMemo(() => {
48
+ var _isLowPhone, _tryExp$initProps4;
49
+ const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
50
+ return (_isLowPhone = tryExp === null || tryExp === void 0 || (_tryExp$initProps4 = tryExp.initProps) === null || _tryExp$initProps4 === void 0 ? void 0 : _tryExp$initProps4.isLowPhone) !== null && _isLowPhone !== void 0 ? _isLowPhone : false;
51
+ }, []);
52
+ const gRawData = useMemo(() => {
53
+ var _gRawData, _tryExp$initProps5;
52
54
  const tryExp = bottomLeftContent === null || bottomLeftContent === void 0 ? void 0 : bottomLeftContent.find(item => item.id === 'TryExperience');
53
- return (_trialRemainingSec = tryExp === null || tryExp === void 0 || (_tryExp$initProps = tryExp.initProps) === null || _tryExp$initProps === void 0 ? void 0 : _tryExp$initProps.trialRemainingSec) !== null && _trialRemainingSec !== void 0 ? _trialRemainingSec : 0;
55
+ return (_gRawData = tryExp === null || tryExp === void 0 || (_tryExp$initProps5 = tryExp.initProps) === null || _tryExp$initProps5 === void 0 ? void 0 : _tryExp$initProps5.gRawData) !== null && _gRawData !== void 0 ? _gRawData : false;
54
56
  }, [bottomLeftContent]);
55
57
  const [shouldHide] = useComponentHideState();
56
-
57
- // 横竖屏共用同一份徽章状态、回调;TrialBadge 实例不随 screenType 切换而重挂载,
58
- // 倒计时与可见性可在横竖屏切换之间保持一致
59
58
  const {
60
59
  showTrialBadge,
61
60
  handleTrialSubscribe,
62
61
  handleCountdownEnd
63
- } = useTrialBadge(ctx.event, trialRemainingSec);
62
+ } = useTrialBadge(ctx.event, ctx.devId, trialRemainingSec);
64
63
  const paddingLeftPx = screenType === 'vertical' ? 0 : 25;
65
- const trialBadgeWrapStyle = screenType === 'vertical' ? TRIAL_BADGE_WRAP_STYLE_VERTICAL : TRIAL_BADGE_WRAP_STYLE_FULL;
64
+ const showBadge = showSmartImageQuality && showTrialBadge && canOpenSettings && gRawData && !isLowPhone && buttonState === 1 && trialRemainingSec > 0;
65
+ const bottomBarHeight = screenType === 'vertical' ? 40 : 58;
66
+ const badgeAreaHeight = screenType === 'vertical' ? BADGE_HEIGHT_VERTICAL : BADGE_HEIGHT_FULL;
67
+ const containerHeight = showBadge ? `${bottomBarHeight + badgeAreaHeight}px` : `${bottomBarHeight}px`;
66
68
  return /*#__PURE__*/React.createElement(CoverView, {
67
- className: clsx('ipc-player-bottom-left-content-wrap')
68
- // 注意:不要在这里覆盖 position,CSS 类已经设置 position: absolute; left: 0; bottom: 0
69
- // 否则 children 会失去贴底定位,从而与 bottomRightContent 不对齐
70
- ,
69
+ className: clsx('ipc-player-bottom-left-content-wrap'),
71
70
  style: {
72
71
  right: `${reservedRight}px`,
73
- height: screenType === 'vertical' ? shouldHide ? '41px' : '40px' : shouldHide ? '57px' : '58px'
74
- }
75
- }, showTrialBadge && /*#__PURE__*/React.createElement(View, {
76
- className: clsx('bottom-left-item-container'),
77
- style: _objectSpread(_objectSpread({}, trialBadgeWrapStyle), {}, {
78
- transform: shouldHide ? 'translateY(40px)' : 'translateY(0)',
72
+ height: containerHeight,
73
+ display: 'flex',
74
+ flexDirection: 'column',
75
+ justifyContent: 'flex-end',
79
76
  opacity: shouldHide ? 0 : 1,
80
- transition: 'transform 0.3s ease-in-out, opacity 0.3s ease-in-out'
81
- })
77
+ pointerEvents: shouldHide ? 'none' : 'auto'
78
+ }
79
+ }, showBadge && /*#__PURE__*/React.createElement(View, {
80
+ style: {
81
+ paddingLeft: screenType === 'vertical' ? '0px' : '25px',
82
+ marginBottom: screenType === 'vertical' ? '4px' : '8px',
83
+ marginLeft: '12px'
84
+ }
82
85
  }, /*#__PURE__*/React.createElement(TrialBadge, {
83
86
  brandColor: brandColor,
84
87
  trialRemainingSec: trialRemainingSec,
@@ -88,6 +91,7 @@ const BottomLeftContent = _ref => {
88
91
  style: {
89
92
  paddingBottom: screenType === 'vertical' ? '14px' : '32px',
90
93
  paddingLeft: `${paddingLeftPx}px`,
94
+ paddingRight: '16px',
91
95
  width: '100%',
92
96
  overflowX: 'auto',
93
97
  overflowY: 'hidden',
@@ -96,10 +100,7 @@ const BottomLeftContent = _ref => {
96
100
  WebkitMaskImage: FADE_MASK,
97
101
  maskImage: FADE_MASK
98
102
  },
99
- className: clsx('ipc-player-bottom-left-content-container', {
100
- // 'ipc-player-bottom-left-content-hide': shouldHide,
101
- // 'ipc-player-bottom-left-content-show': !shouldHide,
102
- })
103
+ className: clsx('ipc-player-bottom-left-content-container')
103
104
  }, children));
104
105
  };
105
106
  export default BottomLeftContent;
@@ -21,13 +21,13 @@ 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
24
  /**
27
25
  * 试看倒计时结束事件:试看徽章倒计时归零时触发,
28
26
  * 业务侧/相关控件可监听此事件刷新自己的状态(例如 TryExperience 重新拉取状态)
29
27
  */
30
28
  export declare const trialCountdownEnd = "trialCountdownEnd";
29
+ export declare const hideTrialBadgeEvent = "hideTrialBadge";
30
+ export declare const refreshSmartImageQualityEvent = "refreshSmartImageQuality";
31
31
  /** 控件点击事件用的 widgetId,统一在此维护 */
32
32
  export declare const widgetLabs: {
33
33
  readonly SCREENSHOT: "Screenshot";
@@ -22,14 +22,13 @@ export const multiPtzId = 'multiPtzId';
22
22
  /** 控件点击统一事件:任意播放器内控件被点击时触发,可用于埋点或统一处理 */
23
23
  export const widgetClick = 'widgetClick';
24
24
 
25
- /** 「去体验」按钮业务事件,与清晰度 resolutionBtnControlClick 用法一致 */
26
- export const tryExperienceBtnClick = 'tryExperienceBtnClick';
27
-
28
25
  /**
29
26
  * 试看倒计时结束事件:试看徽章倒计时归零时触发,
30
27
  * 业务侧/相关控件可监听此事件刷新自己的状态(例如 TryExperience 重新拉取状态)
31
28
  */
32
29
  export const trialCountdownEnd = 'trialCountdownEnd';
30
+ export const hideTrialBadgeEvent = 'hideTrialBadge';
31
+ export const refreshSmartImageQualityEvent = 'refreshSmartImageQuality';
33
32
 
34
33
  /** 控件点击事件用的 widgetId,统一在此维护 */
35
34
  export const widgetLabs = {
package/lib/ui/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export * from './hooks';
3
3
  export * from './context';
4
4
  export type * from './event';
5
5
  export { widgetClick } from './widgetClick';
6
- export { widgetLabs, tryExperienceBtnClick, trialCountdownEnd } from './constant';
6
+ export { widgetLabs, trialCountdownEnd } from './constant';
package/lib/ui/index.js CHANGED
@@ -2,4 +2,4 @@ export * from './ui';
2
2
  export * from './hooks';
3
3
  export * from './context';
4
4
  export { widgetClick } from './widgetClick';
5
- export { widgetLabs, tryExperienceBtnClick, trialCountdownEnd } from './constant';
5
+ export { widgetLabs, trialCountdownEnd } from './constant';
package/lib/ui/ui.js CHANGED
@@ -12,7 +12,7 @@ import { PlayState, PlayerStreamStatus, MultiCameraScreenMode } from '../interfa
12
12
  import { useCtx } from '../ctx/ctx.composition';
13
13
  import { useStore, updateAtom } from '../ctx/store';
14
14
  import { UIEventContext } from './context';
15
- import { showAllComponent, hideAllComponent, playerTap, startTimeToHideAllComponent, pauseTimeToHideAllComponent, decodeClarityDic, changeIgnoreHideStopPreview, moveablePtzControlId, tileActionsId, tileTipId, landscapeTipId, multiPtzId, ptzMoveableTipId, showFlowLowTipId, zoomLevelChange, setScaleMultipleEvent } from './constant';
15
+ import { showAllComponent, hideAllComponent, playerTap, startTimeToHideAllComponent, pauseTimeToHideAllComponent, decodeClarityDic, changeIgnoreHideStopPreview, moveablePtzControlId, tileActionsId, tileTipId, landscapeTipId, multiPtzId, ptzMoveableTipId, showFlowLowTipId, zoomLevelChange, setScaleMultipleEvent, trialCountdownEnd, refreshSmartImageQualityEvent } from './constant';
16
16
  import BottomLeftContent from './bottomLeftContent';
17
17
  import BottomRightContent from './bottomRightContent';
18
18
  import TopLeftContent from './topLeftContent';
@@ -22,7 +22,7 @@ import { useMemoizedFn } from '../hooks';
22
22
  import { Storage } from '../utils/storage';
23
23
  import './ui.less';
24
24
  import { updatePlayerWidgetProps } from '../features';
25
- import { isSmallScreen } from '../utils';
25
+ import { getNgRawData, getSmartImageQualityState, isLowPhone } from '../utils/ttt';
26
26
  function getCtxInstance(instance, devId) {
27
27
  if (instance) return instance;
28
28
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -103,18 +103,37 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
103
103
  useImperativeHandle(eventRefProp, () => eventRef.current, [eventRef.current]);
104
104
  const timer = useRef();
105
105
  const reGetOrientationTimer = useRef(null);
106
- const [scaleMultiple, setScaleMultiple] = useState(playerFit === 'contain' ? 1 : -2);
107
- const [currentZoomLevel, setCurrentZoomLevel] = useState(playerFit === 'contain' ? 1 : -2);
106
+ // 统一调整为1倍缩放,保证画面展示完全
107
+ const [scaleMultiple, setScaleMultiple] = useState(1);
108
+ // 统一调整为1倍缩放,保证画面展示完全
109
+ const [currentZoomLevel, setCurrentZoomLevel] = useState(1);
108
110
  const [createCtx, setCreateCtx] = useState(false);
109
111
  // 是否需要忽略进入后台停止预览
110
112
  const [ignoreStopOnHide, setIgnoreStopOnHide] = useState(ignoreHideStopPreview);
111
113
  const [verticalCoverZoom, setVerticalCoverZoom] = useState(-2);
112
- // const [verticalCoverZoom, setVerticalCoverZoom] = useState(-2);
113
- // const [verticalZoomLevel, setVerticalZoomLevel] = useState(playerFit === 'contain' ? 1 : -2);
114
+ const isLowPhoneRef = useRef(false);
115
+ useEffect(() => {
116
+ isLowPhone().then(res => {
117
+ isLowPhoneRef.current = !!res;
118
+ });
119
+ }, []);
114
120
 
115
121
  // 展示顶部内容
116
122
  const [showTopContent, setShowTopContent] = useState(true);
117
123
 
124
+ // pad / 折叠屏小窗口展示面板的情况;getSystemInfoSync 在 onLoad 之后才有准确值,
125
+ // 这里给安全默认 false,由 onLoad / onResize 实际计算并更新
126
+ const [isSmallScreen, setIsSmallScreen] = useState(false);
127
+ const computeIsSmallScreen = useMemoizedFn(() => {
128
+ const {
129
+ windowWidth,
130
+ screenWidth,
131
+ windowHeight
132
+ } = getSystemInfoSync();
133
+ // 取小屏值判断是最准确的 pad / 折叠屏小窗口情况
134
+ return !(screenWidth === windowWidth || screenWidth === windowHeight);
135
+ });
136
+
118
137
  // 外部传入的ignoreHideStopPreview变化时,同步更新
119
138
  useEffect(() => {
120
139
  setIgnoreStopOnHide(ignoreHideStopPreview);
@@ -406,8 +425,8 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
406
425
  eventRef.current.emit(showAllComponent);
407
426
  eventRef.current.emit('disablePlayerTap', true);
408
427
  eventRef.current.emit(pauseTimeToHideAllComponent);
409
- // 按宽填充,保证播放流宽度为屏幕宽度,高度自适应
410
- setScaleMultiple(-1);
428
+ // 按宽填充,保证播放流宽度为屏幕宽度,高度自适应设为1倍
429
+ setScaleMultiple(1);
411
430
  } else {
412
431
  // 短屏或横屏时,恢复自动隐藏
413
432
  eventRef.current.emit('disablePlayerTap', false);
@@ -416,14 +435,47 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
416
435
  }, [isVerticalFullLayout, screenType, playerFit]);
417
436
  useEffect(() => {
418
437
  if (createCtx) {
419
- setScaleMultiple(playerFit === 'contain' ? 1 : -2);
420
- setCurrentZoomLevel(playerFit === 'contain' ? 1 : -2);
438
+ // 统一调整为1倍缩放,保证画面展示完全
439
+ setScaleMultiple(1);
440
+ setCurrentZoomLevel(1);
421
441
  }
422
442
  }, [playerFit, createCtx]);
423
443
  useEffect(() => {
424
444
  setBrandColor(brandColor);
425
445
  setVerticalMic(verticalMic);
426
446
  }, [brandColor, verticalMic]);
447
+ const refreshSmartImageQuality = useMemoizedFn(async () => {
448
+ const res = await getSmartImageQualityState(devId);
449
+ if (res === undefined) return;
450
+ // 调试时使用
451
+ // res = {
452
+ // isPurchase: false,
453
+ // buttonState: 0,
454
+ // trialRemainingSec: 20,
455
+ // canOpenSettings: true,
456
+ // };
457
+ const getNgRes = await getNgRawData();
458
+ console.log('res===getNgRes111', res, getNgRes);
459
+ updatePlayerWidgetProps(instance, 'bottomLeft', 'TryExperience', {
460
+ isPurchase: res.isPurchase,
461
+ buttonState: res.buttonState,
462
+ trialRemainingSec: res.trialRemainingSec,
463
+ canOpenSettings: res.canOpenSettings,
464
+ gRawData: !!getNgRes,
465
+ isLowPhone: isLowPhoneRef.current
466
+ });
467
+ });
468
+ const siqInitRef = useRef(false);
469
+ useEffect(() => {
470
+ if (playState === PlayState.PLAYING) {
471
+ if (!siqInitRef.current) {
472
+ siqInitRef.current = true;
473
+ refreshSmartImageQuality();
474
+ }
475
+ } else {
476
+ siqInitRef.current = false;
477
+ }
478
+ }, [instance, playState]);
427
479
  const refreshBottomLeft = () => {
428
480
  event.current.emit(startTimeToHideAllComponent);
429
481
  event.current.emit(showAllComponent);
@@ -453,6 +505,13 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
453
505
  * 监听播放器实例创建完成
454
506
  */
455
507
 
508
+ /**
509
+ * 页面 onLoad 后才能拿到准确的 systemInfo,这里第一次确定小屏状态
510
+ */
511
+ usePageEvent('onLoad', () => {
512
+ setIsSmallScreen(computeIsSmallScreen());
513
+ });
514
+
456
515
  /**
457
516
  * 监听屏幕布局变化
458
517
  */
@@ -466,8 +525,13 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
466
525
  const {
467
526
  type
468
527
  } = sizeData;
528
+
529
+ // 折叠屏展开/收起、pad 多窗口拖拽等场景,需要重新计算并同步
530
+ const small = computeIsSmallScreen();
531
+ setIsSmallScreen(small);
532
+
469
533
  // 针对pad 和折叠屏展开的情况暂不支持横屏,且在ios pad模式下 会触发onResize事件, 待解决
470
- if (isSmallScreen) {
534
+ if (small) {
471
535
  setScreenType('vertical');
472
536
  } else {
473
537
  setScreenType(type === 'landscape' ? 'full' : 'vertical');
@@ -482,19 +546,8 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
482
546
  }
483
547
  triggerEvent(showAllComponent);
484
548
  }
485
- // 若为全屏模式并且要求按宽填充,即横屏时充满,主动设置模式为-1即可
486
- if (type === 'landscape' && landscapeMode === 'fill') {
487
- console.log(scaleMultiple, '===========fill');
488
- setScaleMultiple(-1);
489
- } else if (type === 'landscape' && landscapeMode === 'standard') {
490
- console.log(scaleMultiple, '===========landscape');
491
- setScaleMultiple(-2);
492
- } else {
493
- // 竖屏时 将屏幕播放比例设为按宽按高
494
-
495
- console.log(scaleMultiple, '===========landscape');
496
- setScaleMultiple(playerFit === 'contain' ? scaleMultiple === 1 ? -1 : 1 : -2);
497
- }
549
+ // 横屏(fill/standard)与竖屏均统一调整为 1 倍缩放,保证画面完整展示
550
+ setScaleMultiple(1);
498
551
  } catch (err) {
499
552
  console.log(err, 'err');
500
553
  }
@@ -658,10 +711,12 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
658
711
  }
659
712
  }
660
713
  if (playState === PlayState.PLAYING) {
661
- // 仅在第一次播放成功时,针对竖屏并且为cover模式时,设置为-2
714
+ // 仅在第一次播放成功时,针对竖屏并且为cover模式时,设置为-2 修改为只针对第一次播放成功时
662
715
  console.log('Playing状态');
663
- if (screenType === 'vertical' && playerFit === 'cover' && !hasPlayedRef.current) {
664
- setScaleMultiple(-2);
716
+ // if (screenType === 'vertical' && playerFit === 'cover' && !hasPlayedRef.current) {
717
+ if (!hasPlayedRef.current) {
718
+ // 统一调整为1倍缩放,保证画面展示完全
719
+ setScaleMultiple(1);
665
720
  hasPlayedRef.current = true;
666
721
  }
667
722
  }
@@ -738,6 +793,11 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
738
793
  const onSetScaleMultiple = value => {
739
794
  setScaleMultiple(value);
740
795
  };
796
+ const onTrialCountdownEnd = useMemoizedFn(() => {
797
+ updatePlayerWidgetProps(instance, 'bottomLeft', 'TryExperience', {
798
+ buttonState: 2
799
+ });
800
+ });
741
801
  useEffect(() => {
742
802
  eventRef.current.on(startTimeToHideAllComponent, listenStart);
743
803
  eventRef.current.on(pauseTimeToHideAllComponent, listenPause);
@@ -747,6 +807,8 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
747
807
  eventRef.current.on('refreshBottomLeft', refreshBottomLeft);
748
808
  eventRef.current.on(changeIgnoreHideStopPreview, onChangeIgnoreHideStopPreview);
749
809
  eventRef.current.on(setScaleMultipleEvent, onSetScaleMultiple);
810
+ eventRef.current.on(trialCountdownEnd, onTrialCountdownEnd);
811
+ eventRef.current.on(refreshSmartImageQualityEvent, refreshSmartImageQuality);
750
812
  return () => {
751
813
  eventRef.current.off(startTimeToHideAllComponent, listenStart);
752
814
  eventRef.current.off(pauseTimeToHideAllComponent, listenPause);
@@ -756,6 +818,8 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
756
818
  eventRef.current.off('refreshBottomLeft', refreshBottomLeft);
757
819
  eventRef.current.off(changeIgnoreHideStopPreview, onChangeIgnoreHideStopPreview);
758
820
  eventRef.current.off(setScaleMultipleEvent, onSetScaleMultiple);
821
+ eventRef.current.off(trialCountdownEnd, onTrialCountdownEnd);
822
+ eventRef.current.off(refreshSmartImageQualityEvent, refreshSmartImageQuality);
759
823
  if (multiTapTimerRef.current) {
760
824
  clearTimeout(multiTapTimerRef.current);
761
825
  multiTapTimerRef.current = null;
@@ -770,14 +834,6 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
770
834
  /**
771
835
  * 监听当前的zoom比例状态
772
836
  */
773
- // useEffect(() => {
774
- // if (screenType === 'vertical') {
775
- // console.log(currentZoomLevel, '竖屏时的缩放比例');
776
- // setVerticalZoomLevel(currentZoomLevel);
777
- // // setScaleMultiple(currentZoomLevel);
778
- // }
779
- // }, [screenType, currentZoomLevel]);
780
-
781
837
  const onZoomChange = useMemoizedFn(data => {
782
838
  const {
783
839
  zoomLevel,
@@ -788,30 +844,19 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
788
844
  if (zoomLevel === 0) {
789
845
  return false;
790
846
  }
791
- /**
792
- * 针对竖屏为cover模式时,横屏为standard模式时,主动设置缩放比例,避免因值不能正常变化
793
- */
794
- if (scaleMode === -2 && playerFit === 'cover' && screenType === 'vertical' && landscapeMode === 'standard') {
795
- console.log('dsadsadsad----', zoomLevel);
796
- setScaleMultiple(zoomLevel);
797
- }
798
847
  /**
799
848
  * 针对竖屏为contain模式时,横屏为fill模式时,主动设置缩放比例,避免因值不能正常变化
800
849
  */
801
- if (scaleMode === -1 && playerFit === 'contain' && screenType === 'vertical' && landscapeMode === 'fill') {
802
- setVerticalCoverZoom(zoomLevel);
803
- }
850
+ // if (
851
+ // scaleMode === -1 &&
852
+ // playerFit === 'contain' &&
853
+ // screenType === 'vertical' &&
854
+ // landscapeMode === 'fill'
855
+ // ) {
856
+ // setVerticalCoverZoom(zoomLevel);
857
+ // }
804
858
 
805
- /**
806
- * 横屏情况下 针对竖屏为contain模式时,横屏为fill模式时,主动设置缩放比例,避免因值不能正常变化
807
- */
808
- if (scaleMode === -2 && playerFit === 'cover' && screenType !== 'vertical' && landscapeMode === 'standard') {
809
- setScaleMultiple(zoomLevel);
810
- }
811
- if (scaleMode === -1 && playerFit === 'contain' && screenType !== 'vertical' && landscapeMode === 'fill') {
812
- setVerticalCoverZoom(zoomLevel);
813
- setScaleMultiple(zoomLevel);
814
- }
859
+ // 直接记录当前缩放比例
815
860
  setCurrentZoomLevel(zoomLevel);
816
861
  instance.event.emit(zoomLevelChange, zoomLevel);
817
862
  return false;
@@ -878,7 +923,7 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
878
923
  console.log('playerTap 事件已禁止');
879
924
  return;
880
925
  }
881
- console.log('res===on onVideoTap', data);
926
+ console.log('res===on onVideoTap1', data);
882
927
  if (instance.multiCameraCtx.isSupport) {
883
928
  var _instance$multiCamera, _instance$multiCamera2;
884
929
  const preTapIndex = (_instance$multiCamera = (_instance$multiCamera2 = instance.multiCameraCtx.selectedLenInfoRef.current) === null || _instance$multiCamera2 === void 0 ? void 0 : _instance$multiCamera2.index) !== null && _instance$multiCamera !== void 0 ? _instance$multiCamera : prevSelectedIndexRef.current;
@@ -956,7 +1001,7 @@ export const IPCPlayerIntegration = /*#__PURE__*/React.memo(props => {
956
1001
  style: {
957
1002
  height: screenType === 'vertical' ? '48px' : '72px'
958
1003
  }
959
- }, /*#__PURE__*/React.createElement(React.Fragment, null, playerReady && /*#__PURE__*/React.createElement(BottomLeftContent, {
1004
+ }, /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(BottomLeftContent, {
960
1005
  ctx: instance,
961
1006
  reservedRight: bottomRightWidth
962
1007
  }, renderBottomLeftContent), /*#__PURE__*/React.createElement(BottomRightContent, {
package/lib/ui/ui.less CHANGED
@@ -157,7 +157,7 @@
157
157
  // 左下角子元素内容区域样式
158
158
  .ipc-player-bottom-left-content-container {
159
159
  display: flex;
160
- flex-direction: inherit;
160
+ flex-direction: row;
161
161
  }
162
162
 
163
163
  // 右下角子元素内容区域样式
@@ -1,5 +1,4 @@
1
1
  /// <reference types="jest" />
2
- export declare const isSmallScreen: boolean;
3
2
  /**
4
3
  * 麦克风对讲按钮径向渐变
5
4
  */
@@ -15,3 +14,5 @@ export declare const promisify: <TParams extends Record<string, any>, TSuccessRe
15
14
  complete?: (() => void) | undefined;
16
15
  }) => void) => (params: Omit<TParams, "complete" | "success" | "fail">) => Promise<TSuccessResult>;
17
16
  export * from './videoSplitHelper';
17
+ export * from './navigation';
18
+ export * from './ttt';
@@ -1,14 +1,4 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
- import { getSystemInfoSync } from '@ray-js/ray';
3
- const {
4
- windowWidth,
5
- screenWidth,
6
- windowHeight
7
- } = getSystemInfoSync();
8
-
9
- // pad和折叠屏小窗口展示面板的情况
10
- export const isSmallScreen = !(screenWidth === windowWidth || screenWidth === windowHeight);
11
-
12
2
  /**
13
3
  * 麦克风对讲按钮径向渐变
14
4
  */
@@ -47,4 +37,6 @@ export const promisify = apiFunction => {
47
37
  });
48
38
  };
49
39
  };
50
- export * from './videoSplitHelper';
40
+ export * from './videoSplitHelper';
41
+ export * from './navigation';
42
+ export * from './ttt';
@@ -0,0 +1,7 @@
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>;
7
+ export declare function gotoSecurityCloudService2(devId: string): Promise<import("@ray-js/ray-ipc-utils/lib/interface").IRes<unknown>>;
@@ -0,0 +1,23 @@
1
+ import { getServiceUrl, 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}?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
+ }
21
+ export async function gotoSecurityCloudService2(devId) {
22
+ return getServiceUrl(devId, 'security_cloud_service', {}, true);
23
+ }
@@ -0,0 +1,43 @@
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
+ scene: string;
29
+ };
30
+ export type GetAIFrameFeatureResult = {
31
+ enabled: boolean;
32
+ aiFrameFeature: AIFrameFeatureConfig;
33
+ requestId: string;
34
+ localPath: string;
35
+ thingFileUri: string;
36
+ };
37
+ export declare function getAIFrameFeature(devId: string): Promise<GetAIFrameFeatureResult>;
38
+ export declare function setAIFrameFeature(params: SetAIFrameFeatureParams): Promise<any>;
39
+ export declare function getDeviceInfo(devId: string): Promise<unknown>;
40
+ export declare function getCurrentHomeInfo(): Promise<unknown>;
41
+ export declare function setTrailFinish(devId: string): Promise<unknown>;
42
+ export declare function isLowPhone(): Promise<unknown>;
43
+ export declare function getNgRawData(): Promise<unknown>;
@@ -0,0 +1,139 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ export function getSmartImageQualityState(devId) {
3
+ return new Promise(resolve => {
4
+ try {
5
+ ty.ipc.getSmartImageQualityState({
6
+ devId,
7
+ scene: 'inPreview',
8
+ success: data => {
9
+ resolve(data);
10
+ },
11
+ fail: () => {
12
+ resolve(undefined);
13
+ }
14
+ });
15
+ } catch (e) {
16
+ resolve(undefined);
17
+ }
18
+ });
19
+ }
20
+ export function getAIFrameFeature(devId) {
21
+ return new Promise(resolve => {
22
+ try {
23
+ ty.ipc.getAIFrameFeature({
24
+ devId,
25
+ success: data => {
26
+ console.log('res===getAIFrameFeature data', data);
27
+ resolve(data);
28
+ },
29
+ fail: e => {
30
+ console.warn('res===getAIFrameFeature fail', e);
31
+ resolve(undefined);
32
+ }
33
+ });
34
+ } catch (e) {
35
+ resolve(undefined);
36
+ }
37
+ });
38
+ }
39
+ export function setAIFrameFeature(params) {
40
+ return new Promise(resolve => {
41
+ try {
42
+ ty.ipc.setAIFrameFeature(_objectSpread(_objectSpread({}, params), {}, {
43
+ success: data => {
44
+ console.log('res===setAIFrameFeature data', data);
45
+ resolve(data);
46
+ },
47
+ fail: e => {
48
+ console.warn('res===setAIFrameFeature fail', e);
49
+ resolve(undefined);
50
+ }
51
+ }));
52
+ } catch (e) {
53
+ resolve(undefined);
54
+ }
55
+ });
56
+ }
57
+ export function getDeviceInfo(devId) {
58
+ return new Promise(resolve => {
59
+ try {
60
+ ty.device.getDeviceInfo({
61
+ deviceId: devId,
62
+ success: res => {
63
+ resolve(res);
64
+ },
65
+ fail: () => {
66
+ resolve(undefined);
67
+ }
68
+ });
69
+ } catch (e) {
70
+ resolve(undefined);
71
+ }
72
+ });
73
+ }
74
+ export function getCurrentHomeInfo() {
75
+ return new Promise(resolve => {
76
+ try {
77
+ ty.home.getCurrentHomeInfo({
78
+ success: res => {
79
+ resolve(res);
80
+ },
81
+ fail: () => {
82
+ resolve(undefined);
83
+ }
84
+ });
85
+ } catch (e) {
86
+ resolve(undefined);
87
+ }
88
+ });
89
+ }
90
+ export function setTrailFinish(devId) {
91
+ return new Promise(resolve => {
92
+ try {
93
+ ty.ipc.setTrailFinish({
94
+ devId,
95
+ success: res => {
96
+ resolve(res);
97
+ },
98
+ fail: () => {
99
+ resolve(undefined);
100
+ }
101
+ });
102
+ } catch (e) {
103
+ resolve(undefined);
104
+ }
105
+ });
106
+ }
107
+ export function isLowPhone() {
108
+ return new Promise(resolve => {
109
+ try {
110
+ ty.device.isLowPhone({
111
+ success: res => {
112
+ resolve(res);
113
+ },
114
+ fail: () => {
115
+ resolve(false);
116
+ }
117
+ });
118
+ } catch (e) {
119
+ resolve(false);
120
+ }
121
+ });
122
+ }
123
+ export function getNgRawData() {
124
+ return new Promise(resolve => {
125
+ try {
126
+ ty.getNgRawData({
127
+ rawKey: 'is_smart_image_quality',
128
+ success: res => {
129
+ resolve(res);
130
+ },
131
+ fail: () => {
132
+ resolve(false);
133
+ }
134
+ });
135
+ } catch (e) {
136
+ resolve(false);
137
+ }
138
+ });
139
+ }
@@ -22,15 +22,21 @@ export const TrialBadge = _ref => {
22
22
  onCountdownEnd
23
23
  } = _ref;
24
24
  const [remainingSec, setRemainingSec] = useState(Math.max(0, Math.floor(trialRemainingSec)));
25
- /** 防止 onCountdownEnd 被重复触发;同时持有最新回调,避免依赖变化导致 effect 重跑 */
26
25
  const endedRef = useRef(false);
27
26
  const onCountdownEndRef = useRef(onCountdownEnd);
28
27
  onCountdownEndRef.current = onCountdownEnd;
28
+ const startTimeRef = useRef(Date.now());
29
+ const initialSecRef = useRef(Math.max(0, Math.floor(trialRemainingSec)));
29
30
  useEffect(() => {
30
- setRemainingSec(Math.max(0, Math.floor(trialRemainingSec)));
31
+ console.log('res===trialRemainingSec', trialRemainingSec);
32
+ const sec = Math.max(0, Math.floor(trialRemainingSec));
33
+ endedRef.current = false;
34
+ initialSecRef.current = sec;
35
+ startTimeRef.current = Date.now();
36
+ setRemainingSec(sec);
31
37
  }, [trialRemainingSec]);
32
38
  useEffect(() => {
33
- if (remainingSec <= 0) {
39
+ if (trialRemainingSec <= 0) {
34
40
  if (!endedRef.current) {
35
41
  var _onCountdownEndRef$cu;
36
42
  endedRef.current = true;
@@ -39,19 +45,17 @@ export const TrialBadge = _ref => {
39
45
  return undefined;
40
46
  }
41
47
  const timer = setInterval(() => {
42
- setRemainingSec(prev => {
43
- const next = prev - 1;
44
- if (next <= 0) {
45
- clearInterval(timer);
46
- if (!endedRef.current) {
47
- var _onCountdownEndRef$cu2;
48
- endedRef.current = true;
49
- (_onCountdownEndRef$cu2 = onCountdownEndRef.current) === null || _onCountdownEndRef$cu2 === void 0 || _onCountdownEndRef$cu2.call(onCountdownEndRef);
50
- }
51
- return 0;
48
+ const elapsed = Math.floor((Date.now() - startTimeRef.current) / 1000);
49
+ const next = Math.max(0, initialSecRef.current - elapsed);
50
+ setRemainingSec(next);
51
+ if (next <= 0) {
52
+ clearInterval(timer);
53
+ if (!endedRef.current) {
54
+ var _onCountdownEndRef$cu2;
55
+ endedRef.current = true;
56
+ (_onCountdownEndRef$cu2 = onCountdownEndRef.current) === null || _onCountdownEndRef$cu2 === void 0 || _onCountdownEndRef$cu2.call(onCountdownEndRef);
52
57
  }
53
- return next;
54
- });
58
+ }
55
59
  }, 1000);
56
60
  return () => clearInterval(timer);
57
61
  }, [trialRemainingSec]);
@@ -68,15 +72,12 @@ export const TrialBadge = _ref => {
68
72
  className: "ipc-player-trial-badge-divider"
69
73
  }, "|"), /*#__PURE__*/React.createElement(Text, {
70
74
  className: "ipc-player-trial-badge-preview"
71
- }, `${Strings.getLang('ipc_player_trial_preview_text')} ${countdownText}`), /*#__PURE__*/React.createElement(View, {
75
+ }, `${countdownText} ${Strings.getLang('ipc_player_trial_preview_text')}`), /*#__PURE__*/React.createElement(View, {
72
76
  className: "ipc-player-trial-badge-cta",
73
77
  style: {
74
78
  backgroundColor: brandColor
75
79
  },
76
- onClick: e => {
77
- if (e && typeof e.stopPropagation === 'function') {
78
- e.stopPropagation();
79
- }
80
+ onClick: () => {
80
81
  onSubscribe === null || onSubscribe === void 0 || onSubscribe();
81
82
  }
82
83
  }, /*#__PURE__*/React.createElement(Text, {
@@ -1,9 +1,9 @@
1
1
  .ipc-player-trial-badge {
2
2
  display: inline-flex;
3
3
  align-items: center;
4
- height: 28px;
5
- padding: 0 4px 0 8px;
6
- border-radius: 6px;
4
+ height: 40px;
5
+ padding: 0 6px 0 8px;
6
+ border-radius: 8px;
7
7
  background: rgba(0, 0, 0, 0.65);
8
8
  flex-shrink: 0;
9
9
  vertical-align: middle;
@@ -43,9 +43,10 @@
43
43
  display: inline-flex;
44
44
  align-items: center;
45
45
  justify-content: center;
46
- height: 22px;
47
- padding: 0 10px;
48
- border-radius: 11px;
46
+ min-width: 44px;
47
+ min-height: 28px;
48
+ padding: 0 12px;
49
+ border-radius: 14px;
49
50
  flex-shrink: 0;
50
51
  }
51
52
 
@@ -1,16 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  import type { EventInstance } from '../../interface';
3
- /**
4
- * 试用徽章共享 Hook:vertical / full 两种 screenType 下共用同一份状态、回调和方法。
5
- *
6
- * - `showTrialBadge`:是否展示徽章;仅当 0 < trialRemainingSec < 300 时展示,倒计时归零会自动置 false。
7
- * - `handleTrialSubscribe`:「开通」按钮点击回调。
8
- * - `handleCountdownEnd`:倒计时归零回调,内部会广播 `trialCountdownEnd`
9
- * 事件给其它控件(例如 TryExperience)刷新自身状态。
10
- */
11
- export declare const useTrialBadge: (event: EventInstance, trialRemainingSec: number) => {
3
+ export declare const useTrialBadge: (event: EventInstance, devId: string, trialRemainingSec: number) => {
12
4
  showTrialBadge: boolean;
13
5
  setShowTrialBadge: import("react").Dispatch<import("react").SetStateAction<boolean>>;
14
- handleTrialSubscribe: () => void;
15
- handleCountdownEnd: () => void;
6
+ handleTrialSubscribe: () => Promise<void>;
7
+ handleCountdownEnd: () => Promise<void>;
16
8
  };
@@ -1,37 +1,41 @@
1
- import { useCallback, useEffect, useState } from 'react';
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { setTrailFinish } from '../../utils/ttt';
3
+ import { gotoSecurityCloudService2 } from '../../utils';
2
4
  import { trialCountdownEnd } from '../../ui/constant';
3
-
4
- /**
5
- * 试看倒计时归零后的业务 hook 点(mock)。
6
- * 后续接入业务校验 / 上报时替换该实现。横竖屏共用同一份逻辑。
7
- */
8
- const trialEndedTest = () => {
9
- console.log('res===[TrialBadge] countdown end -> test()');
10
- };
11
-
12
- /**
13
- * 试用徽章共享 Hook:vertical / full 两种 screenType 下共用同一份状态、回调和方法。
14
- *
15
- * - `showTrialBadge`:是否展示徽章;仅当 0 < trialRemainingSec < 300 时展示,倒计时归零会自动置 false。
16
- * - `handleTrialSubscribe`:「开通」按钮点击回调。
17
- * - `handleCountdownEnd`:倒计时归零回调,内部会广播 `trialCountdownEnd`
18
- * 事件给其它控件(例如 TryExperience)刷新自身状态。
19
- */
20
- export const useTrialBadge = (event, trialRemainingSec) => {
5
+ import Strings from '../../i18n';
6
+ export const useTrialBadge = (event, devId, trialRemainingSec) => {
21
7
  const [showTrialBadge, setShowTrialBadge] = useState(false);
8
+ const prevTrialSecRef = useRef(trialRemainingSec);
22
9
  useEffect(() => {
23
10
  if (trialRemainingSec > 0 && trialRemainingSec < 300) {
24
- setShowTrialBadge(true);
11
+ if (trialRemainingSec !== prevTrialSecRef.current) {
12
+ setShowTrialBadge(true);
13
+ }
25
14
  }
15
+ prevTrialSecRef.current = trialRemainingSec;
26
16
  }, [trialRemainingSec]);
27
- const handleTrialSubscribe = useCallback(() => {
28
- console.log('[TrialBadge] click subscribe');
29
- }, []);
30
- const handleCountdownEnd = useCallback(() => {
31
- trialEndedTest();
32
- event.emit(trialCountdownEnd);
33
- setShowTrialBadge(false);
34
- }, [event]);
17
+ const handleTrialSubscribe = useCallback(async () => {
18
+ try {
19
+ await gotoSecurityCloudService2(devId);
20
+ } catch (error) {
21
+ ty.showToast({
22
+ title: Strings.getLang('ipc_player_fetch_error'),
23
+ icon: 'none'
24
+ });
25
+ }
26
+ }, [devId]);
27
+ const handleCountdownEnd = useCallback(async () => {
28
+ try {
29
+ setShowTrialBadge(false);
30
+ event.emit(trialCountdownEnd);
31
+ await setTrailFinish(devId);
32
+ } catch (error) {
33
+ ty.showToast({
34
+ title: Strings.getLang('ipc_player_fetch_error'),
35
+ icon: 'none'
36
+ });
37
+ }
38
+ }, [devId, event]);
35
39
  return {
36
40
  showTrialBadge,
37
41
  setShowTrialBadge,
@@ -5,6 +5,11 @@ type Props = ComponentConfigProps & {
5
5
  className?: string;
6
6
  hideTryExperienceMenu?: boolean;
7
7
  buttonState?: number;
8
+ trialRemainingSec?: number;
9
+ isPurchase?: boolean;
10
+ canOpenSettings?: boolean;
11
+ gRawData?: boolean;
12
+ isLowPhone?: boolean;
8
13
  };
9
14
  export declare const TryExperience: (props: Props) => React.JSX.Element | null;
10
15
  export {};
@@ -1,8 +1,11 @@
1
- import { View, Image, getSystemInfoSync } from '@ray-js/ray';
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import { View, Image, getSystemInfoSync, showToast } from '@ray-js/ray';
2
3
  import clsx from 'clsx';
3
- import React, { useContext } from 'react';
4
- import { pauseTimeToHideAllComponent, widgetClick, widgetLabs, tryExperienceBtnClick } from '../../ui/constant';
5
- import { UIEventContext } from '../../ui/context';
4
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
5
+ import { useStore } from '../../ctx/store';
6
+ import Strings from '../../i18n';
7
+ import { getAIFrameFeature, gotoAIDrawMiniProgram, setAIFrameFeature } from '../../utils';
8
+ import { refreshSmartImageQualityEvent } from '../../ui/constant';
6
9
  import tryZh from '../../res/try/try_zh.png';
7
10
  import tryEn from '../../res/try/try_en.png';
8
11
  import tryOpen from '../../res/try/try_open.png';
@@ -33,39 +36,127 @@ const pickIconByStatus = buttonState => {
33
36
  case TryExperienceStatus.Close:
34
37
  return tryClose;
35
38
  case TryExperienceStatus.Default:
36
- default:
37
39
  return getDefaultLangIcon();
40
+ default:
41
+ return '';
38
42
  }
39
43
  };
40
44
  export const TryExperience = props => {
41
45
  const {
42
46
  className,
43
47
  hideTryExperienceMenu,
44
- buttonState = 0,
45
- event: propsEvent
48
+ buttonState,
49
+ trialRemainingSec,
50
+ isPurchase,
51
+ canOpenSettings,
52
+ gRawData,
53
+ isLowPhone,
54
+ devId
46
55
  } = props;
47
56
  const {
48
- event: ctxEvent
49
- } = useContext(UIEventContext);
50
- const event = propsEvent !== null && propsEvent !== void 0 ? propsEvent : ctxEvent;
51
- const iconUrl = pickIconByStatus(buttonState);
57
+ brandColor,
58
+ recording
59
+ } = useStore({
60
+ brandColor: props.brandColor,
61
+ recording: props.recording
62
+ });
63
+ const [imgSrc, setImgSrc] = useState();
64
+ const lockRef = useRef(false);
65
+ useEffect(() => {
66
+ updateImgSrc();
67
+ }, [buttonState]);
68
+ const updateImgSrc = useCallback(() => {
69
+ console.log('res===updateImgSrc', buttonState, isLowPhone);
70
+ if (isLowPhone) {
71
+ setImgSrc(tryClose);
72
+ return;
73
+ }
74
+ if (buttonState === 0 || buttonState) {
75
+ const iconUrl = pickIconByStatus(buttonState);
76
+ setImgSrc(iconUrl);
77
+ } else {
78
+ setImgSrc(undefined);
79
+ }
80
+ }, [buttonState]);
81
+ const onTryExperience = useCallback(async () => {
82
+ console.log('res===onTryExperience', lockRef.current, isLowPhone);
83
+ if (lockRef.current) return;
84
+ if (isLowPhone) {
85
+ showToast({
86
+ title: Strings.getLang('ipc_player_low_phone_not_support'),
87
+ icon: 'none'
88
+ });
89
+ return;
90
+ }
91
+ if (recording) {
92
+ showToast({
93
+ title: Strings.getLang('ipc_player_recording_now_tip'),
94
+ icon: 'none'
95
+ });
96
+ return;
97
+ }
98
+ lockRef.current = true;
99
+ try {
100
+ const getAI = await getAIFrameFeature(devId);
101
+ if (buttonState === TryExperienceStatus.Open) {
102
+ var _getAI$aiFrameFeature, _getAI$aiFrameFeature2, _getAI$aiFrameFeature3, _props$event;
103
+ // 由开变关的时候,只关inPreview
104
+ const scope = _objectSpread(_objectSpread({}, (_getAI$aiFrameFeature = getAI.aiFrameFeature) === null || _getAI$aiFrameFeature === void 0 ? void 0 : _getAI$aiFrameFeature.scope), {}, {
105
+ inPreview: false
106
+ });
107
+ await setAIFrameFeature({
108
+ devId,
109
+ scene: 'inPreview',
110
+ // 实时预览场景
111
+ enabled: getAI.enabled,
112
+ aiFrameFeature: {
113
+ scope,
114
+ feature: (_getAI$aiFrameFeature2 = getAI.aiFrameFeature) === null || _getAI$aiFrameFeature2 === void 0 ? void 0 : _getAI$aiFrameFeature2.feature,
115
+ exportEnabled: (_getAI$aiFrameFeature3 = getAI.aiFrameFeature) === null || _getAI$aiFrameFeature3 === void 0 ? void 0 : _getAI$aiFrameFeature3.exportEnabled
116
+ }
117
+ });
118
+ (_props$event = props.event) === null || _props$event === void 0 || _props$event.emit(refreshSmartImageQualityEvent);
119
+ } else if (buttonState === TryExperienceStatus.Close && isPurchase || buttonState === TryExperienceStatus.Close && trialRemainingSec < 300 && trialRemainingSec > 0) {
120
+ var _getAI$aiFrameFeature4, _getAI$aiFrameFeature5, _getAI$aiFrameFeature6, _props$event2;
121
+ const scope = _objectSpread(_objectSpread({}, (_getAI$aiFrameFeature4 = getAI.aiFrameFeature) === null || _getAI$aiFrameFeature4 === void 0 ? void 0 : _getAI$aiFrameFeature4.scope), {}, {
122
+ inPreview: true
123
+ });
124
+ // 由关变开的时候,enabled和inPreview两个都开
125
+ await setAIFrameFeature({
126
+ devId,
127
+ scene: 'inPreview',
128
+ // 实时预览场景
129
+ enabled: true,
130
+ aiFrameFeature: {
131
+ scope,
132
+ feature: (_getAI$aiFrameFeature5 = getAI.aiFrameFeature) === null || _getAI$aiFrameFeature5 === void 0 ? void 0 : _getAI$aiFrameFeature5.feature,
133
+ exportEnabled: (_getAI$aiFrameFeature6 = getAI.aiFrameFeature) === null || _getAI$aiFrameFeature6 === void 0 ? void 0 : _getAI$aiFrameFeature6.exportEnabled
134
+ }
135
+ });
136
+ (_props$event2 = props.event) === null || _props$event2 === void 0 || _props$event2.emit(refreshSmartImageQualityEvent);
137
+ } else {
138
+ gotoAIDrawMiniProgram(devId, brandColor);
139
+ }
140
+ } catch (error) {
141
+ //
142
+ } finally {
143
+ lockRef.current = false;
144
+ }
145
+ }, [buttonState, recording, isPurchase, trialRemainingSec]);
52
146
  if (hideTryExperienceMenu) {
53
147
  return null;
54
148
  }
149
+ if (!imgSrc || !canOpenSettings || !gRawData) {
150
+ return null;
151
+ }
55
152
  return /*#__PURE__*/React.createElement(View, {
56
153
  className: clsx(className),
57
- onClick: () => {
58
- event.emit(widgetClick, {
59
- widgetId: widgetLabs.TRY_EXPERIENCE
60
- });
61
- event.emit(tryExperienceBtnClick);
62
- event.emit(pauseTimeToHideAllComponent);
63
- }
154
+ onClick: onTryExperience
64
155
  }, /*#__PURE__*/React.createElement(View, {
65
156
  className: "try-experience-box"
66
157
  }, /*#__PURE__*/React.createElement(Image, {
67
158
  className: "try-experience-icon",
68
- src: iconUrl,
159
+ src: imgSrc,
69
160
  mode: "heightFix"
70
161
  })));
71
162
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/ipc-player-integration",
3
- "version": "0.0.35-beta.2",
3
+ "version": "0.0.35-beta.21",
4
4
  "description": "IPC 融合播放器",
5
5
  "main": "lib/index",
6
6
  "files": [
@@ -64,7 +64,7 @@
64
64
  "husky": {
65
65
  "hooks": {
66
66
  "commit-msg": "commitlint -E HUSKY_GIT_PARAMS --config commitlint.config.js",
67
- "pre-commit": "lint-staged"
67
+ "pre-commit": "node ./scripts/check-protected-files.js && lint-staged"
68
68
  }
69
69
  },
70
70
  "lint-staged": {