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" 17 18import { Log } from '../../utils/Log' 19import getStore from '../../redux/store' 20import { Action } from '../../redux/actions/Action' 21import { EventBus } from '../../worker/eventbus/EventBus' 22import EventBusManager from '../../worker/eventbus/EventBusManager' 23import { SettingManager } from '../../setting/SettingManager' 24import Timer from '../../setting/settingitem/Timer' 25 26let localState = (state) => { 27 return { 28 uiEnable: state.ContextReducer.uiEnable, 29 shutterIcon: state.CameraReducer.shutterIcon, 30 captureBtnScale: state.CaptureReducer.captureBtnScale, 31 videoState: state.RecordReducer.videoState, 32 mode: state.ModeReducer.mode, 33 videoUri: state.CameraInitReducer.videoUri, 34 resourceUri: state.CameraInitReducer.resourceUri, 35 isThirdPartyCall: state.ContextReducer.isThirdPartyCall, 36 xComponentWidth: state.PreviewReducer.xComponentWidth, 37 xComponentHeight: state.PreviewReducer.xComponentHeight, 38 } 39} 40 41let localDispatcher = (dispatch) => { 42 return { 43 updateSmallVideoTimerVisible: (visible: boolean) => { 44 dispatch(Action.updateSmallVideoTimerVisible(visible)) 45 }, 46 updateShutterIcon: (icon: Resource) => { 47 dispatch(Action.updateShutterIcon(icon)) 48 }, 49 capture: () => { 50 dispatch(Action.updateShowFlashBlackFlag(true)) 51 dispatch(Action.capture()) 52 }, 53 startRecording: () => { 54 dispatch(Action.startRecording()) 55 dispatch(Action.updateVideoState('startTakeVideo')) 56 dispatch(Action.updateBigVideoTimerVisible(true)) 57 dispatch(Action.updateScreenStatus(true)) 58 }, 59 pauseRecording: () => { 60 dispatch(Action.pauseRecording()) 61 dispatch(Action.updateVideoState('pauseTakeVideo')) 62 }, 63 resumeRecording: () => { 64 dispatch(Action.resumeRecording()) 65 dispatch(Action.updateVideoState('startTakeVideo')) 66 }, 67 stopRecording: () => { 68 dispatch(Action.stopRecording()) 69 dispatch(Action.updateVideoState('beforeTakeVideo')) 70 dispatch(Action.updateBigVideoTimerVisible(false)) 71 dispatch(Action.updateSmallVideoTimerVisible(false)) 72 dispatch(Action.updateScreenStatus(false)) 73 }, 74 changeTimeLapse: (isShowtimeLapse: boolean) => { 75 dispatch(Action.changeTimeLapse(isShowtimeLapse)) 76 } 77 } 78} 79 80@Component 81export struct ShutterButton { 82 private TAG: string = '[ShutterButton]:' 83 private appEventBus: EventBus = EventBusManager.getInstance().getEventBus() 84 private settingManager = SettingManager.getInstance() 85 86 type: ButtonType 87 stateEffect: boolean 88 89 @State state: any = {} 90 @State captureBtnScale: number = 1 91 92 aboutToAppear() { 93 Log.debug(`${this.TAG} aboutToAppear E`) 94 getStore().connect(localState, localDispatcher)(this.state) 95 this.appEventBus.on(Action.ACTION_CHANGE_MODE, this.changeShutterIcon.bind(this)) 96 this.appEventBus.on(Action.ACTION_UPDATE_THUMBNAIL, this.onThumbnailUpdate.bind(this)) 97 this.appEventBus.on(Action.ACTION_INIT_MODE, this.changeShutterIcon.bind(this)) 98 this.refreshIcon(this.state.mode) 99 Log.debug(`${this.TAG} aboutToAppear X`) 100 } 101 102 aboutToDisappear(): void { 103 Log.debug(`${this.TAG} aboutToDisappear E`) 104 this.appEventBus.off(Action.ACTION_CHANGE_MODE, this.changeShutterIcon.bind(this)) 105 this.appEventBus.off(Action.ACTION_UPDATE_THUMBNAIL, this.onThumbnailUpdate.bind(this)) 106 Log.debug(`${this.TAG} aboutToDisappear X`) 107 } 108 109 private async onThumbnailUpdate(data) { 110 Log.info(`${this.TAG} onThumbnailUpdate data: ${JSON.stringify(data)} E`) 111 Log.info(`${this.TAG} onThumbnailUpdate resourceUri= ${JSON.stringify(this.state.resourceUri)} E`) 112 Log.info(`${this.TAG} onThumbnailUpdate isThirdPartyCall= ${this.state.isThirdPartyCall} E`) 113 Log.info(`${this.TAG} onThumbnailUpdate videoUri= ${this.state.videoUri} E`) 114 if (this.state.isThirdPartyCall) { 115 Log.info(`${this.TAG} onThumbnailUpdate start router to ThirdPreviewView`) 116 router.push({ 117 uri: "pages/ThirdPreviewView", 118 params: { 119 width: this.state.xComponentWidth, 120 height: this.state.xComponentHeight, 121 mode: this.state.mode, 122 uri: this.state.resourceUri, 123 videoUri: this.state.videoUri, 124 callBundleName:globalThis.cameraAbilityWant?.parameters?.callBundleName 125 } 126 }) 127 } 128 Log.info(`${this.TAG} onThumbnailUpdate this.state.thumbnail: ${JSON.stringify(this.state.thumbnail)} X`) 129 } 130 131 private async changeShutterIcon(data) { 132 Log.debug(`${this.TAG} resetShutterIcon E`) 133 this.refreshIcon(data.mode) 134 Log.debug(`${this.TAG} resetShutterIcon X`) 135 } 136 137 private async refreshIcon(mode: string) { 138 Log.debug(`${this.TAG} refreshIcon E`) 139 if (mode === 'PHOTO') { 140 this.state.updateShutterIcon($r('app.media.ic_circled_filled')) 141 } else if (mode === 'VIDEO') { 142 this.state.updateShutterIcon($r('app.media.take_video_normal')) 143 } else { 144 this.state.updateShutterIcon($r('app.media.ic_circled_filled')) 145 } 146 Log.debug(`${this.TAG} refreshIcon X`) 147 } 148 149 build() { 150 if (this.state.videoState === 'beforeTakeVideo') { 151 Stack({ alignContent: Alignment.Center }) { 152 if (this.state.mode === 'VIDEO') { 153 Image(this.state.shutterIcon) 154 .width(76).aspectRatio(1).enabled(this.state.uiEnable) 155 .onTouch((event: TouchEvent) => { 156 if (event.type === TouchType.Up) { 157 let timerLapse = this.settingManager.getTimeLapse() 158 Log.log(`${this.TAG} ShutterButton startRecording getValue= ${JSON.stringify(timerLapse)}`) 159 if (timerLapse && timerLapse.id !== Timer.RESOURCE_OFF.id) { 160 Log.log('ShutterButton startRecording changeTimeLapse called') 161 this.state.changeTimeLapse(true) 162 } else { 163 Log.log('ShutterButton startRecording changeTimeLapse not called') 164 this.state.startRecording() 165 } 166 } 167 }) 168 } else { 169 Image($r('app.media.ic_circled')).fillColor(Color.White) 170 Image(this.state.shutterIcon).width(54).aspectRatio(1).fillColor(Color.White) 171 .scale({ x: this.captureBtnScale, y: this.captureBtnScale, z: this.captureBtnScale }) 172 .enabled(this.state.uiEnable) 173 .onTouch((event: TouchEvent) => { 174 if (event.type === TouchType.Down) { 175 animateTo( 176 { duration: 125, curve: Curve.Sharp, delay: 0 }, 177 () => { this.captureBtnScale = 0.85 }) 178 } else if (event.type === TouchType.Up) { 179 animateTo( 180 { duration: 125, curve: Curve.Sharp, delay: 0, 181 onFinish: () => { this.captureBtnScale = 1 }}, 182 () => { this.captureBtnScale = 1 }) 183 let timerLapse = this.settingManager.getTimeLapse() 184 Log.log(`${this.TAG} ShutterButton startRecording getValue= ${JSON.stringify(timerLapse)}`) 185 if (timerLapse && timerLapse.id !== Timer.RESOURCE_OFF.id) { 186 Log.log('ShutterButton startRecording changeTimeLapse called') 187 this.state.changeTimeLapse(true) 188 } else { 189 Log.log('ShutterButton startRecording changeTimeLapse not called') 190 this.state.capture() 191 } 192 } 193 }) 194 } 195 }.width(76).aspectRatio(1).margin({ left: 48, right: 48 }) 196 } else { 197 Column() { 198 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 199 Column() { 200 Image($r('app.media.ic_video_end')) 201 .width(20) 202 .aspectRatio(1) 203 .fillColor(Color.White) 204 .enabled(this.state.uiEnable) 205 } 206 .width(40) 207 .padding({ left: 10, right: 10 }) 208 .margin({ right: 6 }) 209 .enabled(this.state.uiEnable) 210 .onClick(() => { 211 this.state.stopRecording() 212 }) 213 214 Column() { 215 if (this.state.videoState === 'startTakeVideo') { 216 Image($r('app.media.ic_video_recording')) 217 .width(20).aspectRatio(1).fillColor(Color.White) 218 .enabled(this.state.uiEnable) 219 } else if (this.state.videoState === 'pauseTakeVideo') { 220 Image($r('app.media.ic_video_pause')).width(20).aspectRatio(1).fillColor(Color.Red) 221 .enabled(this.state.uiEnable) 222 } 223 } 224 .width(40) 225 .padding({ left: 10, right: 10 }) 226 .margin({ left: 6 }) 227 .enabled(this.state.uiEnable) 228 .onClick(() => { 229 this.state.videoState === 'startTakeVideo' ? this.state.pauseRecording() : this.state.resumeRecording() 230 }) 231 }.width('100%').height('100%') 232 } 233 .width(120).height(56).borderRadius(28) 234 .border({ width: 1, color: Color.White, style: BorderStyle.Solid }) 235 .margin({ left: 24, right: 24 }) 236 } 237 } 238}