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 { Action } from '@ohos/common/src/main/ets/default/redux/actions/Action';
17import { EventBus } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBus';
18import { EventBusManager } from '@ohos/common/src/main/ets/default/worker/eventbus/EventBusManager';
19import { Log } from '@ohos/common/src/main/ets/default/utils/Log';
20import { Dispatch, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store';
21import { getStore } from '@ohos/common/src/main/ets/default/redux/store';
22import { GlobalContext } from '@ohos/common/src/main/ets/default/utils/GlobalContext';
23
24class StateStruct {
25  recordingTime: number = 0;
26  recordingTimeDisplay: string = '';
27  isRecordingPaused: boolean = false;
28  isRecordingSpotVisible: boolean = true;
29  isThirdPartyCall: boolean = false;
30}
31
32class BigVideoTimerDispatcher {
33  private mDispatch: Dispatch = (data) => data;
34
35  public setDispatch(dispatch: Dispatch) {
36    this.mDispatch = dispatch;
37  }
38
39  public updateRecordingTime(recordingTime: number): void {
40    this.mDispatch(Action.updateRecordingTime(recordingTime));
41  }
42
43  public updateSmallVideoTimerVisible(visible: boolean): void {
44    this.mDispatch(Action.updateSmallVideoTimerVisible(visible));
45  }
46
47  public updateBigVideoTimerVisible(visible: boolean): void {
48    this.mDispatch(Action.updateBigVideoTimerVisible(visible));
49  }
50
51  public updateRecordingSpotVisible(visible: boolean): void {
52    this.mDispatch(Action.updateRecordingSpotVisible(visible));
53  }
54
55  public updateRecordingTimeDisplay(timeDisplay: string): void {
56    this.mDispatch(Action.updateRecordingTimeDisplay(timeDisplay));
57  }
58
59  public stopRecording(): void {
60    this.mDispatch(Action.stopRecording())
61    this.mDispatch(Action.updateVideoState('beforeTakeVideo'))
62    this.mDispatch(Action.updateBigVideoTimerVisible(false))
63    this.mDispatch(Action.updateSmallVideoTimerVisible(false))
64    this.mDispatch(Action.updateScreenStatus(false))
65  }
66}
67
68
69@Component
70export struct BigVideoTimer {
71  private TAG: string = '[BigVideoTimer]'
72  private timer: number = 0
73  private timerTick: number = 0
74  private appEventBus: EventBus = EventBusManager.getInstance().getEventBus()
75  @State state: StateStruct = new StateStruct()
76  private mAction: BigVideoTimerDispatcher = new BigVideoTimerDispatcher();
77
78  private async onRecordPaused(): Promise<void> {
79    Log.info(`${this.TAG} onRecordPaused timer id: ${this.timer} E`)
80    clearInterval(this.timer)
81    Log.info(`${this.TAG} onRecordPaused X`)
82  }
83
84  private async onRecordResumed(): Promise<void> {
85    Log.info(`${this.TAG} onRecordResumed E`)
86    if (this.state.recordingTime <= 2) {
87      this.setIntervalTimer()
88    }
89    Log.info(`${this.TAG} onRecordResumed X`)
90  }
91
92  aboutToAppear(): void {
93    Log.info(`${this.TAG} aboutToAppear E`)
94    getStore().subscribe((state: OhCombinedState) => {
95      this.state = {
96        recordingTime: state.recordReducer.recordingTime,
97        recordingTimeDisplay: state.recordReducer.recordingTimeDisplay,
98        isRecordingPaused: state.recordReducer.isRecordingPaused,
99        isRecordingSpotVisible: state.recordReducer.isRecordingSpotVisible,
100        isThirdPartyCall: state.contextReducer.isThirdPartyCall,
101      };
102    }, (dispatch: Dispatch) => {
103      this.mAction.setDispatch(dispatch);
104    });
105
106    this.setIntervalTimer()
107    this.appEventBus.on(Action.ACTION_RECORD_PAUSE, () => this.onRecordPaused())
108    this.appEventBus.on(Action.ACTION_RECORD_RESUME, () => this.onRecordResumed())
109    Log.info(`${this.TAG} aboutToAppear X`)
110  }
111
112  aboutToDisappear(): void {
113    Log.info(`${this.TAG} aboutToDisappear E`)
114    this.appEventBus.off(Action.ACTION_RECORD_PAUSE, () => this.onRecordPaused())
115    this.appEventBus.off(Action.ACTION_RECORD_RESUME, () => this.onRecordResumed())
116    Log.info(`${this.TAG} clearInterval timer id: ${this.timer}`)
117    clearInterval(this.timer)
118    Log.info(`${this.TAG} aboutToDisappear X`)
119  }
120
121  private setIntervalTimer(): void {
122    clearInterval(this.timer)
123    this.timer = setInterval(() => {
124      this.timerTick++
125      if (this.timerTick % 2 === 0) {
126        this.mAction.updateRecordingTime(this.state.recordingTime + 1)
127        let shownSec = '00'
128        let shownMin = '00'
129        let sec = this.state.recordingTime % 60
130        if (sec < 10) {
131          shownSec = `0${sec}`
132        } else {
133          shownSec = `${sec}`
134        }
135        let minute = Math.floor(this.state.recordingTime / 60)
136        if (minute < 10) {
137          shownMin = `0${minute}`
138        } else {
139          shownMin = `${minute}`
140        }
141        this.mAction.updateRecordingTimeDisplay(`${shownMin}:${shownSec}`)
142        if (this.state.recordingTime > 2) {
143          clearInterval(this.timer)
144          this.mAction.updateSmallVideoTimerVisible(true)
145          this.mAction.updateBigVideoTimerVisible(false)
146        }
147      }
148      this.mAction.updateRecordingSpotVisible(!this.state.isRecordingSpotVisible)
149      if (this.state.isThirdPartyCall && GlobalContext.get().getCameraAbilityWant().parameters?.videoDuration) {
150        try {
151          let videoDuration: number = Number.parseInt(GlobalContext.get().getCameraAbilityWant().parameters?.videoDuration as string)
152          Log.info(`${this.TAG} videoDuration is ${videoDuration}`);
153          if (this.state.recordingTime >= videoDuration) {
154            this.mAction.stopRecording();
155          }
156        } catch (error) {
157          Log.info(`${this.TAG} picker videoDuration --> ${JSON.stringify(error)}}`)
158        }
159      }
160    }, 500)
161  }
162
163  build() {
164    Column() {
165      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
166        Row() {
167          Text('').layoutWeight(1)
168          if (this.state.isRecordingPaused) {
169            Image($r('app.media.ic_video_recording'))
170              .width(12).height(12)
171              .fillColor(Color.White)
172          } else {
173            if (this.state.isRecordingSpotVisible) {
174              Column() {
175              }
176              .width(12)
177              .height(12)
178              .borderRadius(6)
179              .backgroundColor(Color.Red)
180              .visibility(Visibility.Visible)
181            } else {
182              Column() {
183              }
184              .width(12)
185              .height(12)
186              .borderRadius(6)
187              .backgroundColor(Color.Red)
188              .visibility(Visibility.Hidden)
189            }
190          }
191          Text(`${this.state.recordingTimeDisplay}`)
192            .margin({ left: 8, right: 8 })
193            .textAlign(TextAlign.Center)
194            .fontSize('50fp')
195            .fontColor(Color.White)
196            .fontWeight(300)
197          Text('').width(12).height(12)
198          Text('').layoutWeight(1)
199        }
200      }
201    }.width('100%').height(96).position({ x: 0, y: 0 })
202  }
203}