Changing logic
This commit is contained in:
@@ -38,6 +38,7 @@ class Application:
|
|||||||
self._tracking_thread: Optional[threading.Thread] = None
|
self._tracking_thread: Optional[threading.Thread] = None
|
||||||
self._running = True
|
self._running = True
|
||||||
self.session_start_time: Optional[float] = None
|
self.session_start_time: Optional[float] = None
|
||||||
|
self.idle_start_time: Optional[float] = None
|
||||||
|
|
||||||
# Загружаем задачу
|
# Загружаем задачу
|
||||||
if self.config.current_task_id:
|
if self.config.current_task_id:
|
||||||
@@ -91,6 +92,7 @@ class Application:
|
|||||||
with self._lock:
|
with self._lock:
|
||||||
if not self.tracking_enabled or not self.current_task:
|
if not self.tracking_enabled or not self.current_task:
|
||||||
self.session_start_time = None
|
self.session_start_time = None
|
||||||
|
self.idle_start_time = None
|
||||||
return
|
return
|
||||||
|
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
@@ -99,24 +101,106 @@ class Application:
|
|||||||
is_blocked = self._is_group_blocked(group_name)
|
is_blocked = self._is_group_blocked(group_name)
|
||||||
|
|
||||||
was_idle = self.is_idle
|
was_idle = self.is_idle
|
||||||
|
current_idle = (current_time - self.last_activity > self.config.idle_threshold_seconds) or is_blocked
|
||||||
|
|
||||||
if current_time - self.last_activity > 60 or is_blocked:
|
# === СЛУЧАЙ 1: Переход в бездействие ===
|
||||||
|
if not was_idle and current_idle:
|
||||||
self.is_idle = True
|
self.is_idle = True
|
||||||
|
self.idle_start_time = current_time
|
||||||
self.last_window_group = None
|
self.last_window_group = None
|
||||||
self.session_start_time = None
|
self.session_start_time = None
|
||||||
else:
|
self.maybe_save_task()
|
||||||
|
return
|
||||||
|
|
||||||
|
# === СЛУЧАЙ 2: Выход из бездействия ===
|
||||||
|
if was_idle and not current_idle:
|
||||||
|
self.is_idle = False
|
||||||
|
idle_duration = current_time - self.idle_start_time if self.idle_start_time else 0
|
||||||
|
self.idle_start_time = None
|
||||||
|
|
||||||
|
# Решаем, создавать ли НОВУЮ сессию
|
||||||
|
create_new_session = False
|
||||||
|
reasons = []
|
||||||
|
|
||||||
|
# Причина 1: Длительное бездействие (>10 минут)
|
||||||
|
if idle_duration > self.config.new_session_after_idle_seconds:
|
||||||
|
create_new_session = True
|
||||||
|
reasons.append(f"бездействие {idle_duration / 60:.1f} мин")
|
||||||
|
|
||||||
|
# Причина 2: Смена календарного дня
|
||||||
|
if self.current_task.sessions:
|
||||||
|
last_session_date = self.current_task.sessions[-1].end_time.date()
|
||||||
|
current_date = datetime.now().date()
|
||||||
|
if last_session_date < current_date:
|
||||||
|
create_new_session = True
|
||||||
|
reasons.append(f"смена дня ({last_session_date} → {current_date})")
|
||||||
|
|
||||||
|
# Причина 3: Первая сессия для задачи
|
||||||
|
if not self.current_task.sessions:
|
||||||
|
create_new_session = True
|
||||||
|
reasons.append("первая сессия задачи")
|
||||||
|
|
||||||
|
# Создаём новую сессию при необходимости
|
||||||
|
if create_new_session:
|
||||||
|
new_session = WorkSession(
|
||||||
|
start_time=datetime.now(),
|
||||||
|
end_time=datetime.now(),
|
||||||
|
details=[],
|
||||||
|
synchronized=False
|
||||||
|
)
|
||||||
|
self.current_task.sessions.append(new_session)
|
||||||
|
logger.info(
|
||||||
|
f"Новая сессия для {self.current_task.task_id}: "
|
||||||
|
f"{', '.join(reasons)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Начинаем отслеживание
|
||||||
|
self.session_start_time = current_time
|
||||||
|
self.last_window_group = group_name
|
||||||
|
self._add_work_detail_to_session(group_name, 5.0)
|
||||||
|
return
|
||||||
|
|
||||||
|
# === СЛУЧАЙ 3: Продолжение активной работы ===
|
||||||
|
if not current_idle:
|
||||||
self.is_idle = False
|
self.is_idle = False
|
||||||
if self.last_window_group != group_name:
|
if self.last_window_group != group_name:
|
||||||
self.last_window_group = group_name
|
self.last_window_group = group_name
|
||||||
self._add_work_detail(group_name, 5.0)
|
|
||||||
|
|
||||||
# Начинаем/продолжаем сессию
|
# Гарантируем наличие сессии (на случай редких состояний)
|
||||||
|
if not self.current_task.sessions:
|
||||||
|
self.current_task.sessions.append(WorkSession(
|
||||||
|
start_time=datetime.now(),
|
||||||
|
end_time=datetime.now(),
|
||||||
|
details=[],
|
||||||
|
synchronized=False
|
||||||
|
))
|
||||||
|
|
||||||
|
self._add_work_detail_to_session(group_name, 5.0)
|
||||||
if self.session_start_time is None:
|
if self.session_start_time is None:
|
||||||
self.session_start_time = current_time
|
self.session_start_time = current_time
|
||||||
|
return
|
||||||
|
|
||||||
|
# === СЛУЧАЙ 4: Продолжение бездействия ===
|
||||||
|
self.is_idle = True
|
||||||
|
|
||||||
|
def _add_work_detail_to_session(self, group_name: str, seconds: float):
|
||||||
|
"""Добавляет запись ТОЛЬКО в последнюю сессию (не создаёт новые)"""
|
||||||
|
if not self.current_task or not self.current_task.sessions:
|
||||||
|
logger.warning("Нет активной сессии для добавления времени")
|
||||||
|
return
|
||||||
|
|
||||||
|
session = self.current_task.sessions[-1]
|
||||||
|
|
||||||
|
# Объединяем записи одной группы
|
||||||
|
for detail in session.details:
|
||||||
|
if detail.group_name == group_name:
|
||||||
|
detail.duration_seconds += seconds
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
session.details.append(WorkDetail(group_name=group_name, duration_seconds=seconds))
|
||||||
|
|
||||||
|
session.end_time = datetime.now()
|
||||||
|
|
||||||
# Сохраняем при переходе в бездействие
|
|
||||||
if not was_idle and self.is_idle:
|
|
||||||
self.maybe_save_task()
|
|
||||||
|
|
||||||
def _match_window_to_policy(self, window_info) -> str:
|
def _match_window_to_policy(self, window_info) -> str:
|
||||||
title = window_info.title.lower()
|
title = window_info.title.lower()
|
||||||
@@ -183,9 +267,17 @@ class Application:
|
|||||||
self.config.tracking_enabled = self.tracking_enabled
|
self.config.tracking_enabled = self.tracking_enabled
|
||||||
self._save_config(self.config)
|
self._save_config(self.config)
|
||||||
|
|
||||||
# Сохраняем при переходе в паузу
|
|
||||||
if was_enabled and not self.tracking_enabled:
|
if was_enabled and not self.tracking_enabled:
|
||||||
|
# Переход в паузу → сохраняем и сбрасываем состояние
|
||||||
self.maybe_save_task()
|
self.maybe_save_task()
|
||||||
|
self.is_idle = True
|
||||||
|
self.idle_start_time = time.time()
|
||||||
|
self.session_start_time = None
|
||||||
|
elif not was_enabled and self.tracking_enabled:
|
||||||
|
# Возобновление → сбрасываем состояние бездействия
|
||||||
|
self.is_idle = False
|
||||||
|
self.idle_start_time = None
|
||||||
|
self.session_start_time = time.time()
|
||||||
|
|
||||||
def create_task(self, task_id: str, project_id: Optional[str], estimated_minutes: Optional[float]):
|
def create_task(self, task_id: str, project_id: Optional[str], estimated_minutes: Optional[float]):
|
||||||
with self._lock:
|
with self._lock:
|
||||||
@@ -226,9 +318,30 @@ class Application:
|
|||||||
with self._lock:
|
with self._lock:
|
||||||
if not self.current_task:
|
if not self.current_task:
|
||||||
return
|
return
|
||||||
seconds = abs(minutes) * 60
|
|
||||||
sign = 1 if minutes >= 0 else -1
|
if minutes == 0:
|
||||||
self._add_work_detail("Manual", sign * seconds)
|
return
|
||||||
|
|
||||||
|
# Создаём ОТДЕЛЬНУЮ сессию для ручного времени
|
||||||
|
new_session = WorkSession(
|
||||||
|
start_time=datetime.now(),
|
||||||
|
end_time=datetime.now(),
|
||||||
|
details=[WorkDetail(
|
||||||
|
group_name="Manual Adjustment",
|
||||||
|
duration_seconds=abs(minutes) * 60
|
||||||
|
)],
|
||||||
|
synchronized=False,
|
||||||
|
description=f"Manual: {minutes:+.1f} min"
|
||||||
|
)
|
||||||
|
self.current_task.sessions.append(new_session)
|
||||||
|
logger.info(f"Добавлена ручная сессия: {minutes:+.1f} мин для {self.current_task.task_id}")
|
||||||
|
|
||||||
|
# Сохраняем и синхронизируем
|
||||||
|
self.save_task(self.current_task)
|
||||||
|
try:
|
||||||
|
self.sync_with_youtrack()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Ошибка синхронизации после ручного добавления: {e}")
|
||||||
|
|
||||||
def get_display_status(self) -> str:
|
def get_display_status(self) -> str:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ class TrackerConfig(BaseModel):
|
|||||||
tracking_enabled: bool = False
|
tracking_enabled: bool = False
|
||||||
current_task_id: Optional[str] = None
|
current_task_id: Optional[str] = None
|
||||||
window_policies: List[WindowPolicy] = Field(default_factory=list)
|
window_policies: List[WindowPolicy] = Field(default_factory=list)
|
||||||
|
idle_threshold_seconds: int = 60 # Порог перехода в idle
|
||||||
|
new_session_after_idle_seconds: int = 600 # 10 минут для новой сессии
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_policies() -> List[WindowPolicy]:
|
def default_policies() -> List[WindowPolicy]:
|
||||||
|
|||||||
Reference in New Issue
Block a user