447 lines
17 KiB
Dart
447 lines
17 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:carousel_slider/carousel_slider.dart';
|
|
//import 'package:confetti/confetti.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:manager_api/api.dart';
|
|
import 'package:mymuseum_visitapp/Components/CustomAppBar.dart';
|
|
import 'package:mymuseum_visitapp/Components/Loading.dart';
|
|
import 'package:mymuseum_visitapp/Components/rounded_button.dart';
|
|
import 'package:mymuseum_visitapp/Helpers/DatabaseHelper.dart';
|
|
import 'package:mymuseum_visitapp/Helpers/translationHelper.dart';
|
|
import 'package:mymuseum_visitapp/Models/ResponseSubDTO.dart';
|
|
import 'package:mymuseum_visitapp/Models/articleRead.dart';
|
|
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
|
//import 'package:mymuseum_visitapp/Screens/Quizz/drawPath.dart';
|
|
import 'package:mymuseum_visitapp/Screens/Quizz/questions_list.dart';
|
|
//import 'package:mymuseum_visitapp/Screens/Quizz/showResponses.dart';
|
|
import 'package:mymuseum_visitapp/app_context.dart';
|
|
import 'package:mymuseum_visitapp/client.dart';
|
|
import 'package:mymuseum_visitapp/constants.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
class QuizzPage extends StatefulWidget {
|
|
const QuizzPage({Key? key, required this.visitAppContextIn, required this.sectionId}) : super(key: key);
|
|
|
|
final String sectionId;
|
|
final VisitAppContext visitAppContextIn;
|
|
|
|
@override
|
|
State<QuizzPage> createState() => _QuizzPageState();
|
|
}
|
|
|
|
class _QuizzPageState extends State<QuizzPage> {
|
|
SectionDTO? sectionDTO;
|
|
List<ResourceModel?> resourcesModel = <ResourceModel?>[];
|
|
ResourceModel? audioResourceModel;
|
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
|
late Uint8List audiobytes;
|
|
VisitAppContext? visitAppContext;
|
|
|
|
QuizzDTO? quizzDTO;
|
|
List<QuestionSubDTO> _questionsSubDTO = <QuestionSubDTO>[];
|
|
//ConfettiController? _controllerCenter;
|
|
CarouselController? sliderController;
|
|
int currentIndex = 1;
|
|
bool showResult = false;
|
|
bool showResponses = false;
|
|
|
|
bool kIsWeb = false;
|
|
bool isResultPage = false;
|
|
|
|
@override
|
|
void initState() {
|
|
widget.visitAppContextIn.isContentCurrentlyShown = true;
|
|
|
|
//_controllerCenter = ConfettiController(duration: const Duration(seconds: 10));
|
|
//_controllerCenter!.play();
|
|
|
|
sliderController = CarouselController();
|
|
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
visitAppContext!.isContentCurrentlyShown = false;
|
|
currentIndex = 1;
|
|
//_controllerCenter!.dispose();
|
|
if(quizzDTO != null) {
|
|
if(quizzDTO!.questions != null) {
|
|
_questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO!.questions!);
|
|
}
|
|
}
|
|
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final appContext = Provider.of<AppContext>(context);
|
|
Size size = MediaQuery.of(context).size;
|
|
visitAppContext = appContext.getContext();
|
|
|
|
return Scaffold(
|
|
key: _scaffoldKey,
|
|
appBar: CustomAppBar(
|
|
title: sectionDTO != null ? TranslationHelper.get(sectionDTO!.title, visitAppContext!) : "",
|
|
isHomeButton: false,
|
|
),
|
|
body: OrientationBuilder(
|
|
builder: (context, orientation) {
|
|
return FutureBuilder(
|
|
future: getQuizz(appContext, appContext.clientAPI, widget.sectionId), // MAYBE MOVE THAT TO PARENT ..
|
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
|
if(quizzDTO != null && sectionDTO != null) {
|
|
|
|
if(showResult) {
|
|
var goodResponses = 0;
|
|
for (var question in _questionsSubDTO) {
|
|
if(question.chosen == question.responsesSubDTO!.indexWhere((response) => response.isGood!)) {
|
|
goodResponses +=1;
|
|
}
|
|
}
|
|
log("goodResponses =" + goodResponses.toString());
|
|
QuizzDTOBadLevel levelToShow = QuizzDTOBadLevel();
|
|
var test = goodResponses/quizzDTO!.questions!.length;
|
|
|
|
if((0 == test || test < 0.25) && quizzDTO!.badLevel != null) {
|
|
levelToShow = quizzDTO!.badLevel!;
|
|
}
|
|
if((test>=0.25 && test < 0.5) && quizzDTO!.mediumLevel != null) {
|
|
levelToShow = quizzDTO!.mediumLevel!;
|
|
}
|
|
if((test>=0.5 && test < 0.75) && quizzDTO!.goodLevel != null) {
|
|
levelToShow = quizzDTO!.goodLevel!;
|
|
}
|
|
if((test>=0.75 && test <= 1) && quizzDTO!.greatLevel != null) {
|
|
levelToShow = quizzDTO!.greatLevel!;
|
|
}
|
|
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
/*Center(
|
|
child: SizedBox(
|
|
width: 5,
|
|
height: 5,
|
|
child: ConfettiWidget(
|
|
confettiController: _controllerCenter!,
|
|
blastDirectionality: BlastDirectionality.explosive,
|
|
shouldLoop: false, // start again as soon as the animation is finished
|
|
colors: const [
|
|
kMainColor,
|
|
kSecondColor,
|
|
kConfigurationColor,
|
|
kTestSecondColor
|
|
//Colors.pink,
|
|
//Colors.orange,
|
|
//Colors.purple
|
|
], // manually specify the colors to be used
|
|
createParticlePath: drawPath, // define a custom shape/path.
|
|
),
|
|
),
|
|
),*/
|
|
if (orientation == Orientation.portrait)
|
|
Column(
|
|
children: [
|
|
if (!showResponses && levelToShow.source_ != null)
|
|
resultImage(size, levelToShow, orientation),
|
|
if(!showResponses)
|
|
// TEXT BOX WITH MAIN SCORE
|
|
Text('$goodResponses/${quizzDTO!.questions!.length}', textAlign: TextAlign.center, style: TextStyle(fontSize: kIsWeb ? (showResponses ? 60 : 100) : 75, color: kBackgroundSecondGrey)),
|
|
],
|
|
),
|
|
|
|
if (orientation == Orientation.landscape)
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: [
|
|
if(!showResponses)
|
|
// TEXT BOX WITH MAIN SCORE
|
|
Text('$goodResponses/${quizzDTO!.questions!.length}', textAlign: TextAlign.center, style: TextStyle(fontSize: kIsWeb ? (showResponses ? 60 : 100) : 75, color: kBackgroundSecondGrey)),
|
|
if (!showResponses && levelToShow.source_ != null)
|
|
resultImage(size, levelToShow, orientation),
|
|
],
|
|
),
|
|
|
|
if(!showResponses)
|
|
// TEXT BOX WITH LEVEL TEXT RESULT
|
|
resultText(size, levelToShow, appContext),
|
|
if(showResponses)
|
|
QuestionsListWidget(
|
|
questionsSubDTO: _questionsSubDTO,
|
|
isShowResponse: true,
|
|
onShowResponse: () {},
|
|
orientation: orientation,
|
|
),
|
|
// RESPONSE BOX
|
|
//ShowReponsesWidget(questionsSubDTO: _questionsSubDTO),
|
|
|
|
if(orientation == Orientation.portrait && !showResponses)
|
|
// Buttons
|
|
Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: resultButtons(size, orientation, visitAppContext!),
|
|
),
|
|
if(orientation == Orientation.landscape && !showResponses)
|
|
// Buttons
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: resultButtons(size, orientation, visitAppContext!),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
} else {
|
|
return QuestionsListWidget(
|
|
isShowResponse: false,
|
|
questionsSubDTO: _questionsSubDTO,
|
|
onShowResponse: () {
|
|
setState(() {
|
|
showResult = true;
|
|
});
|
|
},
|
|
orientation: orientation,
|
|
);
|
|
}
|
|
} else {
|
|
return const Loading();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
),
|
|
floatingActionButton: showResponses ? FloatingActionButton(
|
|
onPressed: () {
|
|
setState(() {
|
|
showResult = false;
|
|
showResponses = false;
|
|
currentIndex = 1;
|
|
_questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO!.questions!);
|
|
});
|
|
},
|
|
backgroundColor: kBackgroundSecondGrey,
|
|
child: const Icon(Icons.undo),
|
|
) : null,
|
|
floatingActionButtonLocation: FloatingActionButtonLocation.miniEndFloat,
|
|
);
|
|
}
|
|
|
|
Future<QuizzDTO?> getQuizz(AppContext appContext, Client client, String sectionId) async {
|
|
try {
|
|
if(sectionDTO == null || quizzDTO == null) {
|
|
bool isConfigOffline = (appContext.getContext() as VisitAppContext).configuration!.isOffline!;
|
|
if(isConfigOffline)
|
|
{
|
|
// OFFLINE
|
|
List<Map<String, dynamic>> sectionTest = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.sections, sectionId);
|
|
if(sectionTest.isNotEmpty) {
|
|
sectionDTO = DatabaseHelper.instance.getSectionFromDB(sectionTest.first);
|
|
try {
|
|
SectionRead sectionRead = SectionRead(id: sectionDTO!.id!, readTime: DateTime.now().millisecondsSinceEpoch);
|
|
await DatabaseHelper.instance.insert(DatabaseTableType.articleRead, sectionRead.toMap());
|
|
visitAppContext!.readSections.add(sectionRead);
|
|
|
|
appContext.setContext(visitAppContext!);
|
|
} catch (e) {
|
|
print("DATABASE ERROR SECTIONREAD");
|
|
print(e);
|
|
}
|
|
} else {
|
|
print("EMPTY SECTION");
|
|
}
|
|
} else
|
|
{
|
|
// ONLINE
|
|
SectionDTO? sectionOnline = await client.sectionApi!.sectionGetDetail(sectionId);
|
|
if(sectionOnline != null) {
|
|
sectionDTO = sectionOnline;
|
|
} else {
|
|
print("EMPTY SECTION");
|
|
}
|
|
}
|
|
|
|
if(sectionDTO!.type == SectionType.Quizz) {
|
|
quizzDTO = QuizzDTO.fromJson(jsonDecode(sectionDTO!.data!));
|
|
}
|
|
if(quizzDTO != null) {
|
|
quizzDTO!.questions!.sort((a, b) => a.order!.compareTo(b.order!));
|
|
_questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO!.questions!);
|
|
if(quizzDTO!.questions != null && quizzDTO!.questions!.isNotEmpty) {
|
|
quizzDTO!.questions!.sort((a, b) => a.order!.compareTo(b.order!));
|
|
for (var question in quizzDTO!.questions!) {
|
|
if(isConfigOffline)
|
|
{
|
|
// OFFLINE
|
|
if(question.resourceId != null) {
|
|
List<Map<String, dynamic>> ressourceQuizz = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, question.resourceId!);
|
|
if(ressourceQuizz.isNotEmpty) {
|
|
resourcesModel.add(DatabaseHelper.instance.getResourceFromDB(ressourceQuizz.first));
|
|
} else {
|
|
print("EMPTY resourcesModel - second");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ONLINE
|
|
if(question.resourceId != null) {
|
|
resourcesModel.add(ResourceModel(id: question.resourceId, source: question.source_, type: ResourceType.Image));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
setState(() {
|
|
//print(sectionDTO!.title);
|
|
});
|
|
} else {
|
|
return null; // TODO return local list..
|
|
}
|
|
} catch (e) {
|
|
print(e);
|
|
print("IN CATCH");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
resultImage(Size size, QuizzDTOBadLevel levelToShow, Orientation orientation) {
|
|
return Container(
|
|
//height: size.height * 0.2,
|
|
//width: size.width * 0.25,
|
|
constraints: BoxConstraints(
|
|
maxHeight: size.height * 0.25,
|
|
maxWidth: kIsWeb ? size.width * 0.20 : orientation == Orientation.portrait ? size.width * 0.85 : size.width * 0.4,
|
|
),
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
image: levelToShow.source_ != null ? DecorationImage(
|
|
fit: BoxFit.contain,
|
|
opacity: 0.85,
|
|
image: NetworkImage(
|
|
levelToShow.source_!,
|
|
),
|
|
): null,
|
|
borderRadius: const BorderRadius.all( Radius.circular(50.0)),
|
|
border: Border.all(
|
|
color: kBackgroundGrey,
|
|
width: 1.0,
|
|
),
|
|
),
|
|
child: Container(
|
|
//borderRadius: BorderRadius.all(Radius.circular(25.0)),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xff7c94b6),
|
|
image: DecorationImage(
|
|
image: NetworkImage(
|
|
levelToShow.source_!,
|
|
),
|
|
fit: BoxFit.cover,
|
|
),
|
|
borderRadius: const BorderRadius.all( Radius.circular(50.0)),
|
|
border: Border.all(
|
|
color: kBackgroundGrey,
|
|
width: 1.0,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
resultText(Size size, QuizzDTOBadLevel levelToShow, AppContext appContext) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 10),
|
|
child: Container(
|
|
width: size.width *0.75,
|
|
height: kIsWeb ? (showResponses ? size.height *0.10 : size.height *0.20) : size.height *0.25,
|
|
decoration: BoxDecoration(
|
|
color: kBackgroundLight, //kBackgroundLight
|
|
shape: BoxShape.rectangle,
|
|
borderRadius: BorderRadius.circular(10.0),
|
|
boxShadow: const [
|
|
BoxShadow(
|
|
color: kBackgroundSecondGrey,
|
|
spreadRadius: 0.3,
|
|
blurRadius: 4,
|
|
offset: Offset(0, 2), // changes position of shadow
|
|
),
|
|
],
|
|
),
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: SingleChildScrollView(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(15.0),
|
|
child: Text(TranslationHelper.get(levelToShow.label, appContext.getContext() as VisitAppContext), textAlign: TextAlign.center, style: TextStyle(fontSize: kIsWeb ? kDescriptionSize : kDescriptionSize)),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
resultButtons(Size size, Orientation orientation, VisitAppContext visitAppContext) {
|
|
return [
|
|
Padding(
|
|
padding: const EdgeInsets.all(4),
|
|
child: SizedBox(
|
|
height: kIsWeb ? 50 : 40,
|
|
width: orientation == Orientation.portrait ? size.width * 0.6 : size.width * 0.35,
|
|
child: RoundedButton(
|
|
text: TranslationHelper.getFromLocale("restart", visitAppContext),
|
|
color: kBackgroundSecondGrey,
|
|
textColor: kBackgroundLight,
|
|
icon: Icons.undo,
|
|
press: () {
|
|
setState(() {
|
|
showResult = false;
|
|
showResponses = false;
|
|
currentIndex = 1;
|
|
_questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO!.questions!);
|
|
});
|
|
},
|
|
fontSize: 18,
|
|
horizontal: 20,
|
|
vertical: 5
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(4.0),
|
|
child: SizedBox(
|
|
height: kIsWeb ? 50 : 40,
|
|
width: orientation == Orientation.portrait ? size.width * 0.6 : size.width * 0.35,
|
|
child: RoundedButton(
|
|
text: TranslationHelper.getFromLocale("responses", visitAppContext),
|
|
color: kBackgroundSecondGrey,
|
|
textColor: kBackgroundLight,
|
|
icon: Icons.assignment_turned_in,
|
|
press: () {
|
|
setState(() {
|
|
showResponses = true;
|
|
});
|
|
},
|
|
fontSize: 18,
|
|
horizontal: 20,
|
|
vertical: 5
|
|
),
|
|
),
|
|
)
|
|
];
|
|
}
|
|
}
|