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}