import 'dart:developer'; import 'dart:math' as math; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:mnemo_cards/features/tests/question_states/test_question_state.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:pie_chart/pie_chart.dart'; import '../../di/locator.dart'; import 'scroll_physics.dart'; import 'test_progress_widget.dart'; import 'test_widgets/input_buttons_test.dart'; import 'test_widgets/simple_test.dart'; @RoutePage() class TestPage extends StatefulWidget { final String testId; @override State createState() => _TestPageState(); TestPage(this.testId); } class _TestPageState extends State { PageController get pageController => locator.testManager.pageController; @override void initState() { super.initState(); locator.testManager.setActiveTest(widget.testId); locator.testManager.preloadImages(context); pageController.addListener(_pageScrollListener); } @override void dispose() { pageController.removeListener(_pageScrollListener); super.dispose(); } void _pageScrollListener() { final index = pageController.page?.floor() ?? 0; if (index > 0) { final prevId = locator.testManager.questions[index - 1].id!; final state = locator.testManager.getState(prevId); if (state?.isAnswered == false) { log('Question skipped'); locator.testManager.skip(prevId); } } } int lastTestIndex = 0; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: StreamBuilder( stream: locator.testManager.testHolder.asStream, builder: (context, s) { if (!s.hasData || s.requireData!.questions.isEmpty) { return Scaffold( body: Center( child: Text('Загружаю тест...'), ), ); } return Scaffold( backgroundColor: locator.testManager.color.withOpacity(0.25), body: SafeArea( child: Builder(builder: (context) { return Column( children: [ SizedBox( height: (64.h - 20.h - MediaQuery.of(context).padding.top) / 2, ), Padding( padding: EdgeInsets.symmetric(horizontal: 10.0.w), child: const TestProgressWidget(), ), Expanded( child: PageView.builder( physics: RightBlockedScrollPhysics(), controller: locator.testManager.pageController, itemBuilder: (context, index) { if (index > locator.testManager.questions.length) { return null; } if (index == locator.testManager.questions.length) { return Column( children: [ Expanded( child: PieChart( dataMap: { 'Правильно': locator.testManager.states .where((e) => e.isCorrect) .length .toDouble(), 'Ошибка': locator.testManager.states .where((e) => !e.isCorrect && e.isAnswered) .length .toDouble(), 'Пропущено': locator.testManager.states .where((e) => !e.isAnswered) .length .toDouble(), }, animationDuration: Duration(milliseconds: 800), chartLegendSpacing: 32, chartRadius: MediaQuery.of(context).size.width / 3.2, colorList: [ Colors.lightGreenAccent[200]!, Colors.redAccent[100]!, Colors.white, ], initialAngleInDegree: 0, chartType: ChartType.ring, ringStrokeWidth: 32, legendOptions: LegendOptions( showLegendsInRow: false, legendPosition: LegendPosition.right, showLegends: true, legendShape: BoxShape.circle, legendTextStyle: TextStyle( fontWeight: FontWeight.bold, ), ), chartValuesOptions: ChartValuesOptions( showChartValueBackground: false, showChartValues: true, showChartValuesOutside: false, decimalPlaces: 0, chartValueStyle: Theme.of(context) .textTheme .titleMedium!, ), ), ), Center( child: Padding( padding: const EdgeInsets.all(8.0), child: InkWell( onTap: () { AutoRouter.of(context).maybePop(); }, child: Container( alignment: Alignment.center, padding: const EdgeInsets.all(8.0), color: locator.testManager.color, height: 60, child: FittedBox( child: Text( 'В меню', style: Theme.of(context) .textTheme .titleMedium, )), ), ), ), ), ], ); } lastTestIndex = math.max(index, lastTestIndex); return switch (locator.testManager .getTest(index) .questionType) { TestQuestionType.simple => SimpleTestWidget( locator.testManager.getTest(index) as SimpleTestQuestionBody, ), TestQuestionType.input_buttons => InputButtonsTestWidget( locator.testManager.getTest(index) as InputButtonsTestQuestionBody, ), TestQuestionType.matrix => Container(), TestQuestionType.match => Container(), // TODO: Handle this case. TestQuestionType.undefined => throw UnimplementedError(), }; }, ), ), ], ); }), ), ); }), ); } } class _LifeWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.max, children: [ Icon(Icons.ac_unit_outlined), SizedBox( width: 2, ), Text( '30', style: TextStyle(fontSize: 22), ) ], ); } }