add MapBox Agenda + updated quiz (full screen + confetti)

This commit is contained in:
Thomas Fransolet 2024-03-13 13:22:52 +01:00
parent c8224b1e35
commit 378c431762
4 changed files with 198 additions and 69 deletions

View File

@ -6,6 +6,7 @@ import 'dart:ui' as ui;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:manager_api/api.dart'; import 'package:manager_api/api.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tablet_app/Components/loading_common.dart'; import 'package:tablet_app/Components/loading_common.dart';
@ -30,6 +31,7 @@ class _AgendaView extends State<AgendaView> {
AgendaDTO agendaDTO = AgendaDTO(); AgendaDTO agendaDTO = AgendaDTO();
late Agenda agenda; late Agenda agenda;
late ValueNotifier<List<EventAgenda>> filteredAgenda = ValueNotifier<List<EventAgenda>>([]); late ValueNotifier<List<EventAgenda>> filteredAgenda = ValueNotifier<List<EventAgenda>>([]);
late Uint8List mapIcon;
@override @override
void initState() { void initState() {
@ -61,6 +63,9 @@ class _AgendaView extends State<AgendaView> {
agenda.events = agenda.events.where((a) => a.dateFrom!.isAfter(DateTime.now())).toList(); agenda.events = agenda.events.where((a) => a.dateFrom!.isAfter(DateTime.now())).toList();
agenda.events.sort((a, b) => a.dateFrom!.compareTo(b.dateFrom!)); agenda.events.sort((a, b) => a.dateFrom!.compareTo(b.dateFrom!));
filteredAgenda.value = agenda.events; filteredAgenda.value = agenda.events;
mapIcon = await getByteIcon();
return agenda; return agenda;
} catch(e) { } catch(e) {
print("Erreur lors du parsing du json : ${e.toString()}"); print("Erreur lors du parsing du json : ${e.toString()}");
@ -68,6 +73,22 @@ class _AgendaView extends State<AgendaView> {
} }
} }
getByteIcon() async {
final ByteData bytes = await rootBundle.load('assets/icons/marker.png');
var icon = await getBytesFromAsset(bytes, 25);
return icon;
}
Future<Uint8List> getBytesFromAsset(ByteData data, int width) async {
//ByteData data = await rootBundle.load(path);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),
targetWidth: width);
ui.FrameInfo fi = await codec.getNextFrame();
return (await fi.image.toByteData(format: ui.ImageByteFormat.png))
!.buffer
.asUint8List();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
@ -134,7 +155,7 @@ class _AgendaView extends State<AgendaView> {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return EventPopup(eventAgenda: eventAgenda, mapProvider: agendaDTO.mapProvider ?? MapProvider.Google); return EventPopup(eventAgenda: eventAgenda, mapProvider: agendaDTO.mapProvider ?? MapProvider.Google, mapIcon: mapIcon);
}, },
); );
}, },

View File

@ -21,8 +21,9 @@ import 'dart:ui' as ui;
class EventPopup extends StatefulWidget { class EventPopup extends StatefulWidget {
final EventAgenda eventAgenda; final EventAgenda eventAgenda;
final MapProvider mapProvider; final MapProvider mapProvider;
final Uint8List mapIcon;
EventPopup({Key? key, required this.eventAgenda, required this.mapProvider}) : super(key: key); EventPopup({Key? key, required this.eventAgenda, required this.mapProvider, required this.mapIcon}) : super(key: key);
@override @override
State<EventPopup> createState() => _EventPopupState(); State<EventPopup> createState() => _EventPopupState();
@ -60,7 +61,7 @@ class _EventPopupState extends State<EventPopup> {
mapboxMap.annotations.createPointAnnotationManager().then((pointAnnotationManager) async { mapboxMap.annotations.createPointAnnotationManager().then((pointAnnotationManager) async {
this.pointAnnotationManager = pointAnnotationManager; this.pointAnnotationManager = pointAnnotationManager;
pointAnnotationManager.createMulti(createPoints(LatLng(widget.eventAgenda.address!.lat, widget.eventAgenda.address!.lng), icon)); pointAnnotationManager.createMulti(createPoints(LatLng(double.parse(widget.eventAgenda.address!.lat!.toString()), double.parse(widget.eventAgenda.address!.lng!.toString())), icon));
init = true; init = true;
}); });
} }
@ -85,21 +86,7 @@ class _EventPopupState extends State<EventPopup> {
return options; return options;
} }
getByteIcon() async {
final ByteData bytes = await rootBundle.load('assets/icons/marker.png');
var icon = await getBytesFromAsset(bytes, 25);
return icon;
}
Future<Uint8List> getBytesFromAsset(ByteData data, int width) async {
//ByteData data = await rootBundle.load(path);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),
targetWidth: width);
ui.FrameInfo fi = await codec.getNextFrame();
return (await fi.image.toByteData(format: ui.ImageByteFormat.png))
!.buffer
.asUint8List();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -301,32 +288,16 @@ class _EventPopupState extends State<EventPopup> {
}, },
markers: markers, markers: markers,
) : ) :
FutureBuilder( mapBox.MapWidget(
future: getByteIcon(),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Uint8List icon = snapshot.data!;
return mapBox.MapWidget(
key: ValueKey("mapBoxWidget"), key: ValueKey("mapBoxWidget"),
styleUri: mapBox.MapboxStyles.STANDARD, styleUri: mapBox.MapboxStyles.STANDARD,
onMapCreated: (maBoxMap) { onMapCreated: (maBoxMap) {
_onMapCreated(maBoxMap, icon); _onMapCreated(maBoxMap, widget.mapIcon);
}, },
cameraOptions: mapBox.CameraOptions( cameraOptions: mapBox.CameraOptions(
center: mapBox.Point(coordinates: mapBox.Position(double.parse(widget.eventAgenda.address!.lng!.toString()), double.parse(widget.eventAgenda.address!.lat!.toString()))).toJson(), center: mapBox.Point(coordinates: mapBox.Position(double.parse(widget.eventAgenda.address!.lng!.toString()), double.parse(widget.eventAgenda.address!.lat!.toString()))).toJson(),
zoom: 14 zoom: 14
), ),
);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
} else {
return Center(
child: Container(
child: LoadingCommon()
)
);
}
}
), ),
): SizedBox(), ): SizedBox(),
SizedBox( SizedBox(

View File

@ -1,6 +1,8 @@
import 'dart:math'; import 'dart:math';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart';
Path drawStrawberry(Size size) { Path drawStrawberry(Size size) {
// Method to convert degree to radians // Method to convert degree to radians
double degToRad(double deg) => deg * (pi / 180.0); double degToRad(double deg) => deg * (pi / 180.0);
@ -120,3 +122,62 @@ Path drawStrawberry(Size size) {
return path; return path;
} }
Path drawStar(Size size) {
// Méthode pour convertir les degrés en radians
double degToRad(double deg) => deg * (pi / 180.0);
// Nombre de pointes de l'étoile
const numberOfPoints = 5;
// Variables pour les dimensions de l'étoile
final halfWidth = size.width / 2;
final externalRadius = halfWidth;
final internalRadius = halfWidth / 2.5;
final degreesPerStep = degToRad(360 / numberOfPoints);
final halfDegreesPerStep = degreesPerStep / 2;
// Création du chemin pour dessiner l'étoile
var path = Path();
// Début du dessin de l'étoile
path.moveTo(size.width, halfWidth);
// Boucle pour dessiner chaque pointe de l'étoile
for (double step = 0; step < 2 * pi; step += degreesPerStep) {
// Pointe externe de l'étoile
path.lineTo(halfWidth + externalRadius * cos(step),
halfWidth + externalRadius * sin(step));
// Pointe interne de l'étoile
path.lineTo(halfWidth + internalRadius * cos(step + halfDegreesPerStep),
halfWidth + internalRadius * sin(step + halfDegreesPerStep));
}
// Fermeture du chemin
path.close();
// Retourne le chemin complet de l'étoile
return path;
}
Path drawText(String text) {
final painter = TextPainter(
text: TextSpan(text: text, style: TextStyle()),
textDirection: TextDirection.ltr,
);
painter.layout();
final textWidth = painter.width;
final textHeight = painter.height;
final offsetX = (50 - textWidth) / 2;
final offsetY = (50 - textHeight) / 2;
final path = Path();
path.addRect(Rect.fromLTWH(offsetX, offsetY, textWidth, textHeight));
path.close();
return path;
}

View File

@ -8,6 +8,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:manager_api/api.dart'; import 'package:manager_api/api.dart';
import 'package:photo_view/photo_view.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tablet_app/Components/Buttons/rounded_button.dart'; import 'package:tablet_app/Components/Buttons/rounded_button.dart';
import 'package:tablet_app/Components/show_element_for_resource.dart'; import 'package:tablet_app/Components/show_element_for_resource.dart';
@ -100,17 +101,19 @@ class _QuizzView extends State<QuizzView> {
height: 5, height: 5,
child: ConfettiWidget( child: ConfettiWidget(
confettiController: _controllerCenter!, confettiController: _controllerCenter!,
numberOfParticles: 2,
blastDirectionality: BlastDirectionality.explosive, blastDirectionality: BlastDirectionality.explosive,
shouldLoop: false, // start again as soon as the animation is finished shouldLoop: false, // start again as soon as the animation is finished
colors: const [ colors: const [
Colors.red, Colors.red,
kMainRed, Colors.blueGrey,
kSecondRed Colors.green,
kTestSecondColor
//Colors.pink, //Colors.pink,
//Colors.orange, //Colors.orange,
//Colors.purple //Colors.purple
], // manually specify the colors to be used ], // manually specify the colors to be used
createParticlePath: drawStrawberry, // define a custom shape/path. createParticlePath: drawStar, // define a custom shape/path.
), ),
), ),
), ),
@ -123,7 +126,7 @@ class _QuizzView extends State<QuizzView> {
maxWidth: kIsWeb ? size.width * 0.20 : size.width * 0.20, //size.width * 0.25 maxWidth: kIsWeb ? size.width * 0.20 : size.width * 0.20, //size.width * 0.25
), ),
alignment: Alignment.center, alignment: Alignment.center,
child : getElementForResource(context, appContext, levelToShow.label!.firstWhere((translation) => translation.language == appContext.getContext().language)), child : getElementForResource(context, appContext, levelToShow.label!.firstWhere((translation) => translation.language == appContext.getContext().language), true),
), ),
Container( Container(
height: 90, height: 90,
@ -337,7 +340,7 @@ class _QuizzView extends State<QuizzView> {
alignment: Alignment.center, alignment: Alignment.center,
child : Padding( child : Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: getElementForResource(context, appContext, i.label!.firstWhere((translation) => translation.language == appContext.getContext().language)), child: getElementForResource(context, appContext, i.label!.firstWhere((translation) => translation.language == appContext.getContext().language), true),
) )
), ),
Padding( Padding(
@ -411,7 +414,7 @@ class _QuizzView extends State<QuizzView> {
alignment: Alignment.center, alignment: Alignment.center,
child : Padding( child : Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: getElementForResource(context, appContext, i.responsesSubDTO![index].label!.firstWhere((translation) => translation.language == appContext.getContext().language)), child: getElementForResource(context, appContext, i.responsesSubDTO![index].label!.firstWhere((translation) => translation.language == appContext.getContext().language), true),
) )
), ),
Container( Container(
@ -520,14 +523,55 @@ class _QuizzView extends State<QuizzView> {
} }
} }
getElementForResource(BuildContext context, AppContext appContext, TranslationAndResourceDTO i) { getElementForResource(BuildContext context, AppContext appContext, TranslationAndResourceDTO i, bool addFullScreen) {
var widgetToInclude; var widgetToInclude;
Size size = MediaQuery.of(context).size;
switch(i.resourceType) { switch(i.resourceType) {
case ResourceType.Image: case ResourceType.Image:
case ResourceType.ImageUrl: case ResourceType.ImageUrl:
widgetToInclude = Container( widgetToInclude = GestureDetector(
//borderRadius: BorderRadius.all(Radius.circular(25.0)), onTap: () {
if(addFullScreen) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))
),
contentPadding: EdgeInsets.zero,
// title: Text(eventAgenda.name!),
content: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(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(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(15.0),
),
),
),
),
);
},
);
}
},
child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xff7c94b6), color: const Color(0xff7c94b6),
image: DecorationImage( image: DecorationImage(
@ -540,18 +584,50 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn
width: 1.0, width: 1.0,
), ),
), ),
),
); );
break; break;
case ResourceType.Video: case ResourceType.Video:
case ResourceType.VideoUrl: case ResourceType.VideoUrl:
case ResourceType.Audio: case ResourceType.Audio:
widgetToInclude = Container( widgetToInclude = GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
if(addFullScreen && i.resourceType != ResourceType.Audio) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))
),
contentPadding: EdgeInsets.zero,
// title: Text(eventAgenda.name!),
content: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(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( decoration: BoxDecoration(
color: kBackgroundSecondGrey, color: kBackgroundSecondGrey,
shape: BoxShape.rectangle, shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(15.0), borderRadius: BorderRadius.circular(15.0),
), ),
child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resourceUrl, type: i.resourceType), appContext, false, true), child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resourceUrl, type: i.resourceType), appContext, false, true),
),
),
); );
break; break;
} }