fix(platform): grade-gate student app, isolate per-video resume & checkpoints, remove fake teachers, enhance arabic lab, clean flutter analyze

This commit is contained in:
Hamza-Ayed
2026-09-04 23:41:32 +03:00
parent ae00aa943e
commit e7bc20bc98
22 changed files with 291 additions and 316 deletions
@@ -84,7 +84,7 @@ class CurriculumBakedData {
#### البند 1: حل المعادلات بإخراج العامل المشترك الأكبر
- **قاعدة:** نجعل طرف المعادلة الأيمن صفراً، ثم نخرج العامل المشترك، ونحل المعادلة الناتجة.
- **مثال 1:** حل المعادلة: \$x^3 + 4x^2 = 5x\$
$$\$x^3 + 4x^2 - 5x = 0 \\implies x(x^2 + 4x - 5) = 0 \\implies x(x + 5)(x - 1) = 0\$$
\$\$x^3 + 4x^2 - 5x = 0 \\implies x(x^2 + 4x - 5) = 0 \\implies x(x + 5)(x - 1) = 0\$\$
إذن جذور المعادلة هي: \$\\{-5, 0, 1\\}\$.
- **أتحقق من فهمي (صفحة 9):**
@@ -97,10 +97,10 @@ class CurriculumBakedData {
- **المفهوم:** نقطة تقاطع المستقيم والمنحنى تمثل حل النظام المشترك.
- **طريقة التعويض:** نجعل أحد المتغيرين موضوعاً للقانون في المعادلة الخطية ونعوضه في المعادلة التربيعية.
- **مثال محلول:**
$$\\begin{cases} y - x = 1 \\\\ x^2 + y^2 = 25 \\end{cases}$$
\$\$\\begin{cases} y - x = 1 \\\\ x^2 + y^2 = 25 \\end{cases}\$\$
من المعادلة الأولى: \$y = x + 1\$. نعوض في الثانية:
$$\$x^2 + (x + 1)^2 = 25 \\implies 2x^2 + 2x - 24 = 0 \\implies x^2 + x - 12 = 0\$$
$$\$(x + 4)(x - 3) = 0 \\implies x = 3 \\text{ أو } x = -4\$$
\$\$x^2 + (x + 1)^2 = 25 \\implies 2x^2 + 2x - 24 = 0 \\implies x^2 + x - 12 = 0\$\$
\$\$(x + 4)(x - 3) = 0 \\implies x = 3 \\text{ أو } x = -4\$\$
- عندما \$x = 3 \\implies y = 4\$ (النقطة: \$(3, 4)\$)
- عندما \$x = -4 \\implies y = -3\$ (النقطة: \$( -4, -3)\$)
@@ -144,11 +144,11 @@ class CurriculumBakedData {
---
### السؤال الثاني: حل النظام الجبري التالي وتحقق من صحة الحل (6 علامات)
$$\\begin{cases} y = 2x + 3 \\\\ x^2 + y = 6 \\end{cases}$$
\$\$\\begin{cases} y = 2x + 3 \\\\ x^2 + y = 6 \\end{cases}\$\$
**خطوات الإجابة:**
- نعوض \$y = 2x + 3\$ في المعادلة الثانية:
$$\$x^2 + 2x + 3 = 6 \\implies x^2 + 2x - 3 = 0\$$
\$\$x^2 + 2x + 3 = 6 \\implies x^2 + 2x - 3 = 0\$\$
- التحليل: \$(x + 3)(x - 1) = 0\$.
- إذا \$x = 1 \\implies y = 2(1) + 3 = 5\$ ➔ الحل الأول: \$(1, 5)\$.
- إذا \$x = -3 \\implies y = 2(-3) + 3 = -3\$ ➔ الحل الثاني: \$( -3, -3)\$.
@@ -193,12 +193,12 @@ $$\\begin{cases} y = 2x + 3 \\\\ x^2 + y = 6 \\end{cases}$$
### ضرب المتجهات (Vector Multiplication):
1. **الضرب القياسي / النقطي (Dot Product):**
$$\\vec{A} \\cdot \\vec{B} = |A| |B| \\cos\\phi$$
\$\$\\vec{A} \\cdot \\vec{B} = |A| |B| \\cos\\phi\$\$
- الناتج كمية قياسية (مثل حساب الشغل: \$W = \\vec{F} \\cdot \\vec{d}\$).
- ينعدم الضرب القياسي إذا كان المتجهان متعامدين (\$\\phi = 90^\\circ\$ لأن \$\\cos 90^\\circ = 0\$).
2. **الضرب المتجهي / التقاطعي (Cross Product):**
$$|\\vec{A} \\times \\vec{B}| = |A| |B| \\sin\\phi$$
\$\$|\\vec{A} \\times \\vec{B}| = |A| |B| \\sin\\phi\$\$
- الناتج متجه عمودي على المستوى الذي يحوي المتجهين، ويُحدد اتجاهه باستخدام قاعدة اليد اليمنى.
""";
@@ -243,7 +243,7 @@ $$\\begin{cases} y = 2x + 3 \\\\ x^2 + y = 6 \\end{cases}$$
2. تعليق كتلة \$m_2 = 200\\text{ g}\$ عند زاوية \$90^\\circ\$.
3. اتزان الحلقة في المنتصف بوضع قوة موازنة ثالثة في الربع المقابل بمقدار \$250\\text{ g}\$ وزاوية \$233^\\circ\$.
4. **الاستنتاج:** محصلة قوتين متعامدتين تُحسب بفيثاغورس:
$$R = \\sqrt{F_1^2 + F_2^2} = \\sqrt{150^2 + 200^2} = 250\\text{ gf}$$
\$\$R = \\sqrt{F_1^2 + F_2^2} = \\sqrt{150^2 + 200^2} = 250\\text{ gf}\$\$
""";
// ============================================================================
@@ -224,20 +224,36 @@ class CurriculumLessonItemModel {
}
final filePath = json['file']?.toString();
// Default video availability: true for core Grade 10 subjects (Math, Physics, English) and explicitly tagged lessons
final bool isCoreTenthSubjectLesson = filePath != null && (
filePath.contains('math_10/semester_1') ||
filePath.contains('physics_10/semester_1') ||
filePath.contains('english_10/semester_1') ||
filePath.contains('lesson_01') ||
filePath.contains('lesson_1a')
final jsonId = json['id']?.toString();
// Stable, deterministic lesson ID (vital for persistent per-lesson progress tracking)
final stableId = (jsonId != null && jsonId.isNotEmpty)
? jsonId
: (filePath != null && filePath.isNotEmpty
? filePath.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_')
: 'lesson_${(json['title']?.toString() ?? 'default').hashCode.abs()}');
// Video availability:
// 1. Explicitly false for introductory/project overviews
// 2. Physics & other subjects currently have no video -> false
// 3. Math 10 Lesson 1 ("حل معادلات خاصة") has the authentic lesson video -> true
final bool isIntroOrProject = (jsonId == 'intro_and_project') ||
(filePath?.contains('intro_and_project') ?? false) ||
((json['title']?.toString() ?? '').contains('مقدمة ومشروع'));
final bool isMath10Lesson1 = !isIntroOrProject && (
(filePath != null && filePath.contains('math_10/semester_1/unit_01/lesson_01')) ||
((json['title']?.toString() ?? '').contains('معادلاتٍ خاصّةٍ'))
);
final bool hasVideoExplicit = (json['has_video'] as bool?) ??
((json['video_url'] != null && json['video_url'].toString().isNotEmpty) || isCoreTenthSubjectLesson);
final bool hasVideoExplicit = !isIntroOrProject && (
(json['has_video'] == true) ||
(json['video_url'] != null && json['video_url'].toString().isNotEmpty) ||
isMath10Lesson1
);
return CurriculumLessonItemModel(
id: json['id']?.toString() ?? 'lesson_${DateTime.now().millisecondsSinceEpoch}',
id: stableId,
title: json['title']?.toString() ?? 'درس بدون عنوان',
outcomes: outs,
markdownFilePath: filePath,