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