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