2025-03-11 21:17:14 +08:00

165 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:lamiter/Class/Question/question.dart';
import 'package:lamiter/Class/Question/question_layout_attributes.dart';
import 'package:lamiter/Extension/build_context.dart';
import 'package:lamiter/Component/q_title.dart';
import 'package:lamiter/Provider/Form/form_provider.dart';
import 'package:lamiter/Provider/Language/language_provider.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class SCQ<T extends FormProvider> extends Question<SCQAnswer> {
final GlobalKey<SCQLayoutState> SCQKey = GlobalKey<SCQLayoutState>();
final SCQLayoutAttributes attributes;
SCQ({
super.key,
required super.id,
required super.required,
super.answer,
required this.attributes,
});
@override
void setAnswerLayout(SCQAnswer? _answer) {
if (_answer == null) return;
answer = _answer;
SCQKey.currentState?.setAnswer(_answer);
}
@override
void lockAnswerLayouot() {
SCQKey.currentState?.lockAnswer();
}
@override
Widget build(BuildContext context) {
void layoutSetAnswer(SCQAnswer? layoutAnswer) {
answer = layoutAnswer;
context.read<T>().refresh();
}
return _Layout(
key: SCQKey,
attributes: attributes,
setAnswer: layoutSetAnswer,
);
}
}
class SCQLayoutAttributes extends QuestionLayoutAttributes {
final List<String> options;
final List<int> scores;
SCQLayoutAttributes({
super.title,
required super.required,
required this.options,
required this.scores,
});
}
class _Layout extends StatefulWidget {
// Single choice question
final SCQLayoutAttributes attributes;
final Function(SCQAnswer?) setAnswer;
const _Layout({
super.key,
required this.attributes,
required this.setAnswer,
});
@override
State<_Layout> createState() => SCQLayoutState();
}
class SCQLayoutState extends State<_Layout> with AutomaticKeepAliveClientMixin {
bool _readOnly = false;
SCQAnswer? _answer;
void setAnswer(SCQAnswer? answer) {
_answer = answer;
setState(() {});
}
void lockAnswer() {
_readOnly = true;
setState(() {});
}
@override
Widget build(BuildContext context) {
super.build(context);
final languageProvider = Provider.of<LanguageProvider>(context);
return Form(
child: Column(
children: [
// question title
widget.attributes.title != null && widget.attributes.title!.isNotEmpty
? QTitle(
title: languageProvider
.getLocaleString(widget.attributes.title!),
readOnly: _readOnly,
required: widget.attributes.required,
)
: const SizedBox.shrink(),
// answer TextField
IgnorePointer(
ignoring: _readOnly,
child: DropdownButtonFormField(
items: List.generate(widget.attributes.options.length, (index) {
return DropdownMenuItem<SCQAnswer>(
value: SCQAnswer(
index: index,
score: widget.attributes.scores[index],
),
child: Text(
languageProvider
.getLocaleString(widget.attributes.options[index]),
softWrap: true,
overflow: TextOverflow.ellipsis,
),
);
}),
value: _answer,
decoration: InputDecoration(
isDense: true,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: context.primary.withOpacity(0.35),
),
),
),
onChanged: (SCQAnswer? answer) {
setAnswer(answer);
widget.setAnswer(answer);
},
),
),
],
),
);
}
@override
bool get wantKeepAlive => true;
}
class SCQAnswer {
int index;
int score;
SCQAnswer({required this.index, required this.score});
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is SCQAnswer && other.index == index && other.score == score;
}
@override
int get hashCode => index.hashCode ^ score.hashCode;
}