282 lines
9.8 KiB
Dart
282 lines
9.8 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:collection/collection.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:mnemo_cards/features/tests/test_manager.dart';
|
|
import 'package:mnemo_cards/features/tests/test_widgets/test_image.dart';
|
|
import 'package:mnemo_cards/theme/themes.dart';
|
|
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|
import 'package:collection/collection.dart';
|
|
import '../../../di/locator.dart';
|
|
import '../../../widgets/game_card_widget.dart';
|
|
import '../question_states/input_buttons_test_state.dart';
|
|
import 'test_button.dart';
|
|
|
|
class InputButtonsTestWidget extends StatelessWidget {
|
|
bool get isCorrect => state.answer.join() == model.answer;
|
|
final InputButtonsTestQuestionBody _inputButtonModel;
|
|
|
|
InputButtonsTestQuestionBody get model => _inputButtonModel;
|
|
|
|
InputButtonsTestState get state =>
|
|
manager.getState(model.id!) as InputButtonsTestState;
|
|
|
|
TestManager get manager => locator.testManager;
|
|
|
|
Color get testColor => manager.color;
|
|
|
|
InputButtonsTestWidget(this._inputButtonModel, {super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context).textTheme;
|
|
// final random = Random(state.seed);
|
|
final buttons = model.buttons; //..shuffle(random);
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: LayoutBuilder(builder: (context, constraints) {
|
|
return Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
if (model.image != null)
|
|
Container(
|
|
margin: const EdgeInsets.all(4.0),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius:
|
|
BorderRadius.circular(16.0),
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
AspectRatio(
|
|
aspectRatio: 1,
|
|
child: TestImageWidget(
|
|
TestImage.image(model.image!),
|
|
),
|
|
),
|
|
if (model.text != null)
|
|
Container(
|
|
padding: EdgeInsets.only(top: 8.0),
|
|
child: Center(
|
|
child: Text(
|
|
model.text!,
|
|
style: theme.headlineLarge,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
else Flexible(
|
|
child: Center(
|
|
child: Text(
|
|
model.text!,
|
|
style: theme.headlineLarge,
|
|
),
|
|
),
|
|
),
|
|
StatefulBuilder(builder: (context, setState) {
|
|
void buttonTapped(int index, TestButtonDto button) {
|
|
if (state.answer.fold(0, (p, n) => p + n.length) >=
|
|
model.answer.length) {
|
|
return;
|
|
}
|
|
setState(() {
|
|
var answer = [...state.answer, button.text!];
|
|
final ignoreSpaces = true;
|
|
if (ignoreSpaces &&
|
|
model.answer.length > answer.length &&
|
|
model.answer[answer.length] == ' ') {
|
|
answer.add(' ');
|
|
}
|
|
manager.setState(
|
|
model.id!,
|
|
state.copyWith(
|
|
answer: answer,
|
|
answerIds: [...state.answerIds, button.id],
|
|
),
|
|
);
|
|
manager.setState(
|
|
model.id!,
|
|
state.copyWith(
|
|
isAnswered: isCorrect,
|
|
isCorrect: isCorrect,
|
|
),
|
|
);
|
|
});
|
|
print('${state.answer} ${model.answer} ${state.isCorrect}');
|
|
if (isCorrect) {
|
|
Future.delayed(
|
|
Duration(milliseconds: 300),
|
|
manager.nextTest,
|
|
);
|
|
}
|
|
}
|
|
|
|
int splitIndex = 0;
|
|
if (model.answer.length * 30 > constraints.maxWidth * 0.9) {
|
|
splitIndex = model.answer.indexOf(
|
|
' ',
|
|
(model.answer.length / 2).ceil(),
|
|
);
|
|
if (splitIndex < 10) {
|
|
splitIndex = model.answer.indexOf(
|
|
' ',
|
|
(model.answer.length / 3).ceil(),
|
|
);
|
|
}
|
|
if (splitIndex == -1) {
|
|
splitIndex = model.answer.indexOf(
|
|
' ',
|
|
0,
|
|
);
|
|
}
|
|
}
|
|
if (splitIndex < 0) {
|
|
splitIndex = 0;
|
|
}
|
|
|
|
final letters = model.answer
|
|
.split('')
|
|
.mapIndexed(
|
|
(index, letter) => letter == ' '
|
|
? SizedBox(width: 10)
|
|
: _Letter(
|
|
text: state.answer.length > index
|
|
? state.answer[index]
|
|
: ' ',
|
|
color: testColor,
|
|
),
|
|
)
|
|
.toList();
|
|
final rows = [
|
|
if (splitIndex > 0)
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 8.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: letters.sublist(0, splitIndex),
|
|
),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: letters.sublist(splitIndex),
|
|
)
|
|
];
|
|
|
|
return Expanded(
|
|
child: Column(
|
|
children: [
|
|
Expanded(
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
var answer = state.answer.toList();
|
|
var answerIds = state.answerIds.toList();
|
|
if (answer.isNotEmpty) {
|
|
if (answer.last == ' ') {
|
|
answer.removeLast();
|
|
}
|
|
if (answer.isNotEmpty) {
|
|
answer.removeLast();
|
|
answerIds.removeLast();
|
|
}
|
|
}
|
|
setState(() {
|
|
manager.setState(
|
|
model.id!,
|
|
state.copyWith(
|
|
// isAnswered: false,
|
|
// isCorrect: false,
|
|
answer: answer,
|
|
answerIds: answerIds,
|
|
),
|
|
);
|
|
});
|
|
},
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: rows,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(
|
|
height: 16.0,
|
|
),
|
|
AbsorbPointer(
|
|
absorbing: state.isCorrect,
|
|
child: Wrap(
|
|
children: [
|
|
...buttons.mapIndexed(
|
|
(index, button) => Container(
|
|
margin: EdgeInsets.all(4.0),
|
|
width: button.text!.length > 3
|
|
? null
|
|
: constraints.maxWidth / 6,
|
|
height: 50,
|
|
child: state.answerIds.contains(button.id)
|
|
? SizedBox.shrink()
|
|
: TestButton(
|
|
text: button.text,
|
|
onTap: () => buttonTapped(index, button),
|
|
color: state.answer == button
|
|
? isCorrect
|
|
? Colors.green[200]
|
|
: Colors.red[200]
|
|
: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
})
|
|
],
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _Letter extends StatelessWidget {
|
|
final String text;
|
|
final Color? color;
|
|
|
|
_Letter({this.text = '', this.color});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
width: 30,
|
|
height: 45,
|
|
margin: const EdgeInsets.all(2.0),
|
|
padding: const EdgeInsets.all(5.0),
|
|
clipBehavior: Clip.antiAlias,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(6.0),
|
|
border: Border.all(color: color ?? borderGray),
|
|
boxShadow: const [
|
|
// BoxShadow(
|
|
// color: Colors.black26,
|
|
// blurRadius: 4.0,
|
|
// ),
|
|
],
|
|
),
|
|
child: Material(
|
|
color: Colors.white,
|
|
child: Text(
|
|
text,
|
|
style: Theme.of(context).textTheme.titleLarge,
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|