• 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 { 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
80class StateStruct {
81  uiEnable
82  shutterIcon
83  captureBtnScale
84  videoState
85  mode
86  resourceUri
87  videoUri
88  thumbnail
89  isThirdPartyCall
90  xComponentWidth
91  xComponentHeight
92  updateSmallVideoTimerVisible : Function
93  updateShutterIcon : Function
94  capture : Function
95  startRecording : Function
96  pauseRecording : Function
97  resumeRecording : Function
98  stopRecording : Function
99  changeTimeLapse : Function
100}
101
102@Component
103export struct ShutterButton {
104  private TAG: string = '[ShutterButton]:'
105  private appEventBus: EventBus = EventBusManager.getInstance().getEventBus()
106  private settingManager = SettingManager.getInstance()
107
108  type: ButtonType
109  stateEffect: boolean
110
111  @State state: StateStruct = new StateStruct()
112  @State captureBtnScale: number = 1
113
114  aboutToAppear() {
115    Log.debug(`${this.TAG} aboutToAppear E`)
116    getStore().connect(localState, localDispatcher)(this.state)
117    this.appEventBus.on(Action.ACTION_CHANGE_MODE, this.changeShutterIcon.bind(this))
118    this.appEventBus.on(Action.ACTION_UPDATE_THUMBNAIL, this.onThumbnailUpdate.bind(this))
119    this.appEventBus.on(Action.ACTION_INIT_MODE, this.changeShutterIcon.bind(this))
120    this.refreshIcon(this.state.mode)
121    Log.debug(`${this.TAG} aboutToAppear X`)
122  }
123
124  aboutToDisappear(): void {
125    Log.debug(`${this.TAG} aboutToDisappear E`)
126    this.appEventBus.off(Action.ACTION_CHANGE_MODE, this.changeShutterIcon.bind(this))
127    this.appEventBus.off(Action.ACTION_UPDATE_THUMBNAIL, this.onThumbnailUpdate.bind(this))
128    Log.debug(`${this.TAG} aboutToDisappear X`)
129  }
130
131  private async onThumbnailUpdate(data) {
132    Log.info(`${this.TAG} onThumbnailUpdate data: ${JSON.stringify(data)} E`)
133    Log.info(`${this.TAG} onThumbnailUpdate resourceUri= ${JSON.stringify(this.state.resourceUri)} E`)
134    Log.info(`${this.TAG} onThumbnailUpdate isThirdPartyCall= ${this.state.isThirdPartyCall} E`)
135    Log.info(`${this.TAG} onThumbnailUpdate videoUri= ${this.state.videoUri} E`)
136    if (this.state.isThirdPartyCall) {
137      Log.info(`${this.TAG} onThumbnailUpdate start router to ThirdPreviewView`)
138      router.push({
139        uri: "pages/ThirdPreviewView",
140        params: {
141          width: this.state.xComponentWidth,
142          height: this.state.xComponentHeight,
143          mode: this.state.mode,
144          uri: this.state.resourceUri,
145          videoUri: this.state.videoUri,
146          callBundleName:globalThis.cameraAbilityWant?.parameters?.callBundleName
147        }
148      })
149    }
150    Log.info(`${this.TAG} onThumbnailUpdate this.state.thumbnail: ${JSON.stringify(this.state.thumbnail)} X`)
151  }
152
153  private async changeShutterIcon(data) {
154    Log.debug(`${this.TAG} resetShutterIcon E`)
155    this.refreshIcon(data.mode)
156    Log.debug(`${this.TAG} resetShutterIcon X`)
157  }
158
159  private async refreshIcon(mode: string) {
160    Log.debug(`${this.TAG} refreshIcon E`)
161    if (mode === 'PHOTO') {
162      this.state.updateShutterIcon($r('app.media.ic_circled_filled'))
163    } else if (mode === 'VIDEO') {
164      this.state.updateShutterIcon($r('app.media.take_video_normal'))
165    } else {
166      this.state.updateShutterIcon($r('app.media.ic_circled_filled'))
167    }
168    Log.debug(`${this.TAG} refreshIcon X`)
169  }
170
171  build() {
172    if (this.state.videoState === 'beforeTakeVideo') {
173      Stack({ alignContent: Alignment.Center }) {
174        if (this.state.mode === 'VIDEO') {
175          Image(this.state.shutterIcon)
176            .width(76).aspectRatio(1).enabled(this.state.uiEnable)
177            .onTouch((event: TouchEvent) => {
178              if (event.type === TouchType.Up) {
179                let timerLapse = this.settingManager.getTimeLapse()
180                Log.log(`${this.TAG} ShutterButton startRecording getValue= ${JSON.stringify(timerLapse)}`)
181                if (timerLapse && timerLapse.id !== Timer.RESOURCE_OFF.id) {
182                  Log.log('ShutterButton startRecording changeTimeLapse called')
183                  this.state.changeTimeLapse(true)
184                } else {
185                  Log.log('ShutterButton startRecording changeTimeLapse not called')
186                  this.state.startRecording()
187                }
188              }
189            })
190        } else {
191          Image($r('app.media.ic_circled')).fillColor(Color.White)
192          Image(this.state.shutterIcon).width(54).aspectRatio(1).fillColor(Color.White)
193            .scale({ x: this.captureBtnScale, y: this.captureBtnScale, z: this.captureBtnScale })
194            .enabled(this.state.uiEnable)
195            .onTouch((event: TouchEvent) => {
196              if (event.type === TouchType.Down) {
197                animateTo(
198                  { duration: 125, curve: Curve.Sharp, delay: 0 },
199                  () => { this.captureBtnScale = 0.85 })
200              } else if (event.type === TouchType.Up) {
201                animateTo(
202                  { duration: 125, curve: Curve.Sharp, delay: 0,
203                    onFinish: () => { this.captureBtnScale = 1 }},
204                  () => { this.captureBtnScale = 1 })
205                let timerLapse = this.settingManager.getTimeLapse()
206                Log.log(`${this.TAG} ShutterButton startRecording getValue= ${JSON.stringify(timerLapse)}`)
207                if (timerLapse && timerLapse.id !== Timer.RESOURCE_OFF.id) {
208                  Log.log('ShutterButton startRecording changeTimeLapse called')
209                  this.state.changeTimeLapse(true)
210                } else {
211                  Log.log('ShutterButton startRecording changeTimeLapse not called')
212                  this.state.capture()
213                }
214              }
215            })
216        }
217      }.width(76).aspectRatio(1).margin({ left: 48, right: 48 })
218    } else {
219      Column() {
220        Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
221          Column() {
222            Image($r('app.media.ic_video_end'))
223              .width(20)
224              .aspectRatio(1)
225              .fillColor(Color.White)
226              .enabled(this.state.uiEnable)
227          }
228          .width(40)
229          .padding({ left: 10, right: 10 })
230          .margin({ right: 6 })
231          .enabled(this.state.uiEnable)
232          .onClick(() => {
233            this.state.stopRecording()
234          })
235
236          Column() {
237            if (this.state.videoState === 'startTakeVideo') {
238              Image($r('app.media.ic_video_recording'))
239                .width(20).aspectRatio(1).fillColor(Color.White)
240                .enabled(this.state.uiEnable)
241            } else if (this.state.videoState === 'pauseTakeVideo') {
242              Image($r('app.media.ic_video_pause')).width(20).aspectRatio(1).fillColor(Color.Red)
243                .enabled(this.state.uiEnable)
244            }
245          }
246          .width(40)
247          .padding({ left: 10, right: 10 })
248          .margin({ left: 6 })
249          .enabled(this.state.uiEnable)
250          .onClick(() => {
251              this.state.videoState === 'startTakeVideo' ? this.state.pauseRecording() : this.state.resumeRecording()
252          })
253        }.width('100%').height('100%')
254      }
255      .width(120).height(56).borderRadius(28)
256      .border({ width: 1, color: Color.White, style: BorderStyle.Solid })
257      .margin({ left: 24, right: 24 })
258    }
259  }
260}