LCOV - code coverage report
Current view: top level - lib/exercises/categories/theory/note_placement - theory_page.dart Coverage Total Hit
Test: lcov.info Lines: 0.0 % 80 0
Test Date: 2025-05-10 20:26:13 Functions: - 0 0

            Line data    Source code
       1              : import 'package:amadeus_proto/constants.dart';
       2              : import 'package:amadeus_proto/exercises/categories/theory/note_placement/theory_dragable_item.dart';
       3              : import 'package:amadeus_proto/exercises/categories/theory/note_placement/theory_dragtarget_item.dart';
       4              : import 'package:amadeus_proto/exercises/providers/note_placement_provider.dart';
       5              : import 'package:amadeus_proto/exercises/exercise_question.dart';
       6              : import 'package:amadeus_proto/exercises/load_json.dart';
       7              : import 'package:amadeus_proto/exercises/widget/animation_dialog_wrapper.dart';
       8              : import 'package:amadeus_proto/exercises/widget/exercise_header.dart';
       9              : import 'package:amadeus_proto/exercises/widget/exercises_end_dialog.dart';
      10              : import 'package:amadeus_proto/api/models/exercise_info.dart';
      11              : import 'package:amadeus_proto/widget/progress_bar.dart';
      12              : import 'package:flutter/material.dart';
      13              : import 'package:provider/provider.dart';
      14              : 
      15              : class _AnimatedDialogWrapper extends StatefulWidget {
      16              :   final Widget child;
      17              :   final Animation<double> animation;
      18              : 
      19            0 :   const _AnimatedDialogWrapper({
      20              :     required this.child,
      21              :     required this.animation,
      22              :   });
      23              : 
      24            0 :   @override
      25            0 :   State<_AnimatedDialogWrapper> createState() => _AnimatedDialogWrapperState();
      26              : }
      27              : 
      28              : class _AnimatedDialogWrapperState extends State<_AnimatedDialogWrapper> {
      29              :   bool _isAnimationCompleted = false;
      30              : 
      31            0 :   @override
      32              :   void initState() {
      33            0 :     super.initState();
      34            0 :     widget.animation.addStatusListener((status) {
      35            0 :       if (status == AnimationStatus.completed) {
      36            0 :         setState(() {
      37            0 :           _isAnimationCompleted = true;
      38              :         });
      39              :       }
      40              :     });
      41              :   }
      42              : 
      43            0 :   @override
      44              :   Widget build(BuildContext context) {
      45            0 :     return AbsorbPointer(
      46              :       absorbing:
      47            0 :           !_isAnimationCompleted, // Disable clicks until animation completes
      48            0 :       child: widget.child,
      49              :     );
      50              :   }
      51              : }
      52              : 
      53              : class TheoryExercise extends StatefulWidget {
      54            0 :   const TheoryExercise(
      55              :       {super.key,
      56              :       required this.info});
      57              : 
      58              :   final ExerciseInfo info;
      59              : 
      60            0 :   @override
      61            0 :   State<TheoryExercise> createState() => _TheoryExerciseState();
      62              : }
      63              : 
      64              : class _TheoryExerciseState extends State<TheoryExercise> {
      65            0 :   @override
      66              :   void initState() {
      67            0 :     super.initState();
      68            0 :     WidgetsBinding.instance.addPostFrameCallback((_) {
      69            0 :       context.read<NotePlacementProvider>().reset();
      70              :     });
      71              :   }
      72              : 
      73              :   /// The implementation of [TheoryExercise.build]
      74              :   ///
      75              :   /// The build is composed by a FutureBuilder that will wait for the data
      76              :   /// from the [loadJsonData] asynchronous function to collect the data
      77              :   /// from the specific JSON file
      78              :   ///
      79              :   /// This widget display an theory exercise with a header [ExerciseHeader],
      80              :   /// a description [ExerciseQuestion], an image that correspond to the
      81              :   /// actual question, and finally a [SingleChoiceExercise] with multiples
      82              :   /// dragable item.
      83              :   ///
      84              :   /// This widget is a drag and drop exercise, when we need to drag the right
      85              :   /// [DragableItem] that stocks data, and drop it to the corresponding
      86              :   /// [DragTargetItem].
      87              :   ///
      88              :   /// All those is data, is initialize by the corresponding JSON file and is
      89              :   /// load by the corresponding [ExerciseProvider], in this case, the provider
      90              :   /// is [NotePlacementProvider]
      91            0 :   @override
      92              :   Widget build(BuildContext context) {
      93            0 :     final NotePlacementProvider theory = context.watch<NotePlacementProvider>();
      94              : 
      95            0 :     WidgetsBinding.instance.addPostFrameCallback((_) {
      96            0 :       if (!theory.isInitialized) {
      97            0 :         theory.initializeData(widget.info.exerciseData);
      98            0 :         theory.exerciseInfo = widget.info;
      99              :       }
     100            0 :       if (!theory.displayDialog && theory.checkEndGame()) {
     101            0 :         theory.displayDialog = true;
     102            0 :         Future.delayed(Duration.zero, () {
     103            0 :           if (!context.mounted) return;
     104            0 :           showGeneralDialog(
     105              :               context: context,
     106              :               transitionDuration: const Duration(milliseconds: fastAnimation),
     107            0 :               pageBuilder: (context, animation1, animation2) {
     108            0 :                 return ExerciseEndDialog<NotePlacementProvider>(
     109            0 :                   leavingExerciseCallback: () {
     110            0 :                     Navigator.of(context).pop();
     111            0 :                     Navigator.of(context).pop();
     112              :                   },
     113            0 :                   resetExerciseCallback: () {
     114            0 :                     Navigator.of(context).pop();
     115            0 :                     Future.delayed(const Duration(milliseconds: fastAnimation),
     116            0 :                         () {
     117            0 :                       if (mounted) {
     118            0 :                         theory.reset();
     119              :                       }
     120              :                     });
     121              :                   },
     122            0 :                   exerciseTitle: widget.info.exerciseData!["title"],
     123            0 :                   exerciseCategory: widget.info.exerciseData!["category"],
     124              :                 );
     125              :               },
     126              :               transitionBuilder:
     127            0 :                   (context, animation, secondaryAnimation, child) {
     128            0 :                 return ScaleTransition(
     129              :                   scale: animation,
     130            0 :                   child: AnimatedDialogWrapper(
     131              :                     animation: animation,
     132              :                     child: child,
     133              :                   ),
     134              :                 );
     135              :               });
     136              :         });
     137              :       }
     138              :     });
     139              : 
     140            0 :     return Scaffold(
     141              :         backgroundColor: Colors.white,
     142            0 :         body: SafeArea(
     143            0 :           child: Column(children: [
     144            0 :             if (theory.isInitialized)
     145            0 :               const ExerciseHeader<NotePlacementProvider>(),
     146            0 :             const SizedBox(
     147              :               height: 10,
     148              :             ),
     149            0 :             if (theory.isInitialized)
     150            0 :               ProgressBar(
     151            0 :                   totalAmount: theory.questions.length,
     152            0 :                   progressAmount: theory.progressRatio(),
     153              :                   width: 300,
     154              :                   height: 15),
     155            0 :             const SizedBox(
     156              :               height: 10,
     157              :             ),
     158            0 :             if (theory.isInitialized)
     159            0 :               const ExerciseQuestion<NotePlacementProvider>(),
     160            0 :             const Spacer(),
     161            0 :             if (theory.isInitialized)
     162            0 :               Image(
     163            0 :                 image: AssetImage(theory.questions[theory.index]),
     164              :                 width: imageAssetWidth,
     165              :                 height: imageAssetHeight,
     166              :               ),
     167            0 :             if (theory.isInitialized)
     168            0 :               Wrap(
     169              :                   spacing: 200,
     170              :                   alignment: WrapAlignment.spaceAround,
     171            0 :                   children: List.generate(
     172              :                       2,
     173            0 :                       (_) => DragTargetItem(
     174            0 :                             imagePath: theory.answerData[theory.index]
     175            0 :                                 ["imagePath"],
     176            0 :                             answer: theory.answerData[theory.index]["choice"],
     177              :                           ))),
     178            0 :             const Spacer(),
     179            0 :             if (theory.isInitialized)
     180            0 :               Wrap(
     181              :                   spacing: 25,
     182              :                   crossAxisAlignment: WrapCrossAlignment.center,
     183            0 :                   children: List.generate(
     184            0 :                     theory.choices.length,
     185            0 :                     (index) => DragableItem(
     186            0 :                         imagePath: theory.choicesPath[index],
     187            0 :                         data: theory.choices[index]),
     188              :                   )),
     189            0 :             const Spacer()
     190              :           ]),
     191              :         ));
     192              :   }
     193              : }
        

Generated by: LCOV version 2.3-1