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/material.dart';
import 'package:flutter/services.dart';
import 'package:manager_api/api.dart';
import 'package:provider/provider.dart';
import 'package:tablet_app/Components/loading_common.dart';
@ -30,6 +31,7 @@ class _AgendaView extends State<AgendaView> {
AgendaDTO agendaDTO = AgendaDTO();
late Agenda agenda;
late ValueNotifier<List<EventAgenda>> filteredAgenda = ValueNotifier<List<EventAgenda>>([]);
late Uint8List mapIcon;
@override
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.sort((a, b) => a.dateFrom!.compareTo(b.dateFrom!));
filteredAgenda.value = agenda.events;
mapIcon = await getByteIcon();
return agenda;
} catch(e) {
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
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
@ -134,7 +155,7 @@ class _AgendaView extends State<AgendaView> {
showDialog(
context: 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 {
final EventAgenda eventAgenda;
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
State<EventPopup> createState() => _EventPopupState();
@ -60,7 +61,7 @@ class _EventPopupState extends State<EventPopup> {
mapboxMap.annotations.createPointAnnotationManager().then((pointAnnotationManager) async {
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;
});
}
@ -85,21 +86,7 @@ class _EventPopupState extends State<EventPopup> {
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
Widget build(BuildContext context) {
@ -301,32 +288,16 @@ class _EventPopupState extends State<EventPopup> {
},
markers: markers,
) :
FutureBuilder(
future: getByteIcon(),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Uint8List icon = snapshot.data!;
return mapBox.MapWidget(
mapBox.MapWidget(
key: ValueKey("mapBoxWidget"),
styleUri: mapBox.MapboxStyles.STANDARD,
onMapCreated: (maBoxMap) {
_onMapCreated(maBoxMap, icon);
_onMapCreated(maBoxMap, widget.mapIcon);
},
cameraOptions: mapBox.CameraOptions(
center: mapBox.Point(coordinates: mapBox.Position(double.parse(widget.eventAgenda.address!.lng!.toString()), double.parse(widget.eventAgenda.address!.lat!.toString()))).toJson(),
zoom: 14
),
);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
} else {
return Center(
child: Container(
child: LoadingCommon()
)
);
}
}
),
): SizedBox(),
SizedBox(

View File

@ -1,6 +1,8 @@
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
Path drawStrawberry(Size size) {
// Method to convert degree to radians
double degToRad(double deg) => deg * (pi / 180.0);
@ -120,3 +122,62 @@ Path drawStrawberry(Size size) {
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_widget_from_html/flutter_widget_from_html.dart';
import 'package:manager_api/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/show_element_for_resource.dart';
@ -100,17 +101,19 @@ class _QuizzView extends State<QuizzView> {
height: 5,
child: ConfettiWidget(
confettiController: _controllerCenter!,
numberOfParticles: 2,
blastDirectionality: BlastDirectionality.explosive,
shouldLoop: false, // start again as soon as the animation is finished
colors: const [
Colors.red,
kMainRed,
kSecondRed
Colors.blueGrey,
Colors.green,
kTestSecondColor
//Colors.pink,
//Colors.orange,
//Colors.purple
], // 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
),
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(
height: 90,
@ -337,7 +340,7 @@ class _QuizzView extends State<QuizzView> {
alignment: Alignment.center,
child : Padding(
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(
@ -411,7 +414,7 @@ class _QuizzView extends State<QuizzView> {
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)),
child: getElementForResource(context, appContext, i.responsesSubDTO![index].label!.firstWhere((translation) => translation.language == appContext.getContext().language), true),
)
),
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;
Size size = MediaQuery.of(context).size;
switch(i.resourceType) {
case ResourceType.Image:
case ResourceType.ImageUrl:
widgetToInclude = Container(
//borderRadius: BorderRadius.all(Radius.circular(25.0)),
widgetToInclude = GestureDetector(
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(
color: const Color(0xff7c94b6),
image: DecorationImage(
@ -540,18 +584,50 @@ getElementForResource(BuildContext context, AppContext appContext, TranslationAn
width: 1.0,
),
),
),
);
break;
case ResourceType.Video:
case ResourceType.VideoUrl:
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(
color: kBackgroundSecondGrey,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(15.0),
),
child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resourceUrl, type: i.resourceType), appContext, false, true),
),
),
);
break;
}