230 lines
9.3 KiB
Dart
230 lines
9.3 KiB
Dart
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<StatefulWidget> createState() => _TestPageState();
|
||
|
||
TestPage(this.testId);
|
||
}
|
||
|
||
class _TestPageState extends State<TestPage> {
|
||
|
||
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),
|
||
)
|
||
],
|
||
);
|
||
}
|
||
}
|