mirror of
https://bitbucket.org/FransoletThomas/tablet-app.git
synced 2025-12-06 08:31:19 +00:00
WIP Agenda (90%)
This commit is contained in:
parent
03debe3bb9
commit
8253550d07
@ -18,19 +18,19 @@ class Agenda {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventAgenda {
|
class EventAgenda {
|
||||||
String name;
|
String? name;
|
||||||
String description;
|
String? description;
|
||||||
String type;
|
String? type;
|
||||||
DateTime dateAdded;
|
DateTime? dateAdded;
|
||||||
DateTime dateFrom;
|
DateTime? dateFrom;
|
||||||
DateTime dateTo;
|
DateTime? dateTo;
|
||||||
String dateHour;
|
String? dateHour;
|
||||||
EventAddress address;
|
EventAddress? address;
|
||||||
String website;
|
String? website;
|
||||||
String phone;
|
String? phone;
|
||||||
String idVideoYoutube;
|
String? idVideoYoutube;
|
||||||
String email;
|
String? email;
|
||||||
String image;
|
String? image;
|
||||||
|
|
||||||
EventAgenda({
|
EventAgenda({
|
||||||
required this.name,
|
required this.name,
|
||||||
@ -68,21 +68,21 @@ class EventAgenda {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventAddress {
|
class EventAddress {
|
||||||
String address;
|
String? address;
|
||||||
double lat;
|
dynamic lat;
|
||||||
double lng;
|
dynamic lng;
|
||||||
int zoom;
|
int? zoom;
|
||||||
String placeId;
|
String? placeId;
|
||||||
String name;
|
String? name;
|
||||||
String streetNumber;
|
String? streetNumber;
|
||||||
String streetName;
|
String? streetName;
|
||||||
String streetNameShort;
|
String? streetNameShort;
|
||||||
String city;
|
String? city;
|
||||||
String state;
|
String? state;
|
||||||
String stateShort;
|
String? stateShort;
|
||||||
String postCode;
|
String? postCode;
|
||||||
String country;
|
String? country;
|
||||||
String countryShort;
|
String? countryShort;
|
||||||
|
|
||||||
EventAddress({
|
EventAddress({
|
||||||
required this.address,
|
required this.address,
|
||||||
|
|||||||
@ -9,6 +9,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:manager_api/api.dart';
|
import 'package:manager_api/api.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:tablet_app/Components/loading_common.dart';
|
import 'package:tablet_app/Components/loading_common.dart';
|
||||||
|
import 'package:tablet_app/Models/agenda.dart';
|
||||||
|
import 'package:tablet_app/Screens/Agenda/event_list_item.dart';
|
||||||
|
import 'package:tablet_app/Screens/Agenda/event_popup.dart';
|
||||||
|
import 'package:tablet_app/Screens/Agenda/month_filter.dart';
|
||||||
|
import 'package:tablet_app/constants.dart';
|
||||||
|
|
||||||
|
|
||||||
class AgendaView extends StatefulWidget {
|
class AgendaView extends StatefulWidget {
|
||||||
@ -21,6 +26,8 @@ class AgendaView extends StatefulWidget {
|
|||||||
|
|
||||||
class _AgendaView extends State<AgendaView> {
|
class _AgendaView extends State<AgendaView> {
|
||||||
AgendaDTO agendaDTO = AgendaDTO();
|
AgendaDTO agendaDTO = AgendaDTO();
|
||||||
|
late Agenda agenda;
|
||||||
|
late ValueNotifier<List<EventAgenda>> filteredAgenda = ValueNotifier<List<EventAgenda>>([]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -35,10 +42,120 @@ class _AgendaView extends State<AgendaView> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Agenda?> getAndParseJsonInfo() async {
|
||||||
|
try {
|
||||||
|
// Récupération du contenu JSON depuis l'URL
|
||||||
|
var httpClient = HttpClient();
|
||||||
|
var request = await httpClient.getUrl(Uri.parse(agendaDTO.resourceUrl!));
|
||||||
|
var response = await request.close();
|
||||||
|
var jsonString = await response.transform(utf8.decoder).join();
|
||||||
|
|
||||||
|
agenda = Agenda.fromJson(jsonString);
|
||||||
|
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;
|
||||||
|
return agenda;
|
||||||
|
} catch(e) {
|
||||||
|
print("Erreur lors du parsing du json : ${e.toString()}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return new Center(
|
Size size = MediaQuery.of(context).size;
|
||||||
child: Text("TODO Agenda"),
|
|
||||||
|
return FutureBuilder(future: getAndParseJsonInfo(),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
if (snapshot.data == null) {
|
||||||
|
return Center(
|
||||||
|
child: Text("Le json n'est pas valide")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundColor,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(30.0),
|
||||||
|
bottomLeft: Radius.circular(30.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: MonthFilter(
|
||||||
|
events: snapshot.data.events,
|
||||||
|
onMonthSelected: (filteredList) {
|
||||||
|
print('events sélectionné: $filteredList');
|
||||||
|
var result = filteredList!;
|
||||||
|
result.sort((a, b) => a.dateFrom!.compareTo(b.dateFrom!));
|
||||||
|
filteredAgenda.value = result;
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 4,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
|
child: Container(
|
||||||
|
child: ValueListenableBuilder<List<EventAgenda>>(
|
||||||
|
valueListenable: filteredAgenda,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
return GridView.builder(
|
||||||
|
scrollDirection: Axis.vertical, // Changer pour horizontal si nécessaire
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 4, // Nombre de colonnes dans la grid
|
||||||
|
crossAxisSpacing: 6.0, // Espace entre les colonnes
|
||||||
|
mainAxisSpacing: 6.0, // Espace entre les lignes
|
||||||
|
childAspectRatio: 0.8, // Aspect ratio des enfants de la grid
|
||||||
|
),
|
||||||
|
itemCount: value.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
EventAgenda eventAgenda = value[index];
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
print("${eventAgenda.name}");
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return EventPopup(eventAgenda: eventAgenda);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: EventListItem(
|
||||||
|
eventAgenda: eventAgenda,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
|
return Text("No data");
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
height: size.height * 0.2,
|
||||||
|
child: LoadingCommon()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} //_webView
|
} //_webView
|
||||||
163
lib/Screens/Agenda/event_list_item.dart
Normal file
163
lib/Screens/Agenda/event_list_item.dart
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:tablet_app/Components/loading_common.dart';
|
||||||
|
import 'package:tablet_app/Models/agenda.dart';
|
||||||
|
import 'package:tablet_app/Models/tabletContext.dart';
|
||||||
|
import 'package:tablet_app/app_context.dart';
|
||||||
|
import 'package:tablet_app/constants.dart';
|
||||||
|
|
||||||
|
class EventListItem extends StatelessWidget {
|
||||||
|
final EventAgenda eventAgenda;
|
||||||
|
|
||||||
|
EventListItem({super.key, required this.eventAgenda});
|
||||||
|
|
||||||
|
final DateFormat formatter = DateFormat('dd/MM/yyyy');
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
TabletAppContext tabletAppContext = appContext.getContext();
|
||||||
|
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;
|
||||||
|
|
||||||
|
Size size = MediaQuery
|
||||||
|
.of(context)
|
||||||
|
.size;
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
margin: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20.0),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black26,
|
||||||
|
offset: Offset(0.0, 2.0),
|
||||||
|
blurRadius: 6.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
width: size.width * 0.5, //210.0,
|
||||||
|
constraints: const BoxConstraints(maxWidth: 210),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 160,
|
||||||
|
width: size.width*1,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
eventAgenda.image != null ? ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(maxHeight: 175, maxWidth: 250),
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
width: size.width,
|
||||||
|
height: 175.0,
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: eventAgenda.image!,
|
||||||
|
width: size.width,
|
||||||
|
height: 175.0,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
progressIndicatorBuilder: (context, url, downloadProgress) {
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: LoadingCommon(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
): SizedBox(),
|
||||||
|
Positioned(
|
||||||
|
right: 0.0,
|
||||||
|
bottom: 0.0,
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: kMainRed, // TODO
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(20.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 10.0,
|
||||||
|
right: 10.0,
|
||||||
|
top: 2.0,
|
||||||
|
bottom: 2.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
|
children: <Widget>[
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
const Icon(
|
||||||
|
Icons.calendar_today_rounded,
|
||||||
|
size: 10.0,
|
||||||
|
color: kBackgroundColor,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 5.0),
|
||||||
|
Text(
|
||||||
|
eventAgenda.dateFrom!.isAtSameMomentAs(eventAgenda.dateTo!) ? "${formatter.format(eventAgenda.dateFrom!)}": "${formatter.format(eventAgenda.dateFrom!)} - ${formatter.format(eventAgenda.dateTo!)}", // TODO
|
||||||
|
style: const TextStyle(
|
||||||
|
color: kBackgroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
width: size.width,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(20.0), bottomRight: Radius.circular(20.0)),
|
||||||
|
border: Border(top: BorderSide(width: 0.1, color: kMainGrey))
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: HtmlWidget(
|
||||||
|
eventAgenda.name!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'center'};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: kDescriptionSize),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
AutoSizeText(
|
||||||
|
eventAgenda.type!,
|
||||||
|
maxFontSize: 12.0,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
267
lib/Screens/Agenda/event_popup.dart
Normal file
267
lib/Screens/Agenda/event_popup.dart
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:tablet_app/Components/loading_common.dart';
|
||||||
|
import 'package:tablet_app/Models/agenda.dart'; // Assurez-vous d'importer votre modèle d'agenda
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:tablet_app/constants.dart';
|
||||||
|
|
||||||
|
class EventPopup extends StatefulWidget {
|
||||||
|
final EventAgenda eventAgenda;
|
||||||
|
|
||||||
|
EventPopup({Key? key, required this.eventAgenda}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EventPopup> createState() => _EventPopupState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EventPopupState extends State<EventPopup> {
|
||||||
|
final DateFormat formatter = DateFormat('dd/MM/yyyy hh:mm');
|
||||||
|
Completer<GoogleMapController> _controller = Completer();
|
||||||
|
Set<Marker> markers = {};
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
|
Set<Marker> getMarkers() {
|
||||||
|
markers = {};
|
||||||
|
|
||||||
|
if (widget.eventAgenda.address!.lat != null && widget.eventAgenda.address!.lng != null) {
|
||||||
|
markers.add(Marker(
|
||||||
|
draggable: false,
|
||||||
|
markerId: MarkerId(widget.eventAgenda.address!.lat.toString() +
|
||||||
|
widget.eventAgenda.address!.lng.toString()),
|
||||||
|
position: LatLng(
|
||||||
|
double.parse(widget.eventAgenda.address!.lat!.toString()),
|
||||||
|
double.parse(widget.eventAgenda.address!.lng!.toString()),
|
||||||
|
),
|
||||||
|
icon: BitmapDescriptor.defaultMarker,
|
||||||
|
infoWindow: InfoWindow.noText));
|
||||||
|
}
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
var dateToShow = widget.eventAgenda.dateFrom!.isAtSameMomentAs(widget.eventAgenda.dateTo!) ? "${formatter.format(widget.eventAgenda.dateFrom!)}": "${formatter.format(widget.eventAgenda.dateFrom!)} - ${formatter.format(widget.eventAgenda.dateTo!)}";
|
||||||
|
|
||||||
|
print(widget.eventAgenda.phone);
|
||||||
|
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
if(!init) {
|
||||||
|
print("getmarkers in build");
|
||||||
|
getMarkers();
|
||||||
|
init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AlertDialog(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20.0))
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
// title: Text(eventAgenda.name!),
|
||||||
|
content: SizedBox(
|
||||||
|
height: size.height * 0.8,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
right: 5,
|
||||||
|
top: 5,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kMainGrey,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: kMainGrey,
|
||||||
|
spreadRadius: 0.5,
|
||||||
|
blurRadius: 1.1,
|
||||||
|
offset: Offset(0, 1.1), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 25,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
widget.eventAgenda.image != null ? ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.only(topLeft: Radius.circular(20.0), bottomLeft: Radius.circular(20.0)),
|
||||||
|
child: Container(
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
width: 225,
|
||||||
|
height: size.height,
|
||||||
|
color: Colors.grey,
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: widget.eventAgenda.image!,
|
||||||
|
width: size.width,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
progressIndicatorBuilder: (context, url, downloadProgress) {
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: LoadingCommon(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
): SizedBox(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 10, bottom: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: size.height * 0.11,
|
||||||
|
width: size.width * 0.45,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
AutoSizeText(
|
||||||
|
widget.eventAgenda.name!,
|
||||||
|
style: TextStyle(fontSize: 25),
|
||||||
|
maxFontSize: 25,
|
||||||
|
),
|
||||||
|
Text('${dateToShow}', style: TextStyle(fontSize: 20, color: kMainGrey)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: size.height * 0.65,
|
||||||
|
width: size.width * 0.45,
|
||||||
|
color: Colors.grey,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
HtmlWidget(
|
||||||
|
widget.eventAgenda.description!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'left'};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: kDescriptionSize),
|
||||||
|
),
|
||||||
|
widget.eventAgenda.idVideoYoutube != null && widget.eventAgenda.idVideoYoutube!.isNotEmpty ?
|
||||||
|
Text('TODO YOUTUBE VIDEO : ${widget.eventAgenda.idVideoYoutube}') : Text(""),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: size.width * 0.28,
|
||||||
|
height: size.height * 0.6,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
widget.eventAgenda.address!.lat != null && widget.eventAgenda.address!.lng != null ?
|
||||||
|
SizedBox(
|
||||||
|
width: size.width * 0.28,
|
||||||
|
height: size.height * 0.2,
|
||||||
|
child: GoogleMap(
|
||||||
|
mapToolbarEnabled: false,
|
||||||
|
initialCameraPosition: CameraPosition(
|
||||||
|
target: LatLng(double.parse(widget.eventAgenda.address!.lat!.toString()), double.parse(widget.eventAgenda.address!.lng!.toString())),
|
||||||
|
zoom: 16,
|
||||||
|
),
|
||||||
|
onMapCreated: (GoogleMapController controller) {
|
||||||
|
_controller.complete(controller);
|
||||||
|
},
|
||||||
|
markers: markers,
|
||||||
|
),
|
||||||
|
): SizedBox(),
|
||||||
|
SizedBox(
|
||||||
|
width: size.width * 0.28,
|
||||||
|
height: size.height * 0.35,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
widget.eventAgenda.address!.address != null && widget.eventAgenda.address!.address!.isNotEmpty ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.location_on, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: size.width*0.25,
|
||||||
|
child: AutoSizeText(widget.eventAgenda.address!.address!, style: TextStyle(fontSize: 12), maxLines: 3)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
widget.eventAgenda.phone != null && widget.eventAgenda.phone!.isNotEmpty ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.phone, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Text(widget.eventAgenda.phone!, style: TextStyle(fontSize: 12)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
widget.eventAgenda.email != null && widget.eventAgenda.email!.isNotEmpty ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.email, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Text(widget.eventAgenda.email!, style: TextStyle(fontSize: 12)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
widget.eventAgenda.website != null && widget.eventAgenda.website!.isNotEmpty ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.public, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Text(widget.eventAgenda.website!, style: TextStyle(fontSize: 12)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
152
lib/Screens/Agenda/month_filter.dart
Normal file
152
lib/Screens/Agenda/month_filter.dart
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tablet_app/Models/agenda.dart';
|
||||||
|
|
||||||
|
class MonthFilter extends StatefulWidget {
|
||||||
|
final List<EventAgenda> events;
|
||||||
|
final Function(List<EventAgenda>?) onMonthSelected;
|
||||||
|
|
||||||
|
MonthFilter({required this.events, required this.onMonthSelected});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MonthFilterState createState() => _MonthFilterState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MonthFilterState extends State<MonthFilter> {
|
||||||
|
String? _selectedMonth;
|
||||||
|
|
||||||
|
Map<String, List<String>> monthNames = {
|
||||||
|
'fr': ['',
|
||||||
|
'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'
|
||||||
|
],
|
||||||
|
// Ajoutez d'autres langues au besoin
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Map<String, dynamic>> sortedMonths = _getSortedMonths();
|
||||||
|
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: sortedMonths.length + 1, // +1 for "Tout (nbr total events)"
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == 0) {
|
||||||
|
return _buildAllItem();
|
||||||
|
} else {
|
||||||
|
final monthYear = sortedMonths[index - 1]['monthYear'];
|
||||||
|
|
||||||
|
List<EventAgenda>? filteredEvents = _filterEvents(monthYear);
|
||||||
|
|
||||||
|
String monthName = _getTranslatedMonthName(monthYear);
|
||||||
|
RegExp regExp = RegExp(r'\d{4}');
|
||||||
|
String annee = regExp.stringMatch(monthYear)!;
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
title: Text(
|
||||||
|
'$monthName $annee (${filteredEvents!.length})',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: _selectedMonth == monthYear ? FontWeight.bold : FontWeight.normal,
|
||||||
|
color: _selectedMonth == monthYear ? Colors.red : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedMonth = monthYear;
|
||||||
|
});
|
||||||
|
widget.onMonthSelected(filteredEvents);
|
||||||
|
},
|
||||||
|
tileColor: _selectedMonth == monthYear ? Colors.red : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _getTranslatedMonthName(String monthYear) {
|
||||||
|
// Récupérez le numéro du mois à partir de la chaîne "monthYear"
|
||||||
|
int monthIndex = int.parse(monthYear.split('-')[0]);
|
||||||
|
// Récupérez le nom du mois traduit dans la langue sélectionnée
|
||||||
|
String translatedMonthName = monthNames["fr"]![monthIndex];
|
||||||
|
return translatedMonthName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAllItem() {
|
||||||
|
int totalEvents = widget.events.length;
|
||||||
|
return ListTile(
|
||||||
|
title: Text(
|
||||||
|
'Tout ($totalEvents)',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontWeight: _selectedMonth == null ? FontWeight.bold : FontWeight.normal,
|
||||||
|
color: _selectedMonth == null ? Colors.red : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedMonth = null;
|
||||||
|
});
|
||||||
|
widget.onMonthSelected(widget.events);
|
||||||
|
},
|
||||||
|
tileColor: _selectedMonth == null ? Colors.red : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> _getSortedMonths() {
|
||||||
|
Map<String, int> monthsMap = {};
|
||||||
|
|
||||||
|
final List<String> monthYears = widget.events.map((event) {
|
||||||
|
return '${event.dateFrom!.month}-${event.dateFrom!.year}';
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
for (var monthYear in monthYears) {
|
||||||
|
if (monthsMap.containsKey(monthYear)) {
|
||||||
|
monthsMap[monthYear] = monthsMap[monthYear]! + 1;
|
||||||
|
} else {
|
||||||
|
monthsMap[monthYear] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> sortedMonths = [];
|
||||||
|
monthsMap.forEach((key, value) {
|
||||||
|
sortedMonths.add({'monthYear': key, 'totalEvents': value});
|
||||||
|
});
|
||||||
|
|
||||||
|
sortedMonths.sort((a, b) {
|
||||||
|
final partsA = a['monthYear'].split('-');
|
||||||
|
final partsB = b['monthYear'].split('-');
|
||||||
|
if (int.parse(partsA[1]) != int.parse(partsB[1])) {
|
||||||
|
return int.parse(partsA[1]).compareTo(int.parse(partsB[1]));
|
||||||
|
} else {
|
||||||
|
return int.parse(partsA[0]).compareTo(int.parse(partsB[0]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sortedMonths;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EventAgenda>? _filterEvents(String? monthYear) {
|
||||||
|
if (monthYear == null) {
|
||||||
|
return widget.events; // Retourner tous les événements si aucun mois n'est sélectionné
|
||||||
|
} else {
|
||||||
|
List<EventAgenda> filteredEvents = widget.events.where((event) {
|
||||||
|
final eventStart = event.dateFrom!;
|
||||||
|
final eventEnd = event.dateTo!;
|
||||||
|
|
||||||
|
// Extraction de l'année et du mois de monthYear
|
||||||
|
final parts = monthYear.split('-');
|
||||||
|
final selectedMonth = int.parse(parts[0]);
|
||||||
|
final selectedYear = int.parse(parts[1]);
|
||||||
|
|
||||||
|
// Création des objets DateTime pour le premier et le dernier jour du mois sélectionné
|
||||||
|
final firstDayOfMonth = DateTime(selectedYear, selectedMonth, 1);
|
||||||
|
final lastDayOfMonth = DateTime(selectedYear, selectedMonth + 1, 0);
|
||||||
|
|
||||||
|
// Vérification si la date de début ou la date de fin de l'événement est comprise entre le premier et le dernier jour du mois sélectionné
|
||||||
|
return (eventStart.isAfter(firstDayOfMonth) && eventStart.isBefore(lastDayOfMonth)) ||
|
||||||
|
(eventEnd.isAfter(firstDayOfMonth) && eventEnd.isBefore(lastDayOfMonth)) ||
|
||||||
|
(eventStart.isBefore(firstDayOfMonth) && eventEnd.isAfter(lastDayOfMonth));
|
||||||
|
}).toList();
|
||||||
|
return filteredEvents.isEmpty ? null : filteredEvents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -560,7 +560,7 @@ boxDecoration(AppContext appContext, SectionDTO section, bool isSelected) {
|
|||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
borderRadius: BorderRadius.circular(30.0),
|
borderRadius: BorderRadius.circular(30.0),
|
||||||
image: section.imageSource != null ? new DecorationImage(
|
image: section.imageSource != null ? new DecorationImage(
|
||||||
fit: !isSelected || kIsWeb ? BoxFit.cover : BoxFit.contain,
|
fit: BoxFit.cover,
|
||||||
colorFilter: !isSelected? new ColorFilter.mode(Colors.black.withOpacity(kIsWeb ? 0.3 : 0.3), BlendMode.dstATop) : null,
|
colorFilter: !isSelected? new ColorFilter.mode(Colors.black.withOpacity(kIsWeb ? 0.3 : 0.3), BlendMode.dstATop) : null,
|
||||||
image: ImageCustomProvider.getImageProvider(appContext, section.imageId!, section.imageSource!),
|
image: ImageCustomProvider.getImageProvider(appContext, section.imageId!, section.imageSource!),
|
||||||
): null,
|
): null,
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
// This is a generated file; do not edit or check into version control.
|
// This is a generated file; do not edit or check into version control.
|
||||||
FLUTTER_ROOT=/Users/thomasfransolet/Documents/flutter
|
FLUTTER_ROOT=C:\PROJ\flutter
|
||||||
FLUTTER_APPLICATION_PATH=/Users/thomasfransolet/Documents/Proj/MyMuseum/tablet_app
|
FLUTTER_APPLICATION_PATH=C:\Users\ThomasFransolet\Documents\Documents\Perso\MuseeDeLaFraise\tablet-app
|
||||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||||
FLUTTER_BUILD_DIR=build
|
FLUTTER_BUILD_DIR=build
|
||||||
FLUTTER_BUILD_NAME=2.0.0
|
FLUTTER_BUILD_NAME=2.0.1
|
||||||
FLUTTER_BUILD_NUMBER=6
|
FLUTTER_BUILD_NUMBER=7
|
||||||
DART_OBFUSCATION=false
|
DART_OBFUSCATION=false
|
||||||
TRACK_WIDGET_CREATION=true
|
TRACK_WIDGET_CREATION=true
|
||||||
TREE_SHAKE_ICONS=false
|
TREE_SHAKE_ICONS=false
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This is a generated file; do not edit or check into version control.
|
# This is a generated file; do not edit or check into version control.
|
||||||
export "FLUTTER_ROOT=/Users/thomasfransolet/Documents/flutter"
|
export "FLUTTER_ROOT=C:\PROJ\flutter"
|
||||||
export "FLUTTER_APPLICATION_PATH=/Users/thomasfransolet/Documents/Proj/MyMuseum/tablet_app"
|
export "FLUTTER_APPLICATION_PATH=C:\Users\ThomasFransolet\Documents\Documents\Perso\MuseeDeLaFraise\tablet-app"
|
||||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||||
export "FLUTTER_BUILD_DIR=build"
|
export "FLUTTER_BUILD_DIR=build"
|
||||||
export "FLUTTER_BUILD_NAME=2.0.0"
|
export "FLUTTER_BUILD_NAME=2.0.1"
|
||||||
export "FLUTTER_BUILD_NUMBER=6"
|
export "FLUTTER_BUILD_NUMBER=7"
|
||||||
export "DART_OBFUSCATION=false"
|
export "DART_OBFUSCATION=false"
|
||||||
export "TRACK_WIDGET_CREATION=true"
|
export "TRACK_WIDGET_CREATION=true"
|
||||||
export "TREE_SHAKE_ICONS=false"
|
export "TREE_SHAKE_ICONS=false"
|
||||||
|
|||||||
@ -27,11 +27,11 @@ dependencies:
|
|||||||
# Specific Mobile
|
# Specific Mobile
|
||||||
sqflite: # Specific mobile and macOS
|
sqflite: # Specific mobile and macOS
|
||||||
webview_flutter: ^4.4.1 # Specific mobile # old : ^3.0.4
|
webview_flutter: ^4.4.1 # Specific mobile # old : ^3.0.4
|
||||||
google_maps_flutter: ^2.5.0 # Specific mobile
|
google_maps_flutter: ^2.5.3 # Specific mobile
|
||||||
youtube_player_flutter: ^8.1.2 # Specific mobile
|
youtube_player_flutter: ^8.1.2 # Specific mobile
|
||||||
|
|
||||||
# Specific Web
|
# Specific Web
|
||||||
google_maps_flutter_web: ^0.5.4+2 # Specific WEB
|
google_maps_flutter_web: ^0.5.4+3 # Specific WEB
|
||||||
youtube_player_iframe: ^4.0.4 # Handle mobile and web here => TO TEST
|
youtube_player_iframe: ^4.0.4 # Handle mobile and web here => TO TEST
|
||||||
|
|
||||||
flare_flutter: ^3.0.2
|
flare_flutter: ^3.0.2
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user