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