forked from terpinedream/tuxagotchi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathui.py
More file actions
143 lines (112 loc) · 3.64 KB
/
ui.py
File metadata and controls
143 lines (112 loc) · 3.64 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# ui.py
from rich.columns import Columns
from datetime import datetime
from rich import box
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
import sys
import os
console = Console()
def load_ascii(mood, tick):
base_path = f"assets/{mood}.txt"
alt_path = f"assets/{mood}2.txt"
try:
with open(base_path) as f:
base_lines = f.readlines()
except FileNotFoundError:
base_lines = ["(?)\n"]
try:
with open(alt_path) as f:
alt_lines = f.readlines()
except FileNotFoundError:
alt_lines = base_lines
# Ensure same height by padding whichever is shorter
max_height = max(len(base_lines), len(alt_lines))
base_lines += ["\n"] * (max_height - len(base_lines))
alt_lines += ["\n"] * (max_height - len(alt_lines))
return "".join(base_lines if tick % 2 == 0 else alt_lines)
def format_timedelta(td):
seconds = int(td.total_seconds())
if seconds < 60:
return f"{seconds}s"
elif seconds < 3600:
return f"{seconds // 60}m"
elif seconds < 86400:
return f"{seconds // 3600}h"
else:
return f"{seconds // 86400}d"
def generate_block_bar(tux, tick, length=10):
countdown = tux.time_until_next_mood()
if not countdown:
return "" # No countdown for sad/dead
# Total time per mood stage
if tux.mood == "happy":
total = 4 * 3600 # 4 hours
elif tux.mood == "neutral":
total = 24 * 3600 # 1 day
else:
return ""
remaining = countdown.total_seconds()
progress = remaining / total # Now: 1.0 when full, 0.0 when empty
blocks_filled = int(progress * length)
blocks_empty = length - blocks_filled
# Animate the last filled block to "bounce"
animation = ["░", "▒", "▓", "█", "▓", "▒"]
frame = animation[tick % len(animation)]
if blocks_filled > 0:
return "█" * (blocks_filled - 1) + frame + "░" * blocks_empty
else:
return frame + "░" * (length - 1)
def center_ascii(art, width=32):
lines = art.splitlines()
return "\n".join(line.center(width) for line in lines)
def render(tux, repo_name, tick):
sys.stdout.write("\033c")
sys.stdout.flush()
# ASCII art + info
art = load_ascii(tux.mood, tick)
last_commit_td = tux.time_since_commit()
countdown_td = tux.time_until_next_mood()
last_commit_text = "Unknown"
if last_commit_td:
last_commit_text = f"{format_timedelta(last_commit_td)} ago"
# Time string
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Tux panel
tux_lines = [
art,
"",
f"[bold]Mood:[/bold] {tux.mood.upper()}",
f"[bold]Repo:[/bold] {repo_name}",
f"[bold]Last Commit:[/bold] {last_commit_text}",
]
if countdown_td:
hunger_bar = generate_block_bar(tux, tick=tick, length=10)
tux_lines.append(
f"[bold]Hungry in:[/bold] {format_timedelta(countdown_td)} {hunger_bar}"
)
while len(tux_lines) < 5:
tux_lines.append("")
tux_panel = Panel.fit(
Text.from_markup("\n".join(tux_lines)),
title="Tuxagotchi",
width=62,
box=box.ROUNDED,
)
commit_counts = tux.get_commit_counts()
stats_lines = [
"[bold]Stats[/bold]",
f" Commits (24h): {commit_counts['24h']}",
f" Commits (7d): {commit_counts['7d']}",
"",
f" Time: {now}",
]
stats_body = "\n".join(stats_lines)
stats_panel = Panel.fit(
Text.from_markup(stats_body),
title="Stats",
width=30,
box=box.ROUNDED,
)
console.print(Columns([tux_panel, stats_panel]))