spinner and progress bar for kittens UI

This commit is contained in:
Kovid Goyal
2021-09-15 13:39:39 +05:30
parent 5916bbd5b3
commit c08dc64581
2 changed files with 570 additions and 0 deletions

39
kittens/tui/progress.py Normal file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
from .operations import styled
def render_progress_bar(frac: float, width: int = 80) -> str:
if frac >= 1:
return styled('🬋' * width, fg='green')
if frac <= 0:
return styled('🬋' * width, dim=True)
w = frac * width
overhang = w - int(w)
filled = '🬋' * int(w)
if overhang < 0.2:
needs_break = True
elif overhang < 0.8:
filled += '🬃'
needs_break = False
else:
if len(filled) < width - 1:
filled += '🬋'
needs_break = True
else:
filled += '🬃'
needs_break = False
ans = styled(filled, fg='blue')
unfilled = ''
if width > len(filled):
if needs_break:
unfilled += '🬇'
filler = width - len(filled) - len(unfilled)
if filler > 0:
unfilled += '🬋' * filler
if unfilled:
ans += styled(unfilled, dim=True)
return ans

531
kittens/tui/spinners.py Normal file
View File

@@ -0,0 +1,531 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
from time import monotonic
from typing import Dict, Sequence
from kitty.typing import TypedDict
class SpinnerDef(TypedDict):
interval: int
frames: Sequence[str]
# Spinner definitions are from
# https://raw.githubusercontent.com/sindresorhus/cli-spinners/main/spinners.json
spinners: Dict[str, SpinnerDef] = { # {{{
"dots": {
"interval": 80,
"frames": ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
},
"dots2": {
"interval": 80,
"frames": ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"]
},
"dots3": {
"interval": 80,
"frames": ["⠋", "⠙", "⠚", "⠞", "⠖", "⠦", "⠴", "⠲", "⠳", "⠓"]
},
"dots4": {
"interval":
80,
"frames":
["⠄", "⠆", "⠇", "⠋", "⠙", "⠸", "⠰", "⠠", "⠰", "⠸", "⠙", "⠋", "⠇", "⠆"]
},
"dots5": {
"interval":
80,
"frames": [
"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐",
"⠐", "⠒", "⠓", "⠋"
]
},
"dots6": {
"interval":
80,
"frames": [
"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄",
"⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"
]
},
"dots7": {
"interval":
80,
"frames": [
"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠",
"⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"
]
},
"dots8": {
"interval":
80,
"frames": [
"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄",
"⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋",
"⠉", "⠈", "⠈"
]
},
"dots9": {
"interval": 80,
"frames": ["⢹", "⢺", "⢼", "⣸", "⣇", "⡧", "⡗", "⡏"]
},
"dots10": {
"interval": 80,
"frames": ["⢄", "⢂", "⢁", "⡁", "⡈", "⡐", "⡠"]
},
"dots11": {
"interval": 100,
"frames": ["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]
},
"dots12": {
"interval":
80,
"frames": [
"⢀⠀", "⡀⠀", "⠄⠀", "⢂⠀", "⡂⠀", "⠅⠀", "⢃⠀", "⡃⠀", "⠍⠀", "⢋⠀", "⡋⠀",
"⠍⠁", "⢋⠁", "⡋⠁", "⠍⠉", "⠋⠉", "⠋⠉", "⠉⠙", "⠉⠙", "⠉⠩", "⠈⢙", "⠈⡙",
"⢈⠩", "⡀⢙", "⠄⡙", "⢂⠩", "⡂⢘", "⠅⡘", "⢃⠨", "⡃⢐", "⠍⡐", "⢋⠠", "⡋⢀",
"⠍⡁", "⢋⠁", "⡋⠁", "⠍⠉", "⠋⠉", "⠋⠉", "⠉⠙", "⠉⠙", "⠉⠩", "⠈⢙", "⠈⡙",
"⠈⠩", "⠀⢙", "⠀⡙", "⠀⠩", "⠀⢘", "⠀⡘", "⠀⠨", "⠀⢐", "⠀⡐", "⠀⠠", "⠀⢀",
"⠀⡀"
]
},
"dots8Bit": {
"interval":
80,
"frames": [
"⠀", "⠁", "⠂", "⠃", "⠄", "⠅", "⠆", "⠇", "⡀", "⡁", "⡂", "⡃", "⡄",
"⡅", "⡆", "⡇", "⠈", "⠉", "⠊", "⠋", "⠌", "⠍", "⠎", "⠏", "⡈", "⡉",
"⡊", "⡋", "⡌", "⡍", "⡎", "⡏", "⠐", "⠑", "⠒", "⠓", "⠔", "⠕", "⠖",
"⠗", "⡐", "⡑", "⡒", "⡓", "⡔", "⡕", "⡖", "⡗", "⠘", "⠙", "⠚", "⠛",
"⠜", "⠝", "⠞", "⠟", "⡘", "⡙", "⡚", "⡛", "⡜", "⡝", "⡞", "⡟", "⠠",
"⠡", "⠢", "⠣", "⠤", "⠥", "⠦", "⠧", "⡠", "⡡", "⡢", "⡣", "⡤", "⡥",
"⡦", "⡧", "⠨", "⠩", "⠪", "⠫", "⠬", "⠭", "⠮", "⠯", "⡨", "⡩", "⡪",
"⡫", "⡬", "⡭", "⡮", "⡯", "⠰", "⠱", "⠲", "⠳", "⠴", "⠵", "⠶", "⠷",
"⡰", "⡱", "⡲", "⡳", "⡴", "⡵", "⡶", "⡷", "⠸", "⠹", "⠺", "⠻", "⠼",
"⠽", "⠾", "⠿", "⡸", "⡹", "⡺", "⡻", "⡼", "⡽", "⡾", "⡿", "⢀", "⢁",
"⢂", "⢃", "⢄", "⢅", "⢆", "⢇", "⣀", "⣁", "⣂", "⣃", "⣄", "⣅", "⣆",
"⣇", "⢈", "⢉", "⢊", "⢋", "⢌", "⢍", "⢎", "⢏", "⣈", "⣉", "⣊", "⣋",
"⣌", "⣍", "⣎", "⣏", "⢐", "⢑", "⢒", "⢓", "⢔", "⢕", "⢖", "⢗", "⣐",
"⣑", "⣒", "⣓", "⣔", "⣕", "⣖", "⣗", "⢘", "⢙", "⢚", "⢛", "⢜", "⢝",
"⢞", "⢟", "⣘", "⣙", "⣚", "⣛", "⣜", "⣝", "⣞", "⣟", "⢠", "⢡", "⢢",
"⢣", "⢤", "⢥", "⢦", "⢧", "⣠", "⣡", "⣢", "⣣", "⣤", "⣥", "⣦", "⣧",
"⢨", "⢩", "⢪", "⢫", "⢬", "⢭", "⢮", "⢯", "⣨", "⣩", "⣪", "⣫", "⣬",
"⣭", "⣮", "⣯", "⢰", "⢱", "⢲", "⢳", "⢴", "⢵", "⢶", "⢷", "⣰", "⣱",
"⣲", "⣳", "⣴", "⣵", "⣶", "⣷", "⢸", "⢹", "⢺", "⢻", "⢼", "⢽", "⢾",
"⢿", "⣸", "⣹", "⣺", "⣻", "⣼", "⣽", "⣾", "⣿"
]
},
"line": {
"interval": 130,
"frames": ["-", "\\", "|", "/"]
},
"line2": {
"interval": 100,
"frames": ["⠂", "-", "–", "—", "–", "-"]
},
"pipe": {
"interval": 100,
"frames": ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"]
},
"simpleDots": {
"interval": 400,
"frames": [". ", ".. ", "...", " "]
},
"simpleDotsScrolling": {
"interval": 200,
"frames": [". ", ".. ", "...", " ..", " .", " "]
},
"star": {
"interval": 70,
"frames": ["✶", "✸", "✹", "✺", "✹", "✷"]
},
"star2": {
"interval": 80,
"frames": ["+", "x", "*"]
},
"flip": {
"interval": 70,
"frames": ["_", "_", "_", "-", "`", "`", "'", "´", "-", "_", "_", "_"]
},
"hamburger": {
"interval": 100,
"frames": ["☱", "☲", "☴"]
},
"growVertical": {
"interval": 120,
"frames": ["▁", "▃", "▄", "▅", "▆", "▇", "▆", "▅", "▄", "▃"]
},
"growHorizontal": {
"interval": 120,
"frames": ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▊", "▋", "▌", "▍", "▎"]
},
"balloon": {
"interval": 140,
"frames": [" ", ".", "o", "O", "@", "*", " "]
},
"balloon2": {
"interval": 120,
"frames": [".", "o", "O", "°", "O", "o", "."]
},
"noise": {
"interval": 100,
"frames": ["▓", "▒", "░"]
},
"bounce": {
"interval": 120,
"frames": ["⠁", "⠂", "⠄", "⠂"]
},
"boxBounce": {
"interval": 120,
"frames": ["▖", "▘", "▝", "▗"]
},
"boxBounce2": {
"interval": 100,
"frames": ["▌", "▀", "▐", "▄"]
},
"triangle": {
"interval": 50,
"frames": ["◢", "◣", "◤", "◥"]
},
"arc": {
"interval": 100,
"frames": ["◜", "◠", "◝", "◞", "◡", "◟"]
},
"circle": {
"interval": 120,
"frames": ["◡", "⊙", "◠"]
},
"squareCorners": {
"interval": 180,
"frames": ["◰", "◳", "◲", "◱"]
},
"circleQuarters": {
"interval": 120,
"frames": ["◴", "◷", "◶", "◵"]
},
"circleHalves": {
"interval": 50,
"frames": ["◐", "◓", "◑", "◒"]
},
"squish": {
"interval": 100,
"frames": ["╫", "╪"]
},
"toggle": {
"interval": 250,
"frames": ["⊶", "⊷"]
},
"toggle2": {
"interval": 80,
"frames": ["▫", "▪"]
},
"toggle3": {
"interval": 120,
"frames": ["□", "■"]
},
"toggle4": {
"interval": 100,
"frames": ["■", "□", "▪", "▫"]
},
"toggle5": {
"interval": 100,
"frames": ["▮", "▯"]
},
"toggle6": {
"interval": 300,
"frames": ["ဝ", "၀"]
},
"toggle7": {
"interval": 80,
"frames": ["⦾", "⦿"]
},
"toggle8": {
"interval": 100,
"frames": ["◍", "◌"]
},
"toggle9": {
"interval": 100,
"frames": ["◉", "◎"]
},
"toggle10": {
"interval": 100,
"frames": ["㊂", "㊀", "㊁"]
},
"toggle11": {
"interval": 50,
"frames": ["⧇", "⧆"]
},
"toggle12": {
"interval": 120,
"frames": ["☗", "☖"]
},
"toggle13": {
"interval": 80,
"frames": ["=", "*", "-"]
},
"arrow": {
"interval": 100,
"frames": ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"]
},
"arrow2": {
"interval": 80,
"frames": ["⬆️ ", "↗️ ", "➡️ ", "↘️ ", "⬇️ ", "↙️ ", "⬅️ ", "↖️ "]
},
"arrow3": {
"interval": 120,
"frames": ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"]
},
"bouncingBar": {
"interval":
80,
"frames": [
"[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]",
"[ =]", "[ ]", "[ =]", "[ ==]", "[ ===]", "[====]",
"[=== ]", "[== ]", "[= ]"
]
},
"bouncingBall": {
"interval":
80,
"frames": [
"( ● )", "( ● )", "( ● )", "( ● )", "( ●)",
"( ● )", "( ● )", "( ● )", "( ● )", "(● )"
]
},
"smiley": {
"interval": 200,
"frames": ["😄 ", "😝 "]
},
"monkey": {
"interval": 300,
"frames": ["🙈 ", "🙈 ", "🙉 ", "🙊 "]
},
"hearts": {
"interval": 100,
"frames": ["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "]
},
"clock": {
"interval":
100,
"frames": [
"🕛 ", "🕐 ", "🕑 ", "🕒 ", "🕓 ", "🕔 ", "🕕 ", "🕖 ", "🕗 ", "🕘 ", "🕙 ",
"🕚 "
]
},
"earth": {
"interval": 180,
"frames": ["🌍 ", "🌎 ", "🌏 "]
},
"material": {
"interval":
17,
"frames": [
"█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"███████▁▁▁▁▁▁▁▁▁▁▁▁▁", "████████▁▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
"██████████▁▁▁▁▁▁▁▁▁▁", "███████████▁▁▁▁▁▁▁▁▁",
"█████████████▁▁▁▁▁▁▁", "██████████████▁▁▁▁▁▁",
"██████████████▁▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
"▁██████████████▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
"▁▁██████████████▁▁▁▁", "▁▁▁██████████████▁▁▁",
"▁▁▁▁█████████████▁▁▁", "▁▁▁▁██████████████▁▁",
"▁▁▁▁██████████████▁▁", "▁▁▁▁▁██████████████▁",
"▁▁▁▁▁██████████████▁", "▁▁▁▁▁██████████████▁",
"▁▁▁▁▁▁██████████████", "▁▁▁▁▁▁██████████████",
"▁▁▁▁▁▁▁█████████████", "▁▁▁▁▁▁▁█████████████",
"▁▁▁▁▁▁▁▁████████████", "▁▁▁▁▁▁▁▁████████████",
"▁▁▁▁▁▁▁▁▁███████████", "▁▁▁▁▁▁▁▁▁███████████",
"▁▁▁▁▁▁▁▁▁▁██████████", "▁▁▁▁▁▁▁▁▁▁██████████",
"▁▁▁▁▁▁▁▁▁▁▁▁████████", "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
"█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", "████████▁▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
"█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
"███████████▁▁▁▁▁▁▁▁▁", "████████████▁▁▁▁▁▁▁▁",
"████████████▁▁▁▁▁▁▁▁", "██████████████▁▁▁▁▁▁",
"██████████████▁▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
"▁██████████████▁▁▁▁▁", "▁▁▁█████████████▁▁▁▁",
"▁▁▁▁▁████████████▁▁▁", "▁▁▁▁▁████████████▁▁▁",
"▁▁▁▁▁▁███████████▁▁▁", "▁▁▁▁▁▁▁▁█████████▁▁▁",
"▁▁▁▁▁▁▁▁█████████▁▁▁", "▁▁▁▁▁▁▁▁▁█████████▁▁",
"▁▁▁▁▁▁▁▁▁█████████▁▁", "▁▁▁▁▁▁▁▁▁▁█████████▁",
"▁▁▁▁▁▁▁▁▁▁▁████████▁", "▁▁▁▁▁▁▁▁▁▁▁████████▁",
"▁▁▁▁▁▁▁▁▁▁▁▁███████▁", "▁▁▁▁▁▁▁▁▁▁▁▁███████▁",
"▁▁▁▁▁▁▁▁▁▁▁▁▁███████", "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
"▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁"
]
},
"moon": {
"interval": 80,
"frames": ["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "]
},
"runner": {
"interval": 140,
"frames": ["🚶 ", "🏃 "]
},
"pong": {
"interval":
80,
"frames": [
"▐⠂ ▌", "▐⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌",
"▐ ⡀ ▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌",
"▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐ ⠠ ▌",
"▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂▌", "▐ ⠠▌",
"▐ ⡀▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌",
"▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐ ⠠ ▌",
"▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌",
"▐ ⡀ ▌", "▐⠠ ▌"
]
},
"shark": {
"interval":
120,
"frames": [
"▐|\\____________▌", "▐_|\\___________▌", "▐__|\\__________▌",
"▐___|\\_________▌", "▐____|\\________▌", "▐_____|\\_______▌",
"▐______|\\______▌", "▐_______|\\_____▌", "▐________|\\____▌",
"▐_________|\\___▌", "▐__________|\\__▌", "▐___________|\\_▌",
"▐____________|\\▌", "▐____________/|▌", "▐___________/|_▌",
"▐__________/|__▌", "▐_________/|___▌", "▐________/|____▌",
"▐_______/|_____▌", "▐______/|______▌", "▐_____/|_______▌",
"▐____/|________▌", "▐___/|_________▌", "▐__/|__________▌",
"▐_/|___________▌", "▐/|____________▌"
]
},
"dqpb": {
"interval": 100,
"frames": ["d", "q", "p", "b"]
},
"weather": {
"interval":
100,
"frames": [
"☀️ ", "☀️ ", "☀️ ", "🌤 ", "⛅️ ", "🌥 ", "☁️ ", "🌧 ", "🌨 ", "🌧 ",
"🌨 ", "🌧 ", "🌨 ", "⛈ ", "🌨 ", "🌧 ", "🌨 ", "☁️ ", "🌥 ", "⛅️ ", "🌤 ",
"☀️ ", "☀️ "
]
},
"christmas": {
"interval": 400,
"frames": ["🌲", "🎄"]
},
"grenade": {
"interval":
80,
"frames": [
"، ", "′ ", " ´ ", " ‾ ", " ⸌", " ⸊", " |", " ⁎", " ⁕",
" ෴ ", " ⁓", " ", " ", " "
]
},
"point": {
"interval": 125,
"frames": ["∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"]
},
"layer": {
"interval": 150,
"frames": ["-", "=", "≡"]
},
"betaWave": {
"interval":
80,
"frames": [
"ρββββββ", "βρβββββ", "ββρββββ", "βββρβββ", "ββββρββ", "βββββρβ",
"ββββββρ"
]
},
"fingerDance": {
"interval": 160,
"frames": ["🤘 ", "🤟 ", "🖖 ", "✋ ", "🤚 ", "👆 "]
},
"fistBump": {
"interval":
80,
"frames": [
"🤜\u3000\u3000\u3000\u3000🤛 ", "🤜\u3000\u3000\u3000\u3000🤛 ",
"🤜\u3000\u3000\u3000\u3000🤛 ", "\u3000🤜\u3000\u3000🤛\u3000 ",
"\u3000\u3000🤜🤛\u3000\u3000 ", "\u3000🤜✨🤛\u3000\u3000 ",
"🤜\u3000✨\u3000🤛\u3000 "
]
},
"soccerHeader": {
"interval":
80,
"frames": [
" 🧑⚽️ 🧑 ", "🧑 ⚽️ 🧑 ", "🧑 ⚽️ 🧑 ", "🧑 ⚽️ 🧑 ",
"🧑 ⚽️ 🧑 ", "🧑 ⚽️ 🧑 ", "🧑 ⚽️🧑 ", "🧑 ⚽️ 🧑 ",
"🧑 ⚽️ 🧑 ", "🧑 ⚽️ 🧑 ", "🧑 ⚽️ 🧑 ", "🧑 ⚽️ 🧑 "
]
},
"mindblown": {
"interval":
160,
"frames": [
"😐 ", "😐 ", "😮 ", "😮 ", "😦 ", "😦 ", "😧 ", "😧 ", "🤯 ", "💥 ", "✨ ",
"\u3000 ", "\u3000 ", "\u3000 "
]
},
"speaker": {
"interval": 160,
"frames": ["🔈 ", "🔉 ", "🔊 ", "🔉 "]
},
"orangePulse": {
"interval": 100,
"frames": ["🔸 ", "🔶 ", "🟠 ", "🟠 ", "🔶 "]
},
"bluePulse": {
"interval": 100,
"frames": ["🔹 ", "🔷 ", "🔵 ", "🔵 ", "🔷 "]
},
"orangeBluePulse": {
"interval": 100,
"frames": ["🔸 ", "🔶 ", "🟠 ", "🟠 ", "🔶 ", "🔹 ", "🔷 ", "🔵 ", "🔵 ", "🔷 "]
},
"timeTravel": {
"interval":
100,
"frames": [
"🕛 ", "🕚 ", "🕙 ", "🕘 ", "🕗 ", "🕖 ", "🕕 ", "🕔 ", "🕓 ", "🕒 ", "🕑 ",
"🕐 "
]
},
"aesthetic": {
"interval":
80,
"frames": [
"▰▱▱▱▱▱▱", "▰▰▱▱▱▱▱", "▰▰▰▱▱▱▱", "▰▰▰▰▱▱▱", "▰▰▰▰▰▱▱", "▰▰▰▰▰▰▱",
"▰▰▰▰▰▰▰", "▰▱▱▱▱▱▱"
]
}
} # }}}
class Spinner:
def __init__(self, name: str = 'dots'):
definition = spinners[name]
self.interval = definition['interval'] / 1000
self.frames = definition['frames']
self.current_frame = -1
self.last_change_at = -self.interval
def __call__(self) -> str:
now = monotonic()
if now - self.last_change_at >= self.interval:
self.last_change_at = now
self.current_frame = (self.current_frame + 1) % len(self.frames)
return self.frames[self.current_frame]