-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.tsx
executable file
·117 lines (98 loc) · 3.47 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// tslint:disable-next-line: no-implicit-dependencies
import * as React from 'react';
// tslint:disable-next-line: no-implicit-dependencies
import { Text } from 'react-native';
interface ITimerCountdownProps {
initialSecondsRemaining: number;
formatSecondsRemaining?: (milliseconds: number) => string;
onTick?: (secondsRemaining: number) => void;
onComplete?: () => void;
allowFontScaling?: boolean;
style?: object;
}
export default class TimerCountdown extends React.Component<ITimerCountdownProps> {
public readonly state = {
secondsRemaining: this.props.initialSecondsRemaining,
timeoutId: undefined,
previousSeconds: undefined
};
public componentDidMount(): void {
this.tick();
}
public componentWillReceiveProps(newProps: ITimerCountdownProps): void {
if (this.state.timeoutId !== undefined) {
clearTimeout(this.state.timeoutId);
}
this.setState({
previousSeconds: undefined,
secondsRemaining: newProps.initialSecondsRemaining
});
}
public componentDidUpdate(): void {
if (!this.state.previousSeconds && this.state.secondsRemaining > 0) {
this.tick();
}
}
public componentWillUnmount(): void {
clearTimeout(this.state.timeoutId);
}
private tick = () => {
const currentSeconds = Date.now();
const dt = this.state.previousSeconds ? currentSeconds - this.state.previousSeconds : 0;
const interval: number = 1000;
// correct for small variations in actual timeout time
const intervalSecondsRemaing: number = interval - (dt % interval);
let timeout: number = intervalSecondsRemaing;
if (intervalSecondsRemaing < interval / 2.0) {
timeout += interval;
}
const secondsRemaining: number = Math.max(this.state.secondsRemaining - dt, 0);
const isComplete: boolean = !!this.state.previousSeconds && secondsRemaining <= 0;
if (this.state.timeoutId !== undefined) {
clearTimeout(this.state.timeoutId);
}
this.setState({
timeoutId: isComplete ? undefined : setTimeout(this.tick, timeout),
previousSeconds: currentSeconds,
secondsRemaining
});
if (isComplete) {
if (this.props.onComplete) {
this.props.onComplete();
}
return;
}
if (this.props.onTick !== undefined) {
this.props.onTick(secondsRemaining);
}
};
private getFormattedTime = (milliseconds: number): string => {
if (this.props.formatSecondsRemaining !== undefined) {
return this.props.formatSecondsRemaining(milliseconds);
}
const remainingSec: number = Math.round(milliseconds / 1000);
const seconds: number = parseInt((remainingSec % 60).toString(), 10);
const minutes: number = parseInt(((remainingSec / 60) % 60).toString(), 10);
const hours: number = parseInt((remainingSec / 3600).toString(), 10);
const s = seconds < 10 ? '0' + seconds : seconds;
const m = minutes < 10 ? '0' + minutes : minutes;
let h = hours < 10 ? '0' + hours : hours;
h = h === '00' ? '' : h + ':';
return h + m + ':' + s;
};
public render(): React.ReactNode {
const secondsRemaining: number = this.state.secondsRemaining;
const allowFontScaling: boolean = !!this.props.allowFontScaling;
const style = this.props.style;
return (
<Text allowFontScaling={allowFontScaling} style={style}>
{this.getFormattedTime(secondsRemaining)}
</Text>
);
}
public static defaultProps = {
formatSecondsRemaining: undefined,
onTick: undefined,
onComplete: undefined
};
}