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