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 {
|
||||
String name;
|
||||
String description;
|
||||
String type;
|
||||
DateTime dateAdded;
|
||||
DateTime dateFrom;
|
||||
DateTime dateTo;
|
||||
String dateHour;
|
||||
EventAddress address;
|
||||
String website;
|
||||
String phone;
|
||||
String idVideoYoutube;
|
||||
String email;
|
||||
String image;
|
||||
String? name;
|
||||
String? description;
|
||||
String? type;
|
||||
DateTime? dateAdded;
|
||||
DateTime? dateFrom;
|
||||
DateTime? dateTo;
|
||||
String? dateHour;
|
||||
EventAddress? address;
|
||||
String? website;
|
||||
String? phone;
|
||||
String? idVideoYoutube;
|
||||
String? email;
|
||||
String? image;
|
||||
|
||||
EventAgenda({
|
||||
required this.name,
|
||||
@ -68,21 +68,21 @@ class EventAgenda {
|
||||
}
|
||||
|
||||
class EventAddress {
|
||||
String address;
|
||||
double lat;
|
||||
double lng;
|
||||
int zoom;
|
||||
String placeId;
|
||||
String name;
|
||||
String streetNumber;
|
||||
String streetName;
|
||||
String streetNameShort;
|
||||
String city;
|
||||
String state;
|
||||
String stateShort;
|
||||
String postCode;
|
||||
String country;
|
||||
String countryShort;
|
||||
String? address;
|
||||
dynamic lat;
|
||||
dynamic lng;
|
||||
int? zoom;
|
||||
String? placeId;
|
||||
String? name;
|
||||
String? streetNumber;
|
||||
String? streetName;
|
||||
String? streetNameShort;
|
||||
String? city;
|
||||
String? state;
|
||||
String? stateShort;
|
||||
String? postCode;
|
||||
String? country;
|
||||
String? countryShort;
|
||||
|
||||
EventAddress({
|
||||
required this.address,
|
||||
|
||||
@ -9,6 +9,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:manager_api/api.dart';
|
||||
import 'package:path_provider/path_provider.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 {
|
||||
@ -21,6 +26,8 @@ class AgendaView extends StatefulWidget {
|
||||
|
||||
class _AgendaView extends State<AgendaView> {
|
||||
AgendaDTO agendaDTO = AgendaDTO();
|
||||
late Agenda agenda;
|
||||
late ValueNotifier<List<EventAgenda>> filteredAgenda = ValueNotifier<List<EventAgenda>>([]);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -35,10 +42,120 @@ class _AgendaView extends State<AgendaView> {
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return new Center(
|
||||
child: Text("TODO Agenda"),
|
||||
Size size = MediaQuery.of(context).size;
|
||||
|
||||
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
|
||||
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,
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
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,
|
||||
image: ImageCustomProvider.getImageProvider(appContext, section.imageId!, section.imageSource!),
|
||||
): null,
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=/Users/thomasfransolet/Documents/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/thomasfransolet/Documents/Proj/MyMuseum/tablet_app
|
||||
FLUTTER_ROOT=C:\PROJ\flutter
|
||||
FLUTTER_APPLICATION_PATH=C:\Users\ThomasFransolet\Documents\Documents\Perso\MuseeDeLaFraise\tablet-app
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=2.0.0
|
||||
FLUTTER_BUILD_NUMBER=6
|
||||
FLUTTER_BUILD_NAME=2.0.1
|
||||
FLUTTER_BUILD_NUMBER=7
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/thomasfransolet/Documents/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/thomasfransolet/Documents/Proj/MyMuseum/tablet_app"
|
||||
export "FLUTTER_ROOT=C:\PROJ\flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=C:\Users\ThomasFransolet\Documents\Documents\Perso\MuseeDeLaFraise\tablet-app"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=2.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=6"
|
||||
export "FLUTTER_BUILD_NAME=2.0.1"
|
||||
export "FLUTTER_BUILD_NUMBER=7"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
|
||||
@ -27,11 +27,11 @@ dependencies:
|
||||
# Specific Mobile
|
||||
sqflite: # Specific mobile and macOS
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
flare_flutter: ^3.0.2
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user