-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
191 lines (155 loc) · 4.63 KB
/
Copy pathmain.py
File metadata and controls
191 lines (155 loc) · 4.63 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
"""Main application entry point."""
import sys
import threading
from pathlib import Path
from textual.app import ComposeResult
from textual.containers import Container
from textual.app import App
from textual.binding import Binding
# Add src to path for imports
sys.path.insert(0, str(Path(__file__).parent / "src"))
from config import validate_api_key
from tracker import TimeTracker
from screenshots import ScreenshotThread
from ui import TimeTrackerApp, HeaderBar
class TTApp(App):
"""Main Time Tracking Application."""
# Global bindings so keys work regardless of widget focus
BINDINGS = [
Binding("t", "new_task", "New Task", show=True),
Binding("s", "start_stop", "Start/Stop", show=True),
Binding("a", "manual_add", "Manual Add", show=True),
Binding("d", "delete_session", "Delete Session", show=True),
Binding("left", "prev_week", "Previous Week", show=True),
Binding("right", "next_week", "Next Week", show=True),
]
TITLE = "Time Tracking Tool"
CSS = """
Screen {
layout: vertical;
}
HeaderBar {
height: 1;
color: white;
padding: 0 1;
border-bottom: none;
}
WeeklyTable {
height: auto;
min-height: 3;
border-bottom: solid $accent;
}
DailyBreakdown {
height: auto;
border-top: solid $accent;
padding: 1;
}
TaskListModal {
align: center middle;
}
TaskListModal > Vertical {
width: 50;
height: auto;
border: solid $accent;
background: $panel;
padding: 1;
}
NewTaskModal {
align: center middle;
}
NewTaskModal > Vertical {
width: 50;
height: auto;
border: solid $accent;
background: $panel;
padding: 1;
}
ManualAddModal {
align: center middle;
}
ManualAddModal > Vertical {
width: 60;
height: auto;
border: solid $accent;
background: $panel;
padding: 1;
}
DeleteSessionModal {
align: center middle;
}
DeleteSessionModal > Vertical {
width: 50;
height: auto;
border: solid $accent;
background: $panel;
padding: 1;
}
"""
def __init__(self):
super().__init__()
# Validate API key first
validate_api_key()
# Initialize tracker before compose is called
self.tracker = TimeTracker()
self.screenshot_thread = None
def on_mount(self):
"""Initialize app on mount."""
# Tracker already initialized in __init__
# Start auto-save thread
self.auto_save_thread = threading.Thread(
target=self._auto_save_loop,
daemon=True
)
self.auto_save_thread.start()
# Start screenshot thread
self.screenshot_thread = ScreenshotThread(self.tracker)
self.screenshot_thread.start()
def compose(self) -> ComposeResult:
"""Compose the main app."""
# Render a persistent header at the top showing keybinds
yield HeaderBar()
yield TimeTrackerApp(self.tracker)
# The following action methods delegate to the main TimeTracker widget
def _get_main_widget(self):
try:
return self.query_one(TimeTrackerApp)
except Exception:
return None
def action_new_task(self):
widget = self._get_main_widget()
if widget:
widget.action_new_task()
def action_start_stop(self):
widget = self._get_main_widget()
if widget:
widget.action_start_stop()
def action_manual_add(self):
widget = self._get_main_widget()
if widget:
widget.action_manual_add()
def action_delete_session(self):
widget = self._get_main_widget()
if widget:
widget.action_delete_session()
def action_prev_week(self):
widget = self._get_main_widget()
if widget:
widget.action_prev_week()
def action_next_week(self):
widget = self._get_main_widget()
if widget:
widget.action_next_week()
def _auto_save_loop(self):
"""Periodically save data."""
import time
while True:
time.sleep(60) # Save every 60 seconds
self.tracker.store.save()
def on_unmount(self):
"""Cleanup on exit."""
if self.screenshot_thread:
self.screenshot_thread.stop()
self.tracker.store.save()
if __name__ == "__main__":
app = TTApp()
app.run()