Spaces:
Running
Running
| """ | |
| 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 |