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 */ 15import prompt from '@ohos.prompt' 16import Logger from '../model/Logger' 17import CameraService from '../model/CameraService' 18import TitleBar from '../view/TitleBar' 19 20const CameraMode = { 21 MODE_PHOTO: 0, // 拍照模式 22 MODE_VIDEO: 1 // 录像模式 23} 24 25@Entry 26@Component 27struct CameraPage { 28 private tag: string = 'CameraPage' 29 private mXComponentController: XComponentController = new XComponentController() 30 private surfaceId: number = -1 31 private cameraService: CameraService = new CameraService(getContext(this)) 32 @State imgThumbnail: string = '' 33 @State videoThumbnail: Resource | undefined = undefined 34 @State curModel: number = CameraMode.MODE_PHOTO 35 @State isRecording: boolean = false 36 37 aboutToAppear() { 38 this.surfaceId = this.mXComponentController.getXComponentSurfaceId() 39 Logger.info(this.tag, `aboutToAppear,surfaceId=${this.surfaceId}`) 40 this.cameraService.setTakePictureCallback(this.handleTakePicture.bind(this)) 41 } 42 43 getCameraIcon() { 44 if (this.curModel === CameraMode.MODE_PHOTO) { 45 return $r('app.media.take_photo_normal') 46 } else { 47 if (this.isRecording) { 48 return $r('app.media.take_video_stop') 49 } else { 50 return $r('app.media.take_video_normal') 51 } 52 } 53 } 54 55 refreshVideoState() { 56 if (this.isRecording) { 57 Logger.info(this.tag, 'stopVideo begin') 58 this.cameraService.stopVideo() 59 this.isRecording = false 60 this.videoThumbnail = $r('app.media.video_poster') 61 } else { 62 Logger.info(this.tag, 'startVideo begin') 63 this.cameraService.startVideo() 64 this.isRecording = true 65 } 66 } 67 68 handleTakePicture = (thumbnail: string) => { 69 this.imgThumbnail = thumbnail 70 Logger.info(this.tag, `takePicture end , thumbnail: ${this.imgThumbnail}`) 71 } 72 73 build() { 74 Column() { 75 TitleBar() 76 Stack({ alignContent: Alignment.Bottom }) { 77 XComponent({ 78 id: 'componentId', 79 type: 'surface', 80 controller: this.mXComponentController 81 }) 82 .onLoad(() => { 83 Logger.info(this.tag, 'onLoad is called') 84 this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 }) 85 this.surfaceId = this.mXComponentController.getXComponentSurfaceId() 86 Logger.info(this.tag, `onLoad surfaceId: ${this.surfaceId}`) 87 this.curModel = CameraMode.MODE_PHOTO 88 this.cameraService.initCamera(this.surfaceId) 89 }) 90 .height('100%') 91 .width('100%') 92 .margin({ bottom: 130 }) 93 Column() { 94 Row() { 95 Text($r('app.string.photo')) 96 .fontColor(this.curModel === CameraMode.MODE_PHOTO ? Color.White : Color.Gray) 97 .fontSize(25) 98 .onClick(() => { 99 if (this.curModel === CameraMode.MODE_VIDEO) { 100 prompt.showToast({ message: '切换中...', duration: 1000 }) 101 if (this.isRecording) { 102 this.cameraService.stopVideo() 103 this.isRecording = false 104 } 105 this.curModel = CameraMode.MODE_PHOTO 106 setTimeout(() => { 107 this.cameraService.initCamera(this.surfaceId) 108 }, 500) 109 this.videoThumbnail = undefined 110 } 111 }) 112 Text($r('app.string.video')) 113 .fontColor(this.curModel === CameraMode.MODE_VIDEO ? Color.White : Color.Gray) 114 .fontSize(25) 115 .margin({ left: 30 }) 116 .onClick(() => { 117 if (this.curModel === CameraMode.MODE_PHOTO) { 118 prompt.showToast({ message: '切换中...', duration: 1000 }) 119 this.curModel = CameraMode.MODE_VIDEO 120 this.cameraService.initCamera(this.surfaceId) 121 } 122 }) 123 } 124 .size({ height: 40, width: '100%' }) 125 .margin({ left: 50 }) 126 .justifyContent(FlexAlign.Center) 127 128 Row() { 129 if (this.curModel === CameraMode.MODE_VIDEO) { 130 Image(this.videoThumbnail) 131 .size({ width: 70, height: 70 }) 132 .aspectRatio(1) 133 .borderRadius(40) 134 .objectFit(ImageFit.Fill) 135 .backgroundColor(Color.Gray) 136 } else { 137 Image(this.imgThumbnail) 138 .size({ width: 70, height: 70 }) 139 .aspectRatio(1) 140 .borderRadius(40) 141 .objectFit(ImageFit.Fill) 142 .backgroundColor(Color.Gray) 143 } 144 145 Image(this.getCameraIcon()) 146 .size({ width: 70, height: 70 }) 147 .margin({ left: 50 }) 148 .key('photo') 149 .onClick(() => { 150 if (this.curModel === CameraMode.MODE_PHOTO) { 151 Logger.info(this.tag, 'takePicture begin') 152 prompt.showToast({ message: '拍照中...', duration: 1000 }) 153 this.cameraService.takePicture() 154 } else if (this.curModel === CameraMode.MODE_VIDEO) { 155 this.refreshVideoState() 156 } 157 }) 158 } 159 .size({ height: 80, width: '100%' }) 160 .margin({ right: 50 }) 161 .justifyContent(FlexAlign.Center) 162 } 163 .size({ height: 130, width: '100%' }) 164 .padding({ bottom: 10 }) 165 .backgroundColor(Color.Black) 166 } 167 .width('100%') 168 .height('100%') 169 .layoutWeight(1) 170 .backgroundColor(Color.Grey) 171 } 172 .width('100%') 173 .height('100%') 174 } 175 176 async aboutToDisappear() { 177 if (this.isRecording) { 178 await this.cameraService.stopVideo() 179 } 180 await this.cameraService.releaseCamera() 181 } 182}