import 'dart:convert'; import 'dart:developer'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:confetti/confetti.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:manager_api_new/api.dart'; import 'package:photo_view/photo_view.dart'; import 'package:provider/provider.dart'; import 'package:tablet_app/Components/Buttons/rounded_button.dart'; import 'package:tablet_app/Components/Carousel/carousel_slider.dart' as cs; import 'package:tablet_app/Components/show_element_for_resource.dart'; import 'package:tablet_app/Helpers/ImageCustomProvider.dart'; import 'package:tablet_app/Helpers/translationHelper.dart'; import 'package:tablet_app/Models/ResponseSubDTO.dart'; import 'package:tablet_app/Models/tabletContext.dart'; import 'package:tablet_app/Screens/Quizz/showResponses.dart'; import 'package:tablet_app/Screens/Slider/slider_view.dart'; import 'package:tablet_app/app_context.dart'; import 'package:tablet_app/constants.dart'; import 'drawStrawberry.dart'; class QuizzView extends StatefulWidget { final QuizDTO section; GlobalKey? key; QuizzView({required this.section, this.key}); @override _QuizzView createState() => _QuizzView(); } class _QuizzView extends State { ConfettiController? _controllerCenter; QuizDTO quizzDTO = QuizDTO(); List _questionsSubDTO = []; cs.CarouselController? sliderController; int currentIndex = 1; bool showResult = false; bool showResponses = false; @override void initState() { super.initState(); _controllerCenter = ConfettiController(duration: const Duration(seconds: 10)); sliderController = cs.CarouselController(); //quizzDTO = QuizzDTO.fromJson(jsonDecode(widget.section!.data!))!; quizzDTO = widget.section; quizzDTO.questions!.sort((a, b) => a.order!.compareTo(b.order!)); _questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO.questions!); _controllerCenter!.play(); } @override void dispose() { sliderController = null; currentIndex = 1; _controllerCenter!.dispose(); _questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO.questions!); super.dispose(); } @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; final appContext = Provider.of(context); TabletAppContext tabletAppContext = appContext.getContext() as TabletAppContext; var primaryColor = tabletAppContext.configuration != null ? tabletAppContext.configuration!.primaryColor != null ? new Color(int.parse(tabletAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)) : kTestSecondColor : kTestSecondColor; if(showResult) { var goodResponses = 0; _questionsSubDTO.forEach((question) { if(question.chosen == question.responsesSubDTO!.indexWhere((response) => response.isGood!)) goodResponses +=1; }); log("goodResponses =" + goodResponses.toString()); LevelDTO? levelToShow; var test = goodResponses/quizzDTO.questions!.length; if(0 == test || test < 0.25) levelToShow = quizzDTO.badLevel; if(test>=0.25 && test < 0.5) levelToShow = quizzDTO.mediumLevel; if(test>=0.5 && test < 0.75) levelToShow = quizzDTO.goodLevel; if(test>=0.75 && test <= 1) levelToShow = quizzDTO.greatLevel; return Column( mainAxisAlignment: MainAxisAlignment.spaceAround, // crossAxisAlignment: CrossAxisAlignment.center, children: [ Center( child: Container( width: 5, height: 5, child: ConfettiWidget( confettiController: _controllerCenter!, numberOfParticles: 2, blastDirectionality: BlastDirectionality.explosive, shouldLoop: false, // start again as soon as the animation is finished colors: [ Colors.red, Colors.blueGrey, Colors.green, primaryColor //Colors.pink, //Colors.orange, //Colors.purple ], // manually specify the colors to be used createParticlePath: drawStar, // define a custom shape/path. ), ), ), if (levelToShow != null && !showResponses && levelToShow.label != null && levelToShow.label!.firstWhere((translation) => translation.language == appContext.getContext().language).resourceId != null) Container( //height: size.height * 0.2, //width: size.width * 0.25, constraints: BoxConstraints( maxHeight: kIsWeb ? size.height * 0.20 : size.height * 0.20, //size.height * 0.25 maxWidth: kIsWeb ? size.width * 0.20 : size.width * 0.20, //size.width * 0.25 ), alignment: Alignment.center, child : getElementForResource(context, appContext, levelToShow.label!.firstWhere((translation) => translation.language == appContext.getContext().language), true), ), Container( height: showResponses ? 60 : 90, //color: Colors.orange, child: Text('$goodResponses/${quizzDTO.questions!.length}', textAlign: TextAlign.center, style: TextStyle(fontSize: kIsWeb ? (showResponses ? 40 : 100) : (showResponses ? 40 : 70), color: kBackgroundSecondGrey)), ), if(!showResponses) Container( child: Padding( padding: const EdgeInsets.only(bottom: 10), child: Container( width: MediaQuery.of(context).size.width *0.75, height: kIsWeb ? (showResponses ? MediaQuery.of(context).size.height *0.10 : MediaQuery.of(context).size.height *0.20) : (showResponses ? MediaQuery.of(context).size.height *0.10 : MediaQuery.of(context).size.height *0.20), //MediaQuery.of(context).size.height *0.25 decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, spreadRadius: 0.3, blurRadius: 4, offset: Offset(0, 2), // changes position of shadow ), ], ), child: Center( child: Container( width: double.infinity, child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(15.0), child: levelToShow != null ? HtmlWidget( levelToShow.label!.firstWhere((translation) => translation.language == appContext.getContext().language).value != null ? levelToShow.label!.firstWhere((translation) => translation.language == appContext.getContext().language).value! : "", textStyle: TextStyle(fontSize: kIsWeb ? kWebDescriptionSize : kDescriptionSize), customStylesBuilder: (element) { return {'text-align': 'center', 'font-family': "Roboto"}; }, ) : Text("No data"), ), ), ), ), ), ), ), if(showResponses) Container( width: MediaQuery.of(context).size.width *0.9, height: kIsWeb ? MediaQuery.of(context).size.height *0.35 : MediaQuery.of(context).size.height *0.6, //MediaQuery.of(context).size.height *0.55 decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, spreadRadius: 0.3, blurRadius: 4, offset: Offset(0, 2), // changes position of shadow ), ], ), child: Center( child: Container( width: double.infinity, child: ShowReponsesWidget(questionsSubDTO: _questionsSubDTO), ), ), ), // Buttons Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( height: 50, //85 child: RoundedButton( text: TranslationHelper.getFromLocale("quiz.restart", appContext.getContext()), color: primaryColor, textColor: kBackgroundLight, icon: Icons.undo, press: () { setState(() { showResult = false; showResponses = false; currentIndex = 1; _questionsSubDTO = QuestionSubDTO().fromJSON(quizzDTO.questions!); }); }, fontSize: kIsWeb ? kWebDescriptionSize : kWebDescriptionSize, //30 horizontal: 30, vertical: 10 ), ), if(!showResponses) Container( height: 50, //85 child: RoundedButton( text: TranslationHelper.getFromLocale("quiz.seeResponses", appContext.getContext()), color: primaryColor, textColor: kBackgroundLight, icon: Icons.assignment_turned_in, press: () { setState(() { showResponses = true; }); }, fontSize: kIsWeb ? kWebDescriptionSize : kWebDescriptionSize, //30 horizontal: 30, vertical: 10 ), ) ], ), ), ], ); } else return Stack( children: [ Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ if(_questionsSubDTO.length > 0) cs.CarouselSlider( carouselController: sliderController, options: cs.CarouselOptions( onPageChanged: (int index, cs.CarouselPageChangedReason reason) { setState(() { currentIndex = index + 1; }); }, height: MediaQuery.of(context).size.height * 0.8, enlargeCenterPage: true, scrollPhysics: NeverScrollableScrollPhysics(), reverse: false, ), items: _questionsSubDTO.map((i) { return Builder( builder: (BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, margin: EdgeInsets.symmetric(horizontal: 5.0), decoration: BoxDecoration( color: kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), image: i.resourceUrl != null ? new DecorationImage( fit: BoxFit.cover, opacity: 0.35, image: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resourceUrl!) ): null, boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, spreadRadius: 0.5, blurRadius: 5, offset: Offset(0, 1.5), // changes position of shadow ), ], ), child: Column( //crossAxisAlignment: CrossAxisAlignment.center, //mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Padding( padding: const EdgeInsets.all(8.0), child: Container( //width: MediaQuery.of(context).size.width *0.65, height: MediaQuery.of(context).size.height *0.3, //color: Colors.green, child: Padding( padding: const EdgeInsets.all(10.0), child: Center( child: Container( decoration: BoxDecoration( color: kBackgroundLight, // Colors.orange,// kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, spreadRadius: 0.3, blurRadius: 4, offset: Offset(0, 2), // changes position of shadow ), ], ), width: MediaQuery.of(context).size.width *0.70, child: Center( child: Container( //color: Colors.yellow, //height: size.height * 0.2, child: Row( children: [ if(i.label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.resourceId != null) Container( //height: size.height * 0.2, //width: size.width * 0.25, constraints: BoxConstraints( maxHeight: size.height * 0.28, //size.height * 0.25 maxWidth: size.width * 0.20, //size.width * 0.25 ), alignment: Alignment.center, child : Padding( padding: const EdgeInsets.all(10.0), child: getElementForResource(context, appContext, i.label!.firstWhere((translation) => translation.language == appContext.getContext().language), true), ) ), SingleChildScrollView( child: Container( //color: Colors.green, width: i.label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.resourceId == null ? size.width * 0.65 : size.width * 0.5, child: Padding( padding: const EdgeInsets.all(10.0), child: HtmlWidget( i.label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.value != null ? i.label!.firstWhere((translation) => translation.language == appContext.getContext().language).value! : "", textStyle: TextStyle(fontSize: kIsWeb ? kWebDescriptionSize : kDescriptionSize), customStylesBuilder: (element) { return {'text-align': 'center', 'font-family': "Roboto"}; }, ), ), ), ), ], ), ), ), ) ), ), ), ), SizedBox( height: MediaQuery.of(context).size.height * 0.05, ), Expanded( child: Padding( padding: const EdgeInsets.all(10.0), child: Container( height: MediaQuery.of(context).size.height * 0.6, width: MediaQuery.of(context).size.width * 0.72, //color: Colors.green, child: Padding( padding: const EdgeInsets.all(0.0), child: GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisExtent: kIsWeb ? 75 : 150, // TODO depends on percentage 150 mainAxisSpacing: kIsWeb ? 75 : 5, // TODO depends on percentage crossAxisSpacing: kIsWeb ? 75 : 20, // TODO depends on percentage ), itemCount: i.responsesSubDTO!.length, itemBuilder: (BuildContext ctx, index) { return InkWell( onTap: () { setState(() { i.chosen = index; if(currentIndex == _questionsSubDTO.length && i.chosen == index) { showResult = true; _controllerCenter!.play(); // TODO Maybe show only confetti on super score .. } else { sliderController!.nextPage(duration: new Duration(milliseconds: 650), curve: Curves.fastOutSlowIn); } }); }, child: Padding( padding: const EdgeInsets.all(8.0), child: Container( alignment: Alignment.center, child: Row(// just to use if else mainAxisAlignment: i.responsesSubDTO![index].label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.resourceId == null ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ if(i.responsesSubDTO![index].label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.resourceId != null) Container( //height: size.height * 0.2, //width: size.width * 0.25, constraints: BoxConstraints( maxHeight: size.height * 0.28, //size.height * 0.25 maxWidth: size.width * 0.20, //size.width * 0.25 ), alignment: Alignment.center, child : Padding( padding: const EdgeInsets.all(10.0), child: getElementForResource(context, appContext, i.responsesSubDTO![index].label!.firstWhere((translation) => translation.language == appContext.getContext().language), true), ) ), SingleChildScrollView( child: Container( width: i.responsesSubDTO![index].label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.resourceId == null ? size.width * 0.3 : size.width * 0.13, //color: Colors.yellow, child: HtmlWidget( i.responsesSubDTO![index].label!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.value != null ? i.responsesSubDTO![index].label!.firstWhere((translation) => translation.language == appContext.getContext().language).value! : "", textStyle: TextStyle(fontSize: kIsWeb ? kWebDescriptionSize : kDescriptionSize, color: i.chosen == index ? Colors.white : Colors.black), customStylesBuilder: (element) { return {'text-align': 'center', 'font-family': "Roboto"}; }, ), ), ), ], ), decoration: BoxDecoration( color: i.chosen == index ? primaryColor : kBackgroundLight, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0), boxShadow: [ BoxShadow( color: kBackgroundSecondGrey, spreadRadius: 0.3, blurRadius: 4, offset: Offset(0, 2), // changes position of shadow ), ], ), ), ), ); }), ), ), ), ), ], ) ), ); }, ); }).toList(), ), ], ), if(_questionsSubDTO.length > 1 && currentIndex != _questionsSubDTO.length && _questionsSubDTO[currentIndex-1].chosen != null && quizzDTO.questions!.length > 0) Positioned( top: MediaQuery.of(context).size.height * 0.35, right: 60, child: InkWell( onTap: () { if(_questionsSubDTO[currentIndex-1].chosen != null && quizzDTO.questions!.length > 0) { sliderController!.nextPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); /*Fluttertoast.showToast( msg: "Vous n'avez pas répondu à cette question", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: kMainRed, textColor: Colors.white, fontSize: 35.0 );*/ } }, child: Icon( Icons.chevron_right, size: kIsWeb ? 100 : 100, // 95 color: primaryColor, ), ) ), if(_questionsSubDTO.length > 1 && currentIndex != 1) Positioned( top: MediaQuery.of(context).size.height * 0.35, left: 60, child: InkWell( onTap: () { if(currentIndex > 1) sliderController!.previousPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn); }, child: Icon( Icons.chevron_left, size: kIsWeb ? 100 : 100, //95 color: primaryColor, ), ) ), if(_questionsSubDTO.length > 0) Padding( padding: const EdgeInsets.only(bottom: 0), child: Align( alignment: Alignment.bottomCenter, child: InkWell( child: Text( currentIndex.toString()+'/'+quizzDTO.questions!.length.toString(), style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500), ), ) ), ), if(_questionsSubDTO.length == 0) Center(child: Text("Aucune question à afficher", style: TextStyle(fontSize: kNoneInfoOrIncorrect),)) ] ); } } getElementForResource(BuildContext context, AppContext appContext, TranslationAndResourceDTO i, bool addFullScreen) { var widgetToInclude; Size size = MediaQuery.of(context).size; TabletAppContext tabletAppContext = appContext.getContext() as TabletAppContext; switch(i.resourceType) { case ResourceType.Image: case ResourceType.ImageUrl: widgetToInclude = GestureDetector( onTap: () { if(addFullScreen) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.8, width: size.width * 0.8, child: Container( decoration: BoxDecoration( color: const Color(0xff7c94b6), borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)), ), child: PhotoView( imageProvider: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resourceUrl!), minScale: PhotoViewComputedScale.contained * 0.8, maxScale: PhotoViewComputedScale.contained * 3.0, backgroundDecoration: BoxDecoration( color: kBackgroundSecondGrey, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), ), ), ), ), ); }, ); } }, child: Container( decoration: BoxDecoration( //color: kBackgroundLight, image: DecorationImage( image: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resourceUrl!), fit: BoxFit.contain, ), borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)), /*border: Border.all( color: kBackgroundGrey, width: 1.0, ),*/ ), ), ); break; case ResourceType.Video: case ResourceType.VideoUrl: case ResourceType.Audio: widgetToInclude = GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { if(addFullScreen && i.resourceType != ResourceType.Audio) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)) ), contentPadding: EdgeInsets.zero, // title: Text(eventAgenda.name!), content: Container( decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)), color: kBackgroundColor, ), height: size.height * 0.8, width: size.width * 0.8, child: Center(child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resourceUrl, type: i.resourceType), appContext, false, true)), ), ); }, ); } }, child: IgnorePointer( ignoring: i.resourceType != ResourceType.Audio, child: Container( decoration: BoxDecoration( //color: kBackgroundSecondGrey, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 15.0), ), child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resourceUrl, type: i.resourceType), appContext, false, true), ), ), ); break; } return Center( child: Container( height: MediaQuery.of(context).size.height * 0.6, width: MediaQuery.of(context).size.width * 0.72, child: AspectRatio( aspectRatio: 16 / 9, child: ClipRect( child: widgetToInclude, ), ), ), ); }