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