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
|
// TODO: change filename?
import * as _ from 'lodash';
import { Dispatch } from 'redux';
import { PROGRESS_STALL_AT_PERCENTAGE, PROGRESS_TICK_INTERVAL_MS } from '../constants';
import { Action, actions } from '../redux/actions';
const curTimeUnix = () => {
return new Date().getTime();
};
enum TickingState {
None,
Running,
Finishing,
}
interface TickingNoneState {
state: TickingState.None;
}
interface TickingRunningStatus {
state: TickingState.Running;
}
interface TickingFinishingStatus {
state: TickingState.Finishing;
increasePercentageEveryTick: number;
}
type TickingStatus = TickingNoneState | TickingRunningStatus | TickingFinishingStatus;
const TICKS_PER_SECOND = 1000 / PROGRESS_TICK_INTERVAL_MS;
class Progress {
private _startTimeUnix?: number;
private _expectedTimeMs?: number;
private _intervalId?: number;
private _percentageDone: number;
private _tickingStatus: TickingStatus;
private _dispatcher: Dispatch<Action>;
constructor(dispatcher: Dispatch<Action>) {
this._startTimeUnix = undefined;
this._expectedTimeMs = undefined;
this._percentageDone = 0;
this._intervalId = undefined;
this._tickingStatus = { state: TickingState.None };
this._dispatcher = dispatcher;
}
public beginRunning(expectedTimeMs: number): void {
this._clearTimer();
this._startTimeUnix = curTimeUnix();
this._expectedTimeMs = expectedTimeMs;
this._percentageDone = 0;
this._intervalId = window.setInterval(this._tick.bind(this), PROGRESS_TICK_INTERVAL_MS);
this._tickingStatus = { state: TickingState.Running };
}
public setFinishing(): void {
const percentLeft = 100 - this._percentageDone;
const increasePercentageEveryTick = percentLeft / TICKS_PER_SECOND;
this._tickingStatus = {
state: TickingState.Finishing,
increasePercentageEveryTick,
};
}
private _tick(): void {
const rawPercentageDone =
this._tickingStatus.state === TickingState.Finishing
? this._getNewPercentageFinishing(this._tickingStatus)
: this._getNewPercentageNormal();
const maxPercentage = this._tickingStatus.state === TickingState.Finishing ? 100 : PROGRESS_STALL_AT_PERCENTAGE;
const percentageDone = Math.floor(Math.min(rawPercentageDone, maxPercentage));
this._percentageDone = percentageDone;
this._dispatcher(actions.updateOrderProgressPercentage(this._percentageDone));
console.log('percentageDone', this._percentageDone);
if (percentageDone >= 100) {
this._clearTimer();
}
return;
}
private _clearTimer(): void {
if (this._intervalId) {
window.clearTimeout(this._intervalId);
}
}
private _getNewPercentageNormal(): number {
if (_.isUndefined(this._startTimeUnix) || _.isUndefined(this._expectedTimeMs)) {
throw new Error('Cant tick, missing var');
}
const elapsedTimeMs = curTimeUnix() - this._startTimeUnix;
const safeElapsedTimeMs = Math.max(elapsedTimeMs, 1);
const percentageDone = safeElapsedTimeMs / this._expectedTimeMs * 100;
return percentageDone;
}
private _getNewPercentageFinishing(finishingState: TickingFinishingStatus): number {
return this._percentageDone + finishingState.increasePercentageEveryTick;
}
}
let _currentProgress: Progress | undefined;
export const progress = (dispatcher: Dispatch<Action>): Progress => {
_currentProgress = _currentProgress || new Progress(dispatcher);
return _currentProgress;
};
|