diff --git a/apps/student_app/macos/Podfile.lock b/apps/student_app/macos/Podfile.lock index f34555e..773f001 100644 --- a/apps/student_app/macos/Podfile.lock +++ b/apps/student_app/macos/Podfile.lock @@ -7,12 +7,16 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS + - video_player_avfoundation (0.0.1): + - Flutter + - FlutterMacOS DEPENDENCIES: - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`) EXTERNAL SOURCES: device_info_plus: @@ -23,12 +27,15 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + video_player_avfoundation: + :path: Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin SPEC CHECKSUMS: device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041 flutter_secure_storage_macos: 7f45e30f838cf2659862a4e4e3ee1c347c2b3b54 FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + video_player_avfoundation: 3453f792138786248960ca029747fcd9f318ef52 PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 diff --git a/apps/student_app/pubspec.lock b/apps/student_app/pubspec.lock index bf689f5..173cd02 100644 --- a/apps/student_app/pubspec.lock +++ b/apps/student_app/pubspec.lock @@ -332,10 +332,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.18" material_color_utilities: dependency: transitive description: @@ -348,10 +348,10 @@ packages: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" nested: dependency: transitive description: @@ -577,10 +577,10 @@ packages: dependency: transitive description: name: test_api - sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.9" typed_data: dependency: transitive description: diff --git a/backend/app/Controllers/VideoController.php b/backend/app/Controllers/VideoController.php index fa8e32d..4e0e474 100644 --- a/backend/app/Controllers/VideoController.php +++ b/backend/app/Controllers/VideoController.php @@ -392,6 +392,17 @@ class VideoController $lesson = Database::selectOne("SELECT * FROM lessons WHERE id = ? LIMIT 1", [(int)$rawId]); } elseif (!empty($rawId)) { $lesson = Database::selectOne("SELECT * FROM lessons WHERE title LIKE ? OR local_path LIKE ? OR markdown_content LIKE ? LIMIT 1", ["%{$rawId}%", "%{$rawId}%", "%{$rawId}%"]); + // Flutter curriculum lessons use the manifest slug (e.g. u1_l1_*), + // while the database stores the canonical lesson title. + if (!$lesson) { + $manifestLesson = CurriculumService::findLessonById($rawId); + if ($manifestLesson && !empty($manifestLesson['title'])) { + $lesson = Database::selectOne( + "SELECT * FROM lessons WHERE title = ? OR markdown_content LIKE ? LIMIT 1", + [$manifestLesson['title'], '%' . ($manifestLesson['file'] ?? '') . '%'] + ); + } + } } if (!$lesson) { diff --git a/backend/app/Services/CurriculumService.php b/backend/app/Services/CurriculumService.php index dacb7bd..05db445 100644 --- a/backend/app/Services/CurriculumService.php +++ b/backend/app/Services/CurriculumService.php @@ -192,6 +192,25 @@ class CurriculumService return []; } + /** Resolve a manifest lesson slug to its canonical title/file. */ + public static function findLessonById(string $lessonId): ?array + { + $walk = function ($node) use (&$walk, $lessonId): ?array { + if (!is_array($node)) return null; + if (isset($node['lessons']) && is_array($node['lessons'])) { + foreach ($node['lessons'] as $lesson) { + if (is_array($lesson) && (string)($lesson['id'] ?? '') === $lessonId) return $lesson; + } + } + foreach ($node as $value) { + $found = $walk($value); + if ($found !== null) return $found; + } + return null; + }; + return $walk(self::getCurriculumTree()); + } + /** * Save/Update Complete Curriculum Tree Manifest */