• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import router from '@system.router';
17import display from '@ohos.display';
18import deviceInfo from '@ohos.deviceInfo'
19import { BigVideoTimer } from './BigVideoTimer'
20import { Action, UiStateMode } from '@ohos/common/src/main/ets/default/redux/actions/Action'
21import { AssistiveGridView } from '@ohos/common/src/main/ets/default/featurecommon/assistivegridview/AssistiveGridView'
22import { BigText } from '@ohos/common/src/main/ets/default/featurecommon/bigtext/BigText'
23import { CameraNeedStatus, CameraStatus } from '@ohos/common/src/main/ets/default/utils/Constants'
24import { CameraId } from '@ohos/common/src/main/ets/default/setting/settingitem/CameraId'
25import { EventBus } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBus'
26import { EventBusManager } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBusManager'
27import { Dispatch, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store'
28import { getStore } from '@ohos/common/src/main/ets/default/redux/store'
29import { Log } from '@ohos/common/src/main/ets/default/utils/Log'
30import { GeoLocation } from '@ohos/common/src/main/ets/default/featurecommon/geolocation/GeoLocation'
31import { ScreenLockManager } from '@ohos/common/src/main/ets/default/featurecommon/screenlock/ScreenLockManager'
32import { SettingManager } from '@ohos/common/src/main/ets/default/setting/SettingManager'
33import { ShowFlashBlack } from '@ohos/common/src/main/ets/default/featurecommon/animate/ShowFlashBlack'
34import { TimeLapseView } from '@ohos/common/src/main/ets/default/featurecommon/timelapseview/TimeLapseView'
35import { ZoomText } from '@ohos/common/src/main/ets/default/featurecommon/zoomview/ZoomText'
36import { SmallVideoTimer } from './SmallVideoTimer'
37import promptAction from '@ohos.promptAction';
38import wantConstant from '@ohos.ability.wantConstant';
39import { GlobalContext } from '@ohos/common/src/main/ets/default/utils/GlobalContext';
40import { CameraPlatformCapability } from '@ohos/common/src/main/ets/default/camera/CameraPlatformCapability';
41import { BusinessError } from '@ohos.base';
42
43const DEFAULT_FUNCTION: Function = () => {
44};
45
46class SizeStruct {
47  width: number = 0;
48  height: number = 0;
49}
50
51class StateStruct {
52  mode: string = '';
53  curMode: string = '';
54  isShowPreview: boolean = true;
55  surfaceId: number = 0;
56  xComponentWidth: number = 0;
57  xComponentHeight: number = 0;
58  cameraPosition: CameraId = CameraId.BACK;
59  curCameraPosition: CameraId = CameraId.BACK;
60  minZoomRatio: number = 0;
61  maxZoomRatio: number = 0;
62  zoomRatio: number = 0;
63  platformCapability: CameraPlatformCapability | undefined = undefined;
64  videoState: string = '';
65  footBarHeight: number = 0;
66  isShowZoomText: boolean = false;
67  showZoomLabelValue: boolean = false;
68  modeIndex: number = 0;
69  isThirdPartyCall: boolean = false;
70  isShowBigText: boolean = false;
71  isShowtimeLapse: boolean = false;
72  isBigVideoTimerVisible: boolean = false;
73  isSmallVideoTimerVisible: boolean = false;
74  isAssGridViewShow: string = '';
75  isShowFlashBlack: boolean = false;
76  modeChangeDone: boolean = false;
77  isShowPageView: boolean = false;
78  showBlur: boolean = false;
79  isFaCall: boolean = false;
80  baseZoom: number = 0;
81}
82
83class PreviewAreaDispatcher {
84  private mDispatch: Dispatch = (data) => data;
85
86  public setDispatch(dispatch: Dispatch) {
87    this.mDispatch = dispatch;
88  }
89
90  public initCamera(cameraId: CameraId, mode: string): void {
91    this.mDispatch(Action.initCamera(cameraId, mode));
92  }
93
94  public initZoomRatio(min: number, max: number): void {
95    this.mDispatch(Action.initZoomRatio(min, max));
96  }
97
98  public changeZoomRatio(zoomRatio: number): void {
99    this.mDispatch(Action.changeZoomRatio(zoomRatio));
100  }
101
102  public updateZoomPercentage(zoomPercentage: number): void {
103    this.mDispatch(Action.updateZoomPercentage(zoomPercentage));
104  }
105
106  public prepareSurface(surfaceId: number): void {
107    this.mDispatch(Action.prepareSurface(surfaceId));
108  }
109
110  public startPreview(zoomRatio: number): void {
111    this.mDispatch(Action.startPreview(zoomRatio));
112  }
113
114  public switchCamera(cameraId: CameraId, mode: string): void {
115    this.mDispatch(Action.switchCamera(cameraId, mode));
116  }
117
118  public updateCameraPosition(cameraPosition: string): void {
119    this.mDispatch(Action.updateCameraPosition(cameraPosition));
120  }
121
122  public startVideoFlag(isStartVideo: boolean): void {
123    this.mDispatch(Action.startVideoFlag(isStartVideo));
124  }
125
126  public changeXComponentSize(xComponentWidth: number, xComponentHeight: number): void {
127    this.mDispatch(Action.changeXComponentSize(xComponentWidth, xComponentHeight));
128  }
129
130  public updateShowPreviewFlag(isShowPreview: boolean): void {
131    this.mDispatch(Action.updateShowPreviewFlag(isShowPreview));
132  }
133
134  public updateIsShowZoomText(isShowZoomText: boolean): void {
135    this.mDispatch(Action.updateShowZoomTextFlag(isShowZoomText));
136  }
137
138  public updateIsPhotoZoomDetails(isPhotoZoomDetails: boolean): void {
139    this.mDispatch(Action.updatePhotoZoomDetailsFlag(isPhotoZoomDetails));
140  }
141
142  public updateBaseZoom(zoomRatio: number): void {
143    this.mDispatch(Action.updateBaseZoom(zoomRatio));
144  }
145
146  public changeImageSize(videoSize: ScreenSizeType): void {
147    this.mDispatch(Action.changeVideoSize(videoSize));
148  }
149
150  public changeVideoSize(videoSize: SizeStruct): void {
151    this.mDispatch(Action.changeVideoSize(videoSize));
152  }
153
154  public close(): void {
155    this.mDispatch(Action.close());
156  }
157
158  public stopRecording(): void {
159    this.mDispatch(Action.stopRecording());
160    this.mDispatch(Action.updateVideoState('beforeTakeVideo'));
161    this.mDispatch(Action.updateBigVideoTimerVisible(false));
162    this.mDispatch(Action.updateSmallVideoTimerVisible(false));
163    this.mDispatch(Action.updateScreenStatus(false));
164  }
165
166  public changeTimeLapse(isShowtimeLapse: boolean): void {
167    this.mDispatch(Action.changeTimeLapse(isShowtimeLapse));
168  }
169
170  public capture(): void {
171    this.mDispatch(Action.updateShowFlashBlackFlag(true));
172    this.mDispatch(Action.capture());
173  }
174
175  public startRecording(): void {
176    this.mDispatch(Action.startRecording());
177    this.mDispatch(Action.updateVideoState('startTakeVideo'));
178    this.mDispatch(Action.updateBigVideoTimerVisible(true));
179    this.mDispatch(Action.updateScreenStatus(true));
180  }
181
182  public assistiveGridView(isViewShow: number): void {
183    this.mDispatch(Action.assistiveGridView(isViewShow));
184  }
185
186  public swipeChangeMode(swipeModeIndex: number): void {
187    this.mDispatch(Action.swipeChangeMode(swipeModeIndex));
188  }
189
190  public thirdPartyCall(isThirdPartyCall: boolean, action: string): void {
191    this.mDispatch(Action.thirdPartyCall(isThirdPartyCall, action));
192  }
193
194  public faCall(isFaCall: boolean): void {
195    this.mDispatch(Action.faCall(isFaCall));
196  }
197
198  public initMode(mode: string): void {
199    this.mDispatch(Action.initMode(mode));
200  }
201
202  public updateModeIndex(index: number): void {
203    this.mDispatch(Action.updateModeIndex(index));
204  }
205
206  public updateMode(mode: string): void {
207    this.mDispatch(Action.updateMode(mode));
208  }
209
210  public changeToMode(mode: string): void {
211    this.mDispatch(Action.changeMode(mode));
212  }
213
214  public updateShowZoomLabelValue(flag: boolean): void {
215    this.mDispatch(Action.updateShowZoomLabelValue(flag));
216  }
217
218  public reloadThumbnail(): void {
219    this.mDispatch(Action.reloadThumbnail());
220  }
221
222  public changeCameraPosition(cameraPosition: string): void {
223    this.mDispatch(Action.setCameraPosition(cameraPosition));
224  }
225
226  public updateShowPinch(flag: boolean): void {
227    this.mDispatch(Action.updateShowPinch(flag));
228  }
229
230  public swipeModeChangeDone(actionOff: boolean): void {
231    this.mDispatch(Action.swipeModeChangeDone(actionOff));
232  }
233
234  public updateInitShowFlag(initShowFlag: boolean): void {
235    this.mDispatch(Action.updateInitShowFlag(initShowFlag));
236  }
237
238  public hideSettingView(): void {
239    this.mDispatch(Action.showSettingView(false));
240  }
241}
242
243GlobalContext.get().setXComponentController(new XComponentController())
244
245interface ScreenSizeType {
246  width: number
247  height: number
248}
249
250interface PlatformCapability {
251  platformCapability: CameraPlatformCapability
252}
253
254interface ModeData {
255  mode: string
256}
257
258interface KeepScreenData {
259  isKeepScreenOn: boolean
260}
261
262@Component
263export struct PreviewAreaLand {
264  private TAG: string = '[PreviewAreaLand]:';
265  appEventBus: EventBus = EventBusManager.getInstance().getEventBus();
266  @State state: StateStruct = new StateStruct();
267  @State btnSwitch: boolean = false;
268  @State btnSwitchSec: boolean = false;
269  @State pinchGestureTimerId: number = 0;
270  @State onTouchDownTimerId: number = 0;
271  @State scaleX: number = 1;
272  @State scaleXSec: number = 0.8;
273  @State rotateAngle: number = 0;
274  @State rotateAngleSec: number = 80;
275  @State btnOpacityFirst: number = 1;
276  @State btnOpacitySec: number = 0;
277  @State switchBackgroundOpacity: number = 1;
278  @State isSwitchBackground: boolean = false;
279  @State pageType: string = '';
280  @Link screenSize: ScreenSizeType;
281  @State isShowBlurSize: ScreenSizeType = { width: 0, height: 0 };
282  private mConnect: Function = () => {
283  };
284  private isShowPreview: boolean = false;
285  private settingManager = SettingManager.getInstance();
286  private pinchGestureTimer: number = 0;
287  private baseZoom: number = 0;
288  private modeArray: Array<string> = ['MULTI', 'PHOTO', 'VIDEO'];
289  private mAction: PreviewAreaDispatcher = new PreviewAreaDispatcher();
290
291  private async onCameraInit(): Promise<void> {
292    Log.info(`${this.TAG} EventBus onCameraInit isShowPreview = ${this.isShowPreview}
293      platformCapability = ${this.state.platformCapability} E`);
294    if (this.state.platformCapability) {
295      this.settingManager.loadAllSetting().then(() => {
296        this.settingManager.setCameraId(this.state.cameraPosition);
297
298        let imageSize = this.settingManager.getImageSize();
299        this.mAction.changeImageSize(imageSize);
300
301        let videoSize = this.settingManager.getVideoSize();
302        this.mAction.changeVideoSize(videoSize);
303
304        let isAssGridViewShow: number = Number(this.settingManager.getAssistiveGrid());
305        this.mAction.assistiveGridView(isAssGridViewShow);
306
307        GeoLocation.getInstance().on();
308
309        this.resetScreenSize(this.screenSize);
310        this.mAction.updateShowPreviewFlag(true);
311      })
312    }
313    Log.info(`${this.TAG} onCameraInit isShowPreview = ${this.state.isShowPreview}  X`);
314  }
315
316  private async doCameraAction() {
317    Log.info(`${this.TAG} doCameraAction E`);
318    this.settingManager.setCameraId(this.state.cameraPosition);
319    Log.info(`${this.TAG} curMode:${this.state.curMode} mode:${this.state.mode}`);
320    if (this.state.curCameraPosition != this.state.cameraPosition) {
321      this.mAction.switchCamera(this.state.cameraPosition, this.state.mode);
322      this.mAction.updateCameraPosition(this.state.cameraPosition);
323    } else if (this.state.curMode != this.state.mode) {
324      this.mAction.changeToMode(this.state.mode);
325      this.mAction.updateMode(this.state.mode);
326    } else {
327      if (GlobalContext.get().getT<boolean>('keepCameraZoomRatio') && GlobalContext.get()
328        .getT<boolean>('keepCameraZoomRatio')) {
329        GlobalContext.get().setObject('keepCameraZoomRatio', false)
330        Log.info(`${this.TAG} keep zoomRatio: ` + this.state.zoomRatio);
331      } else {
332        this.mAction.changeZoomRatio(1);
333        Log.info(`${this.TAG} change zoomRatio: 1`);
334      }
335      this.mAction.startPreview(this.state.zoomRatio);
336    }
337    Log.info(`${this.TAG} doCameraAction X`);
338    this.mAction.updateInitShowFlag(true);
339  }
340
341  private async onModeChanged(data: ModeData) {
342    Log.debug(`${this.TAG} onModeChanged E data.mode: ${data.mode}`);
343    this.mAction.changeZoomRatio(1);
344    this.mAction.updateShowPreviewFlag(true);
345    Log.debug(`${this.TAG} onModeChanged X`);
346  }
347
348  private async onRecordError() {
349    Log.info(`${this.TAG} onRecordError invoke E`);
350    promptAction.showToast({
351      message: "录像异常",
352      duration: 2000,
353    })
354    if (this.state.videoState === 'startTakeVideo') {
355      this.mAction.stopRecording();
356    }
357    this.mAction.close();
358    Log.info(`${this.TAG} onRecordError invoke X`);
359  }
360
361  aboutToAppear(): void {
362    Log.info(`${this.TAG} aboutToAppear E ${JSON.stringify(router.getParams())}`);
363    let routerParams = router.getParams();
364    if (routerParams && routerParams.pageType) {
365      this.pageType = routerParams.pageType.toString();
366    }
367    getStore().subscribe((state: OhCombinedState) => {
368      let isShowBlur: boolean = !state.contextReducer.uiEnable && state.contextReducer.uiStateMode == UiStateMode.NONE;
369      this.state = {
370        mode: state.modeReducer.mode,
371        curMode: state.modeReducer.curMode,
372        isShowPreview: state.previewReducer.isShowPreview,
373        surfaceId: state.previewReducer.surfaceId,
374        xComponentWidth: state.previewReducer.xComponentWidth,
375        xComponentHeight: state.previewReducer.xComponentHeight,
376        cameraPosition: state.cameraReducer.cameraPosition,
377        curCameraPosition: state.cameraReducer.curCameraPosition,
378        minZoomRatio: state.zoomReducer.minZoomRatio,
379        maxZoomRatio: state.zoomReducer.maxZoomRatio,
380        zoomRatio: state.zoomReducer.zoomRatio,
381        platformCapability: state.cameraInitReducer.platformCapability,
382        videoState: state.recordReducer.videoState,
383        footBarHeight: state.contextReducer.footBarHeight,
384        isShowZoomText: state.zoomReducer.isShowZoomText,
385        showZoomLabelValue: state.zoomReducer.showZoomLabelValue,
386        modeIndex: state.modeReducer.modeIndex,
387        isThirdPartyCall: state.contextReducer.isThirdPartyCall,
388        isShowBigText: state.modeReducer.isShowBigText,
389        isShowtimeLapse: state.settingReducer.isShowtimeLapse,
390        isBigVideoTimerVisible: state.recordReducer.isBigVideoTimerVisible,
391        isSmallVideoTimerVisible: state.recordReducer.isSmallVideoTimerVisible,
392        isAssGridViewShow: state.settingReducer.isAssGridViewShow,
393        isShowFlashBlack: state.previewReducer.isShowFlashBlack,
394        modeChangeDone: state.modeReducer.modeChangeDone,
395        isShowPageView: state.settingReducer.isShowSettingView,
396        showBlur: isShowBlur,
397        isFaCall: state.contextReducer.isFaCall,
398        baseZoom: 0
399
400      };
401    }, (dispatch: Dispatch) => {
402      this.mAction.setDispatch(dispatch);
403    });
404    this.mConnect(this.state)
405    this.appEventBus.on(Action.ACTION_INIT_DONE, () => this.onCameraInit);
406    this.appEventBus.on(Action.ACTION_ON_MODE_CHANGED, () => this.onModeChanged);
407    this.appEventBus.on(Action.ACTION_KEEP_SCREEN_ON, () => this.onKeepScreen);
408    this.appEventBus.on("windowSize", () => this.windowSizeChange);
409    this.appEventBus.on(Action.ACTION_RECORD_ERROR, () => this.onRecordError);
410    this.appEventBus.on(ScreenLockManager.SCREEN_CHANGE_EVENT, () => this.onScreenChange);
411    this.appEventBus.on(Action.ACTION_UPDATE_CAMERA_STATUS, () => this.updateCameraStatus);
412    GlobalContext.get().setObject('updateCameraStatus', () => {
413      Log.info(`${this.TAG} globalThis.updateCameraStatus called`);
414      this.updateCameraStatus();
415    });
416    display.getDefaultDisplay().then((dis) => {
417      this.isShowBlurSize = { width: px2vp(dis.width), height: px2vp(dis.height) };
418    })
419    this.calledByOther();
420    this.mAction.initCamera(this.state.cameraPosition, this.state.mode);
421    this.mAction.initZoomRatio(1, 6); //TODO 需要动态取得实际变焦能力范围
422    Log.info(`${this.TAG} aboutToAppear X`);
423    Log.start(Log.X_COMPONENT_LIFE);
424  }
425
426  private releaseCamera(): void {
427    Log.info(`${this.TAG} globalThis.releaseCamera called`);
428    GlobalContext.get().setObject('cameraNeedStatus', CameraNeedStatus.CAMERA_NO_NEED_TO_DO);
429    if (this.state.videoState === 'startTakeVideo') {
430      this.mAction.stopRecording();
431    }
432    this.mAction.close();
433  }
434
435  private async onForegroundInit() {
436    Log.info(`${this.TAG} onForegroundInit E `);
437    this.pageType = '';
438    GlobalContext.get().setObject('cameraNeedStatus', CameraNeedStatus.CAMERA_NO_NEED_TO_DO);
439    this.calledByOther();
440    this.mAction.initCamera(this.state.cameraPosition, this.state.mode);
441    await new Promise<Function | string>((resolve: Function | string) => setTimeout(resolve, 40));
442    this.doCameraAction();
443    this.mAction.updateInitShowFlag(true);
444    if (!this.state.isThirdPartyCall) {
445      this.mAction.reloadThumbnail();
446    }
447    Log.info(`${this.TAG} onForegroundInit X`);
448  }
449
450  private calledByOther(): void {
451    Log.info(`${this.TAG} calledByOther invoke E`);
452    let from: string = "";
453    let action: string = "";
454
455    if (GlobalContext.get().getCameraAbilityWant()) {
456      Log.info(`${this.TAG} cameraAbilityWant: ${JSON.stringify(GlobalContext.get().getCameraAbilityWant())}`);
457      if (GlobalContext.get().getCameraAbilityWant()?.parameters?.from) {
458        from = GlobalContext.get().getCameraAbilityWant()?.parameters?.from as string;
459      }
460      let cameraAbilityWant = GlobalContext.get().getCameraAbilityWant();
461      if (cameraAbilityWant?.action) {
462        action = cameraAbilityWant?.action;
463      }
464    } else {
465      this.mAction.thirdPartyCall(false, "");
466      return;
467    }
468    Log.info(`${this.TAG} from: ${from}  uri: ${action}`);
469
470    if (from === "FA") {
471      Log.info(`from === "FA"`);
472      if (GlobalContext.get().getCameraAbilityWant()?.parameters?.action) {
473        action = GlobalContext.get().getCameraAbilityWant()?.parameters?.action as string;
474      }
475      this.mAction.faCall(true);
476      this.mAction.thirdPartyCall(false, "");
477      this.initStateMode(action);
478    } else if (action != "") {
479      this.mAction.faCall(false);
480      this.mAction.thirdPartyCall(true, GlobalContext.get().getCameraAbilityWant().action);
481      this.initStateMode(action);
482    } else {
483      this.mAction.faCall(false);
484      this.mAction.thirdPartyCall(false, "");
485    }
486    Log.info(`${this.TAG} calledByOther invoke X: ${this.state.mode}`);
487  }
488
489  private initStateMode(action: string): void {
490    switch (action) {
491      case wantConstant.Action.ACTION_IMAGE_CAPTURE:
492        this.mAction.initMode('PHOTO');
493        this.mAction.updateModeIndex(1);
494        break;
495      case wantConstant.Action.ACTION_VIDEO_CAPTURE:
496        this.mAction.initMode('VIDEO');
497        this.mAction.updateModeIndex(2);
498        break;
499      default:
500        Log.info(`${this.TAG} FA default`);
501        break;
502    }
503  }
504
505  private updateCameraStatus(): void {
506    Log.info(`${this.TAG} updateCameraStatus  cameraStatus: ${GlobalContext.get().getT<string>('cameraStatus')}
507      cameraNeedStatus: ${GlobalContext.get().getT<string>('cameraNeedStatus')}`);
508    if (this.canInit() && GlobalContext.get().getT<string>('cameraNeedStatus') == CameraNeedStatus.CAMERA_NEED_INIT) {
509      this.onForegroundInit();
510    }
511    if (this.canRelease() && GlobalContext.get()
512      .getT<string>('cameraNeedStatus') == CameraNeedStatus.CAMERA_NEED_RELEASE) {
513      this.releaseCamera();
514    }
515    Log.info(`${this.TAG} updateCameraStatus X`);
516  }
517
518  private canInit(): boolean {
519    //相机状态是首次加载或者session释放完成状态,才能进行初始化操作
520    return GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_BEFORE_VALUE ||
521      GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_RELEASE_FINISHED;
522  }
523
524  private canRelease(): boolean {
525    //相机状态是预览完成状态或录像完成状态才能进行释放操作
526    return GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_PREVIEW_FINISHED ||
527      GlobalContext.get().getT<string>('cameraStatus') == CameraStatus.CAMERA_TAKE_VIDEO_FINISHED;
528  }
529
530  aboutToDisappear(): void {
531    Log.info(`${this.TAG} aboutToDisappear E`);
532    this.appEventBus.off(Action.ACTION_INIT_DONE, () => this.onCameraInit);
533    this.appEventBus.off(Action.ACTION_ON_MODE_CHANGED, () => this.onModeChanged);
534    this.appEventBus.off("windowSize", () => this.windowSizeChange);
535    this.appEventBus.off(Action.ACTION_UPDATE_CAMERA_STATUS, () => this.updateCameraStatus);
536    // this.mConnect?.destroy();
537    GeoLocation.getInstance().off();
538    GlobalContext.get().setObject('cameraNeedStatus', CameraNeedStatus.CAMERA_NEED_RELEASE)
539    this.updateCameraStatus();
540    Log.info(`${this.TAG} aboutToDisappear X`);
541  }
542
543  onPageHide(): void {
544    this.mAction.startVideoFlag(false);
545    Log.info(`${this.TAG} onPageHide`);
546  }
547
548  private switchAnimationSec(): void {
549    Log.info(`${this.TAG} switchAnimationSec called`);
550    animateTo({ duration: 200,
551      delay: 0,
552      curve: Curve.Sharp,
553    }, () => {
554      this.btnOpacitySec = 1;
555    })
556    animateTo({
557      duration: 350,
558      curve: Curve.FastOutSlowIn,
559      delay: 0,
560    }, () => {
561      Log.info(`${this.TAG} btnSwitchSec callback btnSwitchSec= ${this.btnSwitchSec}`);
562      this.scaleXSec = 1;
563    })
564    animateTo({
565      duration: 350,
566      curve: 'cubic-bezier(0.21, 0.27, 0.20, 1.00)',
567      delay: 0,
568      onFinish: () => {
569        Log.info(`${this.TAG} btnSwitchSec onFinish btnSwitchSec= ${this.btnSwitchSec}`);
570        this.btnSwitchSec = false;
571        this.btnOpacitySec = 0;
572        this.scaleXSec = 0.8;
573        this.rotateAngleSec = 80;
574        this.switchBackgroundAnimation();
575      }
576    }, () => {
577      Log.info(`${this.TAG} btnSwitchSec callback btnSwitchSec= ${this.btnSwitchSec}`);
578      this.rotateAngleSec = 0;
579      //      this.btnSwitchSec = true
580    })
581  }
582
583  private switchBackgroundAnimation(): void {
584    animateTo({ duration: 350,
585      delay: 0,
586      curve: Curve.Sharp,
587      onFinish: () => {
588        this.isSwitchBackground = false;
589        this.switchBackgroundOpacity = 1;
590      }
591    }, () => {
592      this.switchBackgroundOpacity = 0;
593    })
594  }
595
596  private pinchGestureStart(event: GestureEvent): void {
597    Log.info(`${this.TAG} pinchGestureStart invoke E`);
598    if (this.state.mode != 'MULTI' && this.state.cameraPosition !== 'FRONT') {
599      clearTimeout(this.pinchGestureTimer);
600      this.mAction.updateIsShowZoomText(true);
601      this.mAction.updateShowPinch(true);
602      this.mAction.updateShowZoomLabelValue(false);
603      this.baseZoom = this.state.zoomRatio;
604    }
605    if (this.state.mode !== "MULTI" && this.state.cameraPosition !== 'FRONT') {
606      this.mAction.updateIsShowZoomText(true);
607      this.mAction.updateShowPinch(true);
608      this.mAction.updateIsPhotoZoomDetails(true);
609      this.mAction.updateBaseZoom(this.state.zoomRatio);
610      clearTimeout(this.pinchGestureTimerId);
611      clearTimeout(this.onTouchDownTimerId);
612    }
613    Log.info(`${this.TAG} pinchGestureStart invoke X`);
614  }
615
616  private pinchGestureUpdate(event: GestureEvent): void {
617    Log.info(`${this.TAG} pinchGestureUpdate invoke E`);
618    if (this.state.mode != 'MULTI' && this.state.cameraPosition !== 'FRONT') {
619      let zoomRatio = event.scale + this.baseZoom - 1;
620      if (zoomRatio > 6) {
621        zoomRatio = 6;
622      }
623      if (zoomRatio < 1) {
624        zoomRatio = 1;
625      }
626      this.mAction.changeZoomRatio(zoomRatio);
627    }
628    Log.info(`${this.TAG} pinchGestureUpdate invoke X`);
629  }
630
631  private pinchGestureEnd(event: GestureEvent): void {
632    Log.info(`${this.TAG} pinchGestureEnd invoke E`);
633    this.mAction.updateShowZoomLabelValue(true);
634    this.mAction.updateShowPinch(false);
635    if (this.state.mode != 'MULTI' && this.state.cameraPosition !== 'FRONT') {
636      this.pinchGestureTimer = setTimeout(() => {
637        this.mAction.updateIsShowZoomText(false);
638      }, 2000)
639    }
640    Log.info(`${this.TAG} pinchGestureEnd invoke X`);
641  }
642
643  private onPreviewClicked(): void {
644    Log.info(`${this.TAG} onPreviewClicked isShowtimeLapse= ${this.state.isShowtimeLapse}, state.mode= ${this.state.mode}`);
645    if (this.state.mode === 'PHOTO' && this.state.isShowtimeLapse) {
646      this.mAction.changeTimeLapse(false);
647      this.mAction.capture();
648    } else if (this.state.mode === 'VIDEO' && this.state.isShowtimeLapse) {
649      this.mAction.changeTimeLapse(false);
650      this.mAction.startRecording();
651    }
652    Log.info(`${this.TAG} onPreviewClicked invoke X`);
653  }
654
655  private swipeChangeMode(swipe: number): void {
656    Log.info(`${this.TAG} swipeChangeMode E`);
657    if (!this.state.modeChangeDone && this.state.modeIndex + swipe >= 0 && this.state.modeIndex + swipe <= this.modeArray.length - 1 && !this.state.isShowtimeLapse) {
658      this.mAction.swipeChangeMode(this.state.modeIndex + swipe);
659      this.mAction.swipeModeChangeDone(true);
660    }
661    Log.info(`${this.TAG} swipeChangeMode X`);
662  }
663
664  private onKeepScreen(data: KeepScreenData): void {
665    Log.info(`${this.TAG} onKeepScreen E`);
666    if (data) {
667      GlobalContext.get()
668        .getCameraWinClass()
669        .setKeepScreenOn(data.isKeepScreenOn)
670        .then((v) => {
671          Log.info('Succeeded in setting the screen to be always on. Data: ' + JSON.stringify(v));
672        })
673        .catch((err: BusinessError) => {
674          Log.error('Failed to set the screen to be always on. Cause: ' + JSON.stringify(err));
675        });
676    }
677    Log.info(`${this.TAG} onKeepScreen X`);
678  }
679
680  private windowSizeChange(data: ScreenSizeType): void {
681    if (this.screenSize != data) {
682      this.screenSize = data;
683      this.resetScreenSize(data);
684    }
685  }
686
687  private resetScreenSize(size: ScreenSizeType): void {
688    this.settingManager.setScreenHeight(size.height);
689    this.settingManager.setScreenWidth(size.width);
690    let xComponentSize = this.settingManager.getPreviewDisplaySize(this.state.mode);
691    Log.info(this.TAG + " PreviewArea xComponentSize = " + JSON.stringify(xComponentSize));
692    this.mAction.changeXComponentSize(xComponentSize.width, xComponentSize.height);
693  }
694
695  private async onScreenChange(isScreenOn: boolean) {
696    Log.info(`${this.TAG} onScreenChanged E isScreenOn: ${isScreenOn}`);
697    if (!isScreenOn) {
698      GlobalContext.get().setObject('keepCameraZoomRatio', true);
699      if (this.state.isShowPageView) {
700        this.mAction.hideSettingView();
701      }
702    }
703    Log.info(`${this.TAG} onScreenChanged X`);
704  }
705
706  build() {
707    Column() {
708      if (this.state.isShowPreview) {
709        Stack() {
710          XComponent({
711            id: '',
712            type: 'surface',
713            libraryname: '',
714            controller: GlobalContext.get().getXComponentController()
715          })
716            .onLoad(() => {
717              Log.end(Log.X_COMPONENT_LIFE);
718              Log.info(`${this.TAG} XComponent_onLoad`);
719              let surfaceId: number = GlobalContext.get().getXComponentController().getXComponentSurfaceId();
720              this.mAction.prepareSurface(surfaceId);
721              this.doCameraAction();
722            })
723            .width(this.state.xComponentWidth)
724            .height(this.state.xComponentHeight)
725            .animation({
726              duration: 100,
727              curve: Curve.Sharp,
728              delay: 0,
729              iterations: 1,
730              playMode: PlayMode.Normal
731            })
732
733          if (this.isSwitchBackground) {
734            Column() {
735            }
736            .width(this.state.xComponentWidth)
737            .height(this.state.xComponentHeight)
738            .backgroundColor('#000')
739            .opacity(this.switchBackgroundOpacity)
740          }
741
742          if (this.btnSwitch) {
743            Image($r('app.media.whitePicture'))
744              .width(this.state.xComponentWidth)
745              .height(this.state.xComponentHeight)
746              .syncLoad(false)
747              .scale({ x: this.scaleX, y: 1.0 })
748              .rotate({ x: 0, y: 10, z: 0, angle: this.rotateAngle })// .opacity(this.state.btnOpacity_first)
749              .onComplete(() => { /* this.switchAnimation() */
750              })
751          }
752
753          if (this.btnSwitchSec) {
754            Image($r('app.media.whitePicture'))
755              .width(this.state.xComponentWidth)
756              .height(this.state.xComponentHeight)
757              .syncLoad(false)
758              .scale({ x: this.scaleX, y: 1.0 })
759              .rotate({ x: 0, y: 10, z: 0, angle: this.rotateAngleSec })// .opacity(this.state.btnOpacity_sec)
760              .onComplete(() => { /* this.switchAnimationSec() */
761              })
762          }
763
764          if (this.state.isShowFlashBlack) {
765            ShowFlashBlack();
766          }
767
768          if (this.state.isShowZoomText && deviceInfo.deviceType !== "default" && !this.state.isShowtimeLapse) {
769            Stack({ alignContent: Alignment.Top }) {
770              Column() {
771                Column() {
772                  ZoomText({ state: $state })
773                }
774                .width('100%')
775                .height('100%')
776              }
777              .width('100%')
778              .height('100%')
779              .alignItems(HorizontalAlign.Start)
780            }
781            .width('100%')
782            .height('96%')
783          }
784
785          if (this.state.isAssGridViewShow === '1' && this.state.mode !== 'MORE') {
786            AssistiveGridView();
787          }
788
789          if (this.state.isSmallVideoTimerVisible) {
790            Column() {
791              SmallVideoTimer();
792            }
793            .width('100%')
794            .height('100%')
795            .alignItems(HorizontalAlign.Start)
796          }
797          if (this.state.isBigVideoTimerVisible) {
798            Column() {
799              BigVideoTimer();
800            }
801            .width('100%')
802            .height('100%')
803            .alignItems(HorizontalAlign.Start)
804          }
805          if (this.state.isShowtimeLapse) {
806            Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
807              Column() {
808                TimeLapseView();
809              }.width('100%').height(150)
810            }.width('100%').height('100%')
811          }
812          if (this.state.showBlur) {
813            Column()
814              .width(this.isShowBlurSize.width)
815              .height(this.isShowBlurSize.height)
816              .backgroundColor(Color.Black)
817              .border({ width: { top: 0.5, bottom: 0.5 }, color: Color.Black })
818          }
819
820          Stack() {
821            if (this.state.isShowBigText) {
822              Stack({ alignContent: Alignment.BottomStart }) {
823                Column() {
824                  Column() {
825                    BigText()
826                  }
827                  .width('100%')
828                  .height('100%')
829                }
830                .width('100%')
831                .height('96vp')
832                .alignItems(HorizontalAlign.Start)
833              }
834              .width('100%')
835              .height('100%')
836            }
837          }
838          .width(this.screenSize.width > this.screenSize.height ? this.screenSize.height : this.screenSize.width)
839          .height(this.screenSize.height > (this.screenSize.width * 9 / 16) ? (this.screenSize.width * 9 / 16) :
840          this.screenSize.height)
841        }
842        .width('100%')
843        .height('100%')
844      }
845    }
846    .width(this.state.xComponentWidth)
847    .height(this.state.xComponentHeight)
848    .margin({ top: 0 })
849    .backgroundColor('#000')
850    .gesture(
851      GestureGroup(
852        GestureMode.Exclusive,
853        TapGesture({ fingers: 1, count: 1 })
854          .onAction(() => this.onPreviewClicked),
855        PinchGesture({ fingers: 2, distance: 1 })
856          .onActionStart(() => this.pinchGestureStart)
857          .onActionUpdate(() => this.pinchGestureUpdate)
858          .onActionEnd(() => this.pinchGestureEnd),
859        PanGesture({ fingers: 1, direction: PanDirection.Up, distance: 10 })
860          .onActionEnd(() => {
861            if (!this.state.isThirdPartyCall && !this.state.isFaCall) {
862              this.swipeChangeMode(1);
863            }
864          }),
865        PanGesture({ fingers: 1, direction: PanDirection.Down, distance: 10 })
866          .onActionEnd(() => {
867            if (!this.state.isThirdPartyCall && !this.state.isFaCall) {
868              this.swipeChangeMode(-1);
869            }
870          })
871      )
872    )
873  }
874}