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
|
<?php
namespace gipfl\Cli;
use React\EventLoop\LoopInterface;
use React\Promise\Deferred;
use React\Promise\ExtendedPromiseInterface;
class Spinner
{
const ASCII_SLASH = ['/', '-', '\\', '|'];
const ASCII_BOUNCING_CIRCLE = ['.', 'o', 'O', '°', 'O', 'o'];
const ROTATING_HALF_CIRCLE = ['◑', '◒', '◐', '◓'];
const ROTATING_EARTH = ['🌎', '🌏', '🌍'];
const ROTATING_MOON = ['🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘'];
const UP_DOWN_BAR = [' ', '_', '▁', '▃', '▄', '▅', '▆', '▇', '▆', '▅', '▄', '▃', '▁'];
const CLOCK = ['🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚', '🕛'];
const WAVING_DOTS = ['⢄', '⢂', '⢁', '⡁', '⡈', '⡐', '⡠', '⡐', '⡈', '⡁', '⢁', '⢂'];
const ROTATING_DOTS = ['⣷', '⣯', '⣟', '⡿', '⢿', '⣻', '⣽', '⣾'];
/** @var LoopInterface */
protected $loop;
protected $frames;
protected $frame = -1;
protected $count;
protected $delay;
public function __construct(LoopInterface $loop, array $frames = self::ASCII_SLASH)
{
$this->loop = $loop;
$this->frames = $frames;
$this->count = \count($frames);
$this->delay = ((int) (2 * 100 / $this->count)) / 100;
}
protected function getNextFrame()
{
$first = $this->frame === -1;
$this->frame++;
if ($this->frame >= $this->count) {
$this->frame = 0;
}
return $this->frames[$this->frame];
}
public function spinWhile(ExtendedPromiseInterface $promise, callable $renderer)
{
$next = function () use ($renderer) {
$renderer($this->getNextFrame());
};
$spinTimer = $this->loop->addPeriodicTimer($this->delay, $next);
$deferred = new Deferred(function () use ($spinTimer) {
$this->loop->cancelTimer($spinTimer);
});
$this->loop->futureTick($next);
$wait = $deferred->promise();
$cancel = function () use ($wait) {
$wait->cancel();
};
$promise->otherwise($cancel)->then($cancel);
return $promise;
}
}
|