divid_teacher / focus_timer_manager.py
Asem75's picture
Create focus_timer_manager.py
c940bea verified
Raw
History Blame Contribute Delete
13.5 kB
"""
focus_timer_manager.py
مدير مؤقت التركيز Pomodoro في منصة Divid Teacher
مسؤول عن:
- جلسة دراسة 25 دقيقة
- استراحة قصيرة 5 دقائق
- استراحة طويلة بعد كل 4 جلسات
- تحديد أصوات البداية والنهاية
- حفظ تقدم الطالب في جلسات التركيز
"""
from datetime import datetime, timedelta
from pathlib import Path
from student_manager import StudentManager
try:
from config import ASSETS_FOLDER
except Exception:
ASSETS_FOLDER = "assets"
class FocusTimerManager:
def __init__(self):
self.student_manager = StudentManager()
self.assets_folder = Path(ASSETS_FOLDER)
self.sounds_folder = self.assets_folder / "sounds"
self.sounds_folder.mkdir(parents=True, exist_ok=True)
self.default_settings = {
"study_minutes": 25,
"short_break_minutes": 5,
"long_break_minutes": 15,
"long_break_after_sessions": 4,
"enabled": True,
"use_sound": True,
"use_voice_message": True
}
self.sound_files = {
"pomodoro_start": str(self.sounds_folder / "pomodoro_start.mp3"),
"pomodoro_end": str(self.sounds_folder / "pomodoro_end.mp3"),
"break_start": str(self.sounds_folder / "break_start.mp3"),
"break_end": str(self.sounds_folder / "break_end.mp3"),
"long_break": str(self.sounds_folder / "long_break.mp3")
}
# ======================================================
# الوقت
# ======================================================
def now(self):
return datetime.utcnow()
def now_text(self):
return self.now().isoformat()
# ======================================================
# تجهيز ملف التركيز داخل الطالب
# ======================================================
def ensure_focus_profile(self, student):
if "focus_timer" not in student or not isinstance(student["focus_timer"], dict):
student["focus_timer"] = {}
if "settings" not in student["focus_timer"]:
student["focus_timer"]["settings"] = self.default_settings.copy()
if "sessions" not in student["focus_timer"]:
student["focus_timer"]["sessions"] = []
if "current_session" not in student["focus_timer"]:
student["focus_timer"]["current_session"] = None
if "completed_pomodoros" not in student["focus_timer"]:
student["focus_timer"]["completed_pomodoros"] = 0
if "today_pomodoros" not in student["focus_timer"]:
student["focus_timer"]["today_pomodoros"] = 0
if "last_session_at" not in student["focus_timer"]:
student["focus_timer"]["last_session_at"] = ""
return student
def save_student(self, student):
return self.student_manager.save_student(student)
# ======================================================
# جلب الإعدادات
# ======================================================
def get_settings(self, identity=None):
if identity:
student = self.student_manager.get_student(identity)
if student:
student = self.ensure_focus_profile(student)
return student["focus_timer"]["settings"]
return self.default_settings.copy()
def update_settings(
self,
identity,
study_minutes=25,
short_break_minutes=5,
long_break_minutes=15,
long_break_after_sessions=4,
enabled=True
):
student = self.student_manager.get_student(identity)
if not student:
return None
student = self.ensure_focus_profile(student)
student["focus_timer"]["settings"] = {
"study_minutes": int(study_minutes),
"short_break_minutes": int(short_break_minutes),
"long_break_minutes": int(long_break_minutes),
"long_break_after_sessions": int(long_break_after_sessions),
"enabled": bool(enabled),
"use_sound": True,
"use_voice_message": True
}
self.save_student(student)
return student["focus_timer"]["settings"]
# ======================================================
# بدء جلسة تركيز
# ======================================================
def start_pomodoro(
self,
identity,
subject="",
lesson_title="",
plan_type="A"
):
student = self.student_manager.get_student(identity)
if not student:
return {
"success": False,
"message": "لم يتم العثور على الطالب.",
"session": None
}
student = self.ensure_focus_profile(student)
settings = student["focus_timer"]["settings"]
start_time = self.now()
end_time = start_time + timedelta(
minutes=int(settings.get("study_minutes", 25))
)
session_number = len(student["focus_timer"]["sessions"]) + 1
session = {
"session_id": f"pomodoro_{session_number}",
"type": "study",
"status": "active",
"subject": subject,
"lesson_title": lesson_title,
"plan_type": plan_type,
"start_time": start_time.isoformat(),
"expected_end_time": end_time.isoformat(),
"actual_end_time": "",
"duration_minutes": int(settings.get("study_minutes", 25)),
"sound_on_start": self.sound_files["pomodoro_start"],
"sound_on_end": self.sound_files["pomodoro_end"],
"voice_message_start": "بدأت جلسة التركيز. حاول أن تركز بهدوء.",
"voice_message_end": "أحسنت، انتهت جلسة التركيز. خذ استراحة قصيرة."
}
student["focus_timer"]["current_session"] = session
student["focus_timer"]["sessions"].append(session)
student["focus_timer"]["last_session_at"] = self.now_text()
self.save_student(student)
return {
"success": True,
"message": "تم بدء جلسة التركيز.",
"session": session
}
# ======================================================
# إنهاء جلسة التركيز
# ======================================================
def finish_current_session(self, identity):
student = self.student_manager.get_student(identity)
if not student:
return {
"success": False,
"message": "لم يتم العثور على الطالب.",
"next": None
}
student = self.ensure_focus_profile(student)
current = student["focus_timer"].get("current_session")
if not current:
return {
"success": False,
"message": "لا توجد جلسة نشطة.",
"next": None
}
current["status"] = "completed"
current["actual_end_time"] = self.now_text()
student["focus_timer"]["completed_pomodoros"] += 1
student["focus_timer"]["today_pomodoros"] += 1
completed_count = student["focus_timer"]["completed_pomodoros"]
settings = student["focus_timer"]["settings"]
long_after = int(settings.get("long_break_after_sessions", 4))
if completed_count % long_after == 0:
next_break = self.build_break_session(
student=student,
break_type="long_break"
)
else:
next_break = self.build_break_session(
student=student,
break_type="short_break"
)
student["focus_timer"]["current_session"] = next_break
student["focus_timer"]["sessions"].append(next_break)
self.save_student(student)
return {
"success": True,
"message": "تم إنهاء جلسة التركيز.",
"next": next_break
}
# ======================================================
# بناء الاستراحة
# ======================================================
def build_break_session(self, student, break_type="short_break"):
settings = student["focus_timer"]["settings"]
if break_type == "long_break":
minutes = int(settings.get("long_break_minutes", 15))
sound = self.sound_files["long_break"]
message_start = "أنهيت أربع جلسات تركيز. تستحق استراحة أطول."
message_end = "انتهت الاستراحة الطويلة. نعود بهدوء."
else:
minutes = int(settings.get("short_break_minutes", 5))
sound = self.sound_files["break_start"]
message_start = "بدأت الاستراحة القصيرة."
message_end = "انتهت الاستراحة. نعود للدرس."
start_time = self.now()
end_time = start_time + timedelta(minutes=minutes)
session_number = len(student["focus_timer"]["sessions"]) + 1
return {
"session_id": f"{break_type}_{session_number}",
"type": break_type,
"status": "active",
"start_time": start_time.isoformat(),
"expected_end_time": end_time.isoformat(),
"actual_end_time": "",
"duration_minutes": minutes,
"sound_on_start": sound,
"sound_on_end": self.sound_files["break_end"],
"voice_message_start": message_start,
"voice_message_end": message_end
}
# ======================================================
# إنهاء الاستراحة
# ======================================================
def finish_break(self, identity):
student = self.student_manager.get_student(identity)
if not student:
return {
"success": False,
"message": "لم يتم العثور على الطالب."
}
student = self.ensure_focus_profile(student)
current = student["focus_timer"].get("current_session")
if not current:
return {
"success": False,
"message": "لا توجد استراحة نشطة."
}
if current.get("type") not in ["short_break", "long_break"]:
return {
"success": False,
"message": "الجلسة الحالية ليست استراحة."
}
current["status"] = "completed"
current["actual_end_time"] = self.now_text()
student["focus_timer"]["current_session"] = None
self.save_student(student)
return {
"success": True,
"message": "تم إنهاء الاستراحة.",
"voice_message": current.get("voice_message_end", "")
}
# ======================================================
# حالة المؤقت
# ======================================================
def get_timer_status(self, identity):
student = self.student_manager.get_student(identity)
if not student:
return {
"exists": False,
"message": "لم يتم العثور على الطالب."
}
student = self.ensure_focus_profile(student)
current = student["focus_timer"].get("current_session")
return {
"exists": True,
"current_session": current,
"completed_pomodoros": student["focus_timer"].get("completed_pomodoros", 0),
"today_pomodoros": student["focus_timer"].get("today_pomodoros", 0),
"settings": student["focus_timer"].get("settings", {})
}
# ======================================================
# تنسيق للعرض
# ======================================================
def format_timer_status(self, identity):
status = self.get_timer_status(identity)
if not status.get("exists"):
return status.get("message", "لا توجد بيانات.")
current = status.get("current_session")
text = f"""
# مؤقت التركيز Pomodoro
عدد جلسات اليوم: {status.get("today_pomodoros", 0)}
عدد الجلسات الكلي: {status.get("completed_pomodoros", 0)}
"""
if current:
text += f"""
## الجلسة الحالية
النوع: {current.get("type", "")}
الحالة: {current.get("status", "")}
البداية: {current.get("start_time", "")}
النهاية المتوقعة: {current.get("expected_end_time", "")}
المدة: {current.get("duration_minutes", "")} دقيقة
رسالة البداية:
{current.get("voice_message_start", "")}
رسالة النهاية:
{current.get("voice_message_end", "")}
"""
else:
text += "\nلا توجد جلسة نشطة حاليًا."
return text.strip()
# ======================================================
# مسارات الأصوات
# ======================================================
def get_sound_files(self):
return self.sound_files