Files
TimeTracker/src/citrus_time_tracker/models.py

74 lines
2.3 KiB
Python
Raw Normal View History

2026-03-10 01:40:10 +03:00
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, Field
from typing_extensions import Literal
class WorkDetail(BaseModel):
group_name: str
duration_seconds: float
class WorkSession(BaseModel):
start_time: datetime
end_time: datetime
details: List[WorkDetail]
synchronized: bool = False
class TrackedTask(BaseModel):
task_id: str
project_id: Optional[str] = None
estimated_seconds: Optional[float] = None
start_time: datetime
end_time: Optional[datetime] = None
sessions: List[WorkSession] = Field(default_factory=list)
@property
def total_worked_seconds(self) -> float:
return sum(
detail.duration_seconds
for session in self.sessions
for detail in session.details
)
@property
def remaining_seconds(self) -> Optional[float]:
if self.estimated_seconds is None:
return None
return max(0.0, self.estimated_seconds - self.total_worked_seconds)
class WindowPolicy(BaseModel):
group_name: str
window_patterns: List[str] = Field(default_factory=list)
process_names: List[str] = Field(default_factory=list)
policy_type: Literal["work", "blocked"]
class TrackerConfig(BaseModel):
tracking_enabled: bool = False
current_task_id: Optional[str] = None
window_policies: List[WindowPolicy] = Field(default_factory=list)
@staticmethod
def default_policies() -> List[WindowPolicy]:
return [
WindowPolicy(
group_name="IDE",
window_patterns=["PyCharm", "IntelliJ", "Visual Studio Code", "Code", "Sublime", "Vim", "Neovim"],
process_names=["pycharm64.exe", "idea64.exe", "code.exe", "sublime_text.exe", "nvim.exe", "vim.exe"],
policy_type="work"
),
WindowPolicy(
group_name="Gaming & Distractions",
window_patterns=["Steam", "Discord", "YouTube", "Twitch", "Spotify", "Netflix"],
process_names=["steam.exe", "discord.exe", "spotify.exe"],
policy_type="blocked"
),
]
def __init__(self, **data):
super().__init__(**data)
if not self.window_policies:
self.window_policies = self.default_policies()