197 lines
6.5 KiB
Dart
197 lines
6.5 KiB
Dart
import 'dart:developer';
|
|
import 'dart:math' as math;
|
|
|
|
import 'package:auto_route/auto_route.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:mnemo_cards/main.dart';
|
|
import 'package:mnemo_cards/managers/audio_player.dart';
|
|
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|
import 'package:rxdart/rxdart.dart';
|
|
|
|
import '../../di/locator.dart';
|
|
import 'scroll_physics.dart';
|
|
import 'test_complete_widget.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;
|
|
|
|
int? lastSkipIndex;
|
|
int? _lastAudioQuestionId;
|
|
|
|
@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() {
|
|
if (!pageController.hasClients) {
|
|
return;
|
|
}
|
|
final index = pageController.page!.floor();
|
|
print('Current index $index, lastAudio $_lastAudioQuestionId');
|
|
|
|
if (index < locator.testManager.questions.length) {
|
|
final question = locator.testManager.questions[index];
|
|
if (question.id != _lastAudioQuestionId) {
|
|
print('AUDIO $_lastAudioQuestionId ${question.id}');
|
|
_lastAudioQuestionId = question.id;
|
|
try {
|
|
if (globalSharedPreferences.getBool('auto_play_sound_tests') !=
|
|
false) {
|
|
AudioPlayer.playAudio((question as dynamic).audio);
|
|
}
|
|
} catch (e, s) {}
|
|
}
|
|
}
|
|
|
|
if (index == lastSkipIndex) {
|
|
return;
|
|
}
|
|
print('Will try to skip $index, ${locator.testManager.questions.length}');
|
|
if (index > 0 && index <= locator.testManager.questions.length) {
|
|
final prevId = locator.testManager.questions[index - 1].id!;
|
|
final state = locator.testManager.getState(prevId);
|
|
if (state?.isAnswered == false) {
|
|
print('Skipping $index ${state?.word}');
|
|
locator.testManager.skip(prevId);
|
|
lastSkipIndex = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: Colors.white,
|
|
body: StreamBuilder(
|
|
stream: locator.testManager.testHolder.asStream.takeWhileInclusive(
|
|
(state) => state?.questions.isNotEmpty != true,
|
|
),
|
|
builder: (context, s) {
|
|
if (!s.hasData || s.requireData!.questions.isEmpty) {
|
|
return Scaffold(
|
|
body: Center(
|
|
child: Text('Загружаю тест...'),
|
|
),
|
|
);
|
|
}
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_pageScrollListener();
|
|
});
|
|
|
|
final keys = List.generate(
|
|
locator.testManager.questions.length,
|
|
(v) =>
|
|
GlobalKey(debugLabel: locator.testManager.questions[v].word),
|
|
);
|
|
|
|
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(
|
|
canScroll: _canScroll,
|
|
),
|
|
controller: locator.testManager.pageController,
|
|
itemBuilder: (context, index) {
|
|
if (index > locator.testManager.questions.length) {
|
|
return null;
|
|
}
|
|
if (index == locator.testManager.questions.length) {
|
|
return TestCompleteWidget(
|
|
locator.testManager.states,
|
|
locator.testManager.color,
|
|
);
|
|
}
|
|
final question = locator.testManager.getTest(index);
|
|
return switch (question.questionType) {
|
|
TestQuestionType.simple => SimpleTestWidget(
|
|
question as SimpleTestQuestionBody,
|
|
key: keys[index],
|
|
),
|
|
TestQuestionType.input_buttons =>
|
|
InputButtonsTestWidget(
|
|
question as InputButtonsTestQuestionBody,
|
|
key: keys[index]),
|
|
TestQuestionType.matrix => Container(),
|
|
TestQuestionType.match => Container(),
|
|
// TODO: Handle this case.
|
|
TestQuestionType.undefined =>
|
|
throw UnimplementedError(),
|
|
};
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
bool _canScroll() {
|
|
return locator.testManager.pageController.hasClients &&
|
|
locator.testManager.pageController.page !=
|
|
locator.testManager.questions.length;
|
|
}
|
|
}
|
|
|
|
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),
|
|
)
|
|
],
|
|
);
|
|
}
|
|
}
|