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 display from '@ohos.display'; 17import deviceInfo from '@ohos.deviceInfo'; 18import { ModeMap } from '../common/ModeMap'; 19import { Action } from '@ohos/common/src/main/ets/default/redux/actions/Action'; 20import { CameraWorker } from '@ohos/common/src/main/ets/default/worker/CameraWorker'; 21import { EventBus } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBus'; 22import { EventBusManager } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBusManager'; 23import { Dispatch, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store'; 24import { getStore } from '@ohos/common/src/main/ets/default/redux/store'; 25import { Log } from '@ohos/common/src/main/ets/default/utils/Log'; 26import { MoreList } from '@ohos/common/src/main/ets/default/featurecommon/moreList/moreList'; 27import { 28 PersistType, 29 PreferencesService 30} from '@ohos/common/src/main/ets/default/featurecommon/preferences/PreferencesService'; 31import { RdbStoreManager } from '@ohos/common/src/main/ets/default/setting/storage/RdbStoreManager'; 32import { TabBar } from '@ohos/common/src/main/ets/default/featurecommon/tabbar/TabBar'; 33import { ZoomView } from '@ohos/common/src/main/ets/default/featurecommon/zoomview/ZoomView'; 34import { Control } from './Control'; 35import { FootBar } from './FootBar'; 36import { PreviewArea } from './PreviewArea'; 37import { SettingView } from './SettingView'; 38import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; 39import { CameraId } from '@ohos/common/src/main/ets/default/setting/settingitem/CameraId'; 40import { BusinessError } from '@ohos.base'; 41import ability from '@ohos.ability.ability'; 42import { GlobalContext } from '@ohos/common/src/main/ets/default/utils/GlobalContext'; 43 44CameraWorker.getInstance(new ModeMap()); 45 46PersistentStorage.PersistProp('storageCameraId', ''); 47 48class StateStruct { 49 footBarHeight: number = 0; 50 permissionFlag: boolean = false; 51 mode: string = ''; 52 curMode: string = ''; 53 isShowtimeLapse: boolean = false; 54 videoState: string = ''; 55 isShowMoreList: boolean = false; 56 isThirdPartyCall: boolean = false; 57 showZoomLabelValue: boolean = true; 58 isShowPinch: boolean = false; 59 isShowPageView: boolean = false; 60 isInitiated: boolean = false; 61 curCameraPosition: CameraId = CameraId.BACK 62} 63 64class IndexDispatcher { 65 private mDispatch: Dispatch = (data) => data; 66 67 public setDispatch(dispatch: Dispatch) { 68 this.mDispatch = dispatch; 69 } 70 71 public initFootBarHeight(footBarHeight: number): void { 72 this.mDispatch(Action.initFootBarHeight(footBarHeight)); 73 } 74 75 public setPermissionFlag(permissionFlag: boolean): void { 76 Log.info(`CameraApp setPermissionFlag: ${permissionFlag}`); 77 this.mDispatch(Action.setPermissionFlag(permissionFlag)); 78 } 79 80 public initAction(action: string): void { 81 this.mDispatch(Action.initAction(action)); 82 } 83 84 public initCameraPosition(cameraPosition: string): void { 85 this.mDispatch(Action.setCameraPosition(cameraPosition)); 86 } 87 88 public initMode(mode: string): void { 89 this.mDispatch(Action.initMode(mode)); 90 } 91 92 public changeTimeLapse(isShowtimeLapse: boolean): void { 93 this.mDispatch(Action.changeTimeLapse(isShowtimeLapse)); 94 } 95 96 public stopRecording(): void { 97 this.mDispatch(Action.stopRecording()); 98 this.mDispatch(Action.updateVideoState('beforeTakeVideo')); 99 this.mDispatch(Action.updateBigVideoTimerVisible(false)); 100 this.mDispatch(Action.updateSmallVideoTimerVisible(false)); 101 } 102 103 public resetRecordingTime(): void { 104 this.mDispatch(Action.updateRecordingTime(0)); 105 this.mDispatch(Action.updateRecordingTimeDisplay('00:00')); 106 } 107 108 public hideSettingView(): void { 109 this.mDispatch(Action.showSettingView(false)); 110 } 111 112 public updateModeIndex(index: number): void { 113 this.mDispatch(Action.updateModeIndex(index)); 114 } 115 116 public faCall(isFaCall: boolean): void { 117 this.mDispatch(Action.faCall(isFaCall)); 118 } 119} 120 121const ZOOM_HEIGHT = 140; 122 123@Entry 124@Component 125struct Index { 126 appEventBus: EventBus = EventBusManager.getInstance().getEventBus(); 127 @State state: StateStruct = new StateStruct(); 128 protected mPreferencesService: PreferencesService = PreferencesService.getInstance(); 129 private TAG: string = '[Index]:'; 130 private modeArray: Array<string> = ['PHOTO', 'VIDEO']; 131 private mAction: IndexDispatcher = new IndexDispatcher(); 132 133 aboutToAppear(): void { 134 Log.info(`${this.TAG} aboutToAppear E`); 135 let dbStore: RdbStoreManager = RdbStoreManager.getInstance(); 136 dbStore.initRdbConfig(); 137 getStore().subscribe((state: OhCombinedState) => { 138 this.state = { 139 footBarHeight: state.contextReducer.footBarHeight, 140 permissionFlag: state.contextReducer.permissionFlag, 141 mode: state.modeReducer.mode, 142 curMode: state.modeReducer.curMode, 143 isShowtimeLapse: state.settingReducer.isShowtimeLapse, 144 videoState: state.recordReducer.videoState, 145 isShowMoreList: state.modeReducer.isShowMoreList, 146 isThirdPartyCall: state.contextReducer.isThirdPartyCall, 147 showZoomLabelValue: state.zoomReducer.showZoomLabelValue, 148 isShowPinch: state.zoomReducer.isShowPinch, 149 isShowPageView: state.settingReducer.isShowSettingView, 150 isInitiated: state.modeReducer.isInitiated, 151 curCameraPosition: state.cameraReducer.curCameraPosition, 152 }; 153 }, (dispatch: Dispatch) => { 154 this.mAction.setDispatch(dispatch); 155 }) 156 display.getDefaultDisplay().then((dis) => { 157 Log.info(`${this.TAG} dis data = ${JSON.stringify(dis)}`); 158 let footBarHeight: number = 0; 159 if (deviceInfo.deviceType === "default") { 160 footBarHeight = px2vp(dis.width) * (4 / 3) - 160; 161 } else { 162 footBarHeight = px2vp(dis.width) * (4 / 3) - 82; 163 } 164 this.mAction.initFootBarHeight(footBarHeight); 165 }) 166 167 if (!this.state.permissionFlag) { 168 let permissionList: Array<Permissions> = [ 169 "ohos.permission.MEDIA_LOCATION", 170 "ohos.permission.READ_IMAGEVIDEO", 171 "ohos.permission.WRITE_IMAGEVIDEO", 172 "ohos.permission.CAMERA", 173 "ohos.permission.MICROPHONE", 174 "ohos.permission.DISTRIBUTED_DATASYNC", 175 "ohos.permission.LOCATION", 176 "ohos.permission.LOCATION_IN_BACKGROUND", 177 "ohos.permission.APPROXIMATELY_LOCATION" 178 ]; 179 Log.info(`${this.TAG} permissions need to require from user: ${JSON.stringify(permissionList)}`); 180 let atManager = abilityAccessCtrl.createAtManager(); 181 try { 182 atManager.requestPermissionsFromUser(GlobalContext.get().getCameraAbilityContext(), permissionList).then((data) => { 183 Log.info(`${this.TAG} data permissions: ${JSON.stringify(data.permissions)}`); 184 Log.info(`${this.TAG} data authResult: ${JSON.stringify(data.authResults)}`); 185 let sum = 0 186 for (let i = 0; i < data.authResults.length; i++) { 187 sum += data.authResults[i]; 188 } 189 if (sum >= 0) { 190 GlobalContext.get().setObject('permissionFlag', true); 191 this.mAction.setPermissionFlag(true); 192 } else { 193 GlobalContext.get().setObject('permissionFlag', false); 194 this.mAction.setPermissionFlag(false); 195 } 196 Log.info(`${this.TAG} request permissions result: ${GlobalContext.get().getT<boolean>('permissionFlag')}`); 197 }, (err: BusinessError) => { 198 Log.error(`${this.TAG} Failed to start ability err code: ${err.code}`); 199 }) 200 } catch (error) { 201 Log.info(`${this.TAG} catch error: ${JSON.stringify(error)}`); 202 } 203 } 204 205 if (GlobalContext.get().getCameraFormParam() != undefined) { 206 this.mAction.initAction(GlobalContext.get().getCameraFormParam().action); 207 this.mAction.initMode(GlobalContext.get().getCameraFormParam().mode); 208 GlobalContext.get().setCameraFormParam(undefined); 209 } 210 211 GlobalContext.get().setObject('stopCameraRecording', () => { 212 this.stopCameraRecording(); 213 }) 214 215 if (!this.state.isInitiated) { 216 let initIndex: number = this.mPreferencesService.getModeValue(PersistType.FOR_AWHILE, 0); 217 Log.info(`${this.TAG} initModeIndex: ${initIndex}`); 218 this.mAction.initMode(this.modeArray[initIndex]); 219 this.mAction.updateModeIndex(initIndex); 220 } 221 222 Log.info(`${this.TAG} aboutToAppear X`); 223 } 224 225 onPageShow(): void { 226 Log.info(`${this.TAG} onPageShow this.permissionFlag: ${this.state.permissionFlag} permissionFlag: ${GlobalContext.get().getT<boolean>('permissionFlag')}`); 227 this.mAction.setPermissionFlag(GlobalContext.get().getT<boolean>('permissionFlag')); 228 let curCameraId = AppStorage.Get<string>('storageCameraId'); 229 if (curCameraId) this.mAction.initCameraPosition(curCameraId); 230 this.mAction.resetRecordingTime(); 231 Log.info(`${this.TAG} onPageShow X`); 232 } 233 234 aboutToDisappear(): void { 235 Log.info(`${this.TAG} aboutToDisappear E`); 236 } 237 238 onBackPress(): boolean { 239 Log.info(`${this.TAG} onBackPress E`); 240 if (this.state.isShowPageView) { 241 this.mAction.hideSettingView(); 242 return true; 243 } else if (this.state.isShowtimeLapse) { 244 this.mAction.changeTimeLapse(false); 245 return true 246 } else if (this.state.isThirdPartyCall) { 247 let that = this; 248 that.terminateSelfWithResult(); 249 } else { 250 if (this.state.videoState === 'startTakeVideo' || this.state.videoState === 'pauseTakeVideo') { 251 this.mAction.stopRecording(); 252 return true; 253 } 254 Log.info(`${this.TAG} onBackPress X`); 255 return false; 256 } 257 return false; 258 } 259 260 onPageHide(): void { 261 Log.info(`${this.TAG} onPageHide E`); 262 this.stopCameraRecording(); 263 Log.info(`${this.TAG} onPageHide X`); 264 } 265 266 public stopCameraRecording() { 267 Log.info(`${this.TAG} stopCameraRecording E`); 268 if (this.state.isShowtimeLapse) { 269 this.mAction.changeTimeLapse(false); 270 } 271 if (this.state.videoState === 'startTakeVideo' || this.state.videoState === 'pauseTakeVideo') { 272 this.mAction.stopRecording(); 273 } 274 Log.info(`${this.TAG} stopCameraRecording X`); 275 } 276 277 terminateSelfWithResult() { 278 Log.info(`${this.TAG} terminateSelfWithResult start`); 279 let abilityResult: ability.AbilityResult = { 280 resultCode: -1, 281 want: { 282 parameters: { 283 resourceUri: '', 284 mode: this.state.mode 285 } 286 } 287 }; 288 Log.info(`${this.TAG} terminateSelfWithResult start1`); 289 if (GlobalContext.get().getSession()) { 290 Log.info(`${this.TAG} terminateSelfWithResult start2`); 291 GlobalContext.get().getSession().terminateSelfWithResult(abilityResult, (error: BusinessError) => { 292 if (error) { 293 Log.error(`${this.TAG} Operation failed. Cause: ${error?.code}`); 294 return; 295 } 296 Log.info(`${this.TAG} Operation succeeded`); 297 }); 298 } else { 299 GlobalContext.get().getCameraAbilityContext().terminateSelfWithResult(abilityResult, (error: BusinessError) => { 300 if (error) { 301 Log.error(`${this.TAG} Operation failed. Cause: ${error}`); 302 return; 303 } 304 Log.info(`${this.TAG} Operation succeeded`); 305 }); 306 } 307 } 308 309 build() { 310 Stack({ alignContent: Alignment.Top }) { 311 Stack() { 312 PreviewArea() 313 }.width('100%').position({ y: 48 }) 314 315 Stack() { 316 if (deviceInfo.deviceType !== "default" && this.state.videoState === "beforeTakeVideo" && !this.state.isShowtimeLapse && this.state.showZoomLabelValue) { 317 TabBar({ onBackClicked: () => this.onBackClicked() }); 318 } 319 }.width('100%').height(48).position({ x: '0', y: '0' }) 320 321 if (this.state.isShowMoreList && this.state.showZoomLabelValue) { 322 MoreList() 323 } 324 Stack({ alignContent: Alignment.Bottom }) { 325 Column() { 326 if (this.state.mode === "PHOTO" || this.state.mode === "VIDEO") { 327 if (deviceInfo.deviceType !== "default" && this.state.curCameraPosition !== 'FRONT') { 328 Column() { 329 ZoomView() 330 } 331 .visibility(!this.state.isShowtimeLapse && !this.state.isShowPinch ? Visibility.Visible : Visibility.Hidden) 332 } 333 } 334 if (this.state.videoState === "beforeTakeVideo" && this.state.showZoomLabelValue) { 335 Column() { 336 Control() 337 } 338 .visibility((!this.state.isShowtimeLapse && this.state.showZoomLabelValue) ? Visibility.Visible : Visibility.Hidden) 339 .width('100%') 340 .offset({ 341 x: 156, y: 0 342 }) 343 } 344 Column() { 345 FootBar() 346 } 347 .visibility((!this.state.isShowtimeLapse && this.state.showZoomLabelValue) ? Visibility.Visible : Visibility.Hidden) 348 } 349 }.width('100%').height(302 - ZOOM_HEIGHT).position({ y: this.state.footBarHeight + ZOOM_HEIGHT }) 350 .visibility(!this.state.isShowtimeLapse ? Visibility.Visible : Visibility.Hidden) 351 352 if (this.state.isShowPageView) { 353 SettingView().width('100%').height('100%') 354 } 355 }.width('100%').height('100%').backgroundColor('#000') 356 } 357 358 private onBackClicked(): void { 359 Log.info(`${this.TAG} onBackClicked E`); 360 let that = this; 361 that.terminateSelfWithResult(); 362 } 363}