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, getStore, OhCombinedState } from '@ohos/common/src/main/ets/default/redux/store';
20import { Log } from '@ohos/common/src/main/ets/default/utils/Log';
21import { GlobalContext } from '@ohos/common/src/main/ets/default/utils/GlobalContext';
22
23class StateStruct {
24  recordingTime: number = 0;
25  recordingTimeDisplay: string = '';
26  isRecordingPaused: boolean = false;
27  isRecordingSpotVisible: boolean = true;
28  isThirdPartyCall: boolean = false;
29}
30
31class SmallVideoTimerDispatcher {
32  private mDispatch: Dispatch = (data) => data;
33
34  public setDispatch(dispatch: Dispatch) {
35    this.mDispatch = dispatch;
36  }
37
38  public updateSpotVisible(visible: boolean): void {
39    this.mDispatch(Action.updateRecordingSpotVisible(visible));
40  }
41
42  public updateRecordingTime(recordingTime: number): void {
43    this.mDispatch(Action.updateRecordingTime(recordingTime));
44  }
45
46  public updateRecordingTimeDisplay(timeDisplay: string): void {
47    this.mDispatch(Action.updateRecordingTimeDisplay(timeDisplay));
48  }
49
50  public stopRecording(): void {
51    this.mDispatch(Action.stopRecording())
52    this.mDispatch(Action.updateVideoState('beforeTakeVideo'))
53    this.mDispatch(Action.updateBigVideoTimerVisible(false))
54    this.mDispatch(Action.updateSmallVideoTimerVisible(false))
55    this.mDispatch(Action.updateScreenStatus(false))
56  }
57}
58
59@Component
60export struct SmallVideoTimer {
61  private TAG: string = '[SmallVideoTimer]';
62  private timer: number = 0;
63  private timerTick: number = 0;
64  private appEventBus: EventBus = EventBusManager.getInstance().getEventBus();
65  @State state: StateStruct = new StateStruct();
66  private mAction: SmallVideoTimerDispatcher = new SmallVideoTimerDispatcher();
67
68  private async onRecordPausedSmall() {
69    Log.info(`${this.TAG} onRecordPaused timer id: ${this.timer} E`)
70    clearInterval(this.timer)
71    Log.info(`${this.TAG} onRecordPaused X`)
72  }
73
74  private async onRecordResumedSmall() {
75    Log.info(`${this.TAG} onRecordResumed E`)
76    this.setIntervalTimer()
77    Log.info(`${this.TAG} onRecordResumed timer id: ${this.timer} X`)
78  }
79
80  aboutToAppear(): void {
81    Log.info(`${this.TAG} aboutToAppear E`)
82    getStore().subscribe((state: OhCombinedState) => {
83      this.state = {
84        recordingTime: state.recordReducer.recordingTime,
85        recordingTimeDisplay: state.recordReducer.recordingTimeDisplay,
86        isRecordingPaused: state.recordReducer.isRecordingPaused,
87        isRecordingSpotVisible: state.recordReducer.isRecordingSpotVisible,
88        isThirdPartyCall: state.contextReducer.isThirdPartyCall,
89      };
90    }, (dispatch: Dispatch) => {
91      this.mAction.setDispatch(dispatch);
92    });
93
94    this.setIntervalTimer()
95    this.appEventBus.on(Action.ACTION_RECORD_PAUSE, () => this.onRecordPausedSmall())
96    this.appEventBus.on(Action.ACTION_RECORD_RESUME, () => this.onRecordResumedSmall())
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.onRecordPausedSmall())
103    this.appEventBus.off(Action.ACTION_RECORD_RESUME, () => this.onRecordResumedSmall())
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    Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
147      Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) {
148        if (this.state.isRecordingPaused) {
149          Image($r('app.media.ic_video_recording')).width(12).height(12).fillColor(Color.White)
150        } else {
151          if (this.state.isRecordingSpotVisible) {
152            Column() {
153            }
154            .width(12)
155            .height(12)
156            .backgroundColor('#FF0000')
157            .borderRadius(6)
158            .visibility(Visibility.Visible)
159          } else {
160            Column() {
161            }
162            .width(12)
163            .height(12)
164            .backgroundColor('#FF0000')
165            .borderRadius(6)
166            .visibility(Visibility.Hidden)
167          }
168        }
169        Text(`${this.state.recordingTimeDisplay.split(':')[0]}`)
170          .margin({ left: 8 })
171          .fontSize('28fp')
172          .fontWeight(300)
173          .fontColor('#FFFFFF')
174      }.layoutWeight(1)
175
176      Text(':').fontSize('28fp').fontWeight(300).fontColor('#FFFFFF')
177      Text(`${this.state.recordingTimeDisplay.split(':')[1]}`)
178        .fontSize('28fp')
179        .fontWeight(300)
180        .fontColor('#FFFFFF')
181        .textAlign(TextAlign.Start)
182        .align(Alignment.Start)
183        .layoutWeight(1)
184    }.width('100%').height(48)
185  }
186}