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