Compare commits
20 Commits
feature/in
...
70545052c2
Author | SHA1 | Date | |
---|---|---|---|
70545052c2 | |||
6e0b54a925 | |||
5d9802d56e | |||
8a7515aaf6 | |||
f9934a0d5d | |||
09c82da57f | |||
75b42dd091 | |||
dfe21960be | |||
4a936cc267 | |||
bd5bfa94ca | |||
f30aa8f630 | |||
924794e8a0 | |||
7528e55dca | |||
02ba067615 | |||
9eafb30374 | |||
24cb90959d | |||
1620d84137 | |||
6e8ba642a2 | |||
0113fcc382 | |||
e4571cabe7 |
@@ -5,11 +5,15 @@ class Events {
|
||||
String? startDate;
|
||||
String? endDate;
|
||||
String? description;
|
||||
String? link;
|
||||
String? ticket;
|
||||
double? latitude;
|
||||
double? longitude;
|
||||
List<String>? tags;
|
||||
List<String>? organizers;
|
||||
String? imgUrl;
|
||||
int? interestedCount;
|
||||
bool? interested;
|
||||
Events(
|
||||
{this.place,
|
||||
this.id,
|
||||
@@ -21,7 +25,11 @@ class Events {
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.organizers,
|
||||
this.imgUrl});
|
||||
this.link,
|
||||
this.ticket,
|
||||
this.imgUrl,
|
||||
this.interestedCount,
|
||||
this.interested});
|
||||
|
||||
Events.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'] as String?;
|
||||
@@ -38,5 +46,9 @@ class Events {
|
||||
organizers = (json['organizers'] as List<dynamic>?)
|
||||
?.cast<String>(); // Convert List<dynamic> to List<String>
|
||||
imgUrl = json['imgUrl'] as String?;
|
||||
link = json['link'] as String?;
|
||||
ticket = json['ticket'] as String?;
|
||||
interested = json['interested'] as bool?;
|
||||
interestedCount = json['interested_count'] as int?;
|
||||
}
|
||||
}
|
||||
|
91
covas_mobile/lib/classes/notification_service.dart
Normal file
91
covas_mobile/lib/classes/notification_service.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:timezone/data/latest_all.dart' as tz;
|
||||
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NotificationService {
|
||||
static final FlutterLocalNotificationsPlugin _notificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
/// Initialisation (à appeler dans main())
|
||||
static Future<void> initialize() async {
|
||||
tz.initializeTimeZones();
|
||||
|
||||
const AndroidInitializationSettings androidInitSettings =
|
||||
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
|
||||
const InitializationSettings initSettings = InitializationSettings(
|
||||
android: androidInitSettings,
|
||||
iOS: DarwinInitializationSettings(),
|
||||
);
|
||||
|
||||
await _notificationsPlugin.initialize(initSettings);
|
||||
|
||||
// Demande les permissions au lancement
|
||||
await requestPermissions();
|
||||
}
|
||||
|
||||
/// Demander les permissions (Android 13+ et iOS)
|
||||
static Future<void> requestPermissions() async {
|
||||
// Android 13+
|
||||
final androidImplementation =
|
||||
_notificationsPlugin.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>();
|
||||
await androidImplementation?.requestNotificationsPermission();
|
||||
|
||||
// iOS
|
||||
final iosImplementation =
|
||||
_notificationsPlugin.resolvePlatformSpecificImplementation<
|
||||
IOSFlutterLocalNotificationsPlugin>();
|
||||
await iosImplementation?.requestPermissions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
}
|
||||
|
||||
/// Planifie une notification 1h avant l’évènement
|
||||
static Future<void> scheduleEventNotification({
|
||||
required String eventId,
|
||||
required String title,
|
||||
required String body,
|
||||
required DateTime eventDate,
|
||||
}) async {
|
||||
final scheduledDate = eventDate.subtract(const Duration(hours: 1));
|
||||
|
||||
if (scheduledDate.isBefore(DateTime.now())) {
|
||||
// Trop tard pour notifier
|
||||
return;
|
||||
}
|
||||
|
||||
await _notificationsPlugin.zonedSchedule(
|
||||
eventId.hashCode, // identifiant unique pour l’évènement
|
||||
title,
|
||||
body,
|
||||
tz.TZDateTime.from(scheduledDate, tz.local),
|
||||
const NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
'events_channel',
|
||||
'Events',
|
||||
channelDescription: 'Favorite event notifications',
|
||||
importance: Importance.high,
|
||||
priority: Priority.high,
|
||||
),
|
||||
iOS: DarwinNotificationDetails(),
|
||||
),
|
||||
androidScheduleMode: AndroidScheduleMode
|
||||
.inexactAllowWhileIdle, // évite l'erreur Exact Alarm
|
||||
uiLocalNotificationDateInterpretation:
|
||||
UILocalNotificationDateInterpretation.absoluteTime,
|
||||
matchDateTimeComponents: DateTimeComponents.dateAndTime,
|
||||
);
|
||||
}
|
||||
|
||||
/// Annule une notification planifiée
|
||||
static Future<void> cancel(String eventId) async {
|
||||
await _notificationsPlugin.cancel(eventId.hashCode);
|
||||
}
|
||||
}
|
@@ -130,5 +130,14 @@
|
||||
"unknown_error": "Unbekannter Fehler",
|
||||
"app_error": "Anwendungsfehler",
|
||||
"at": "um",
|
||||
"to_date": "bis"
|
||||
"to_date": "bis",
|
||||
"item_link": "Link : ",
|
||||
"item_ticket": "Abendkarte : ",
|
||||
"link": "Link",
|
||||
"edit_link": "Linkereignis bearbeiten",
|
||||
"ticket": "Abendkarte",
|
||||
"edit_ticket": "Ticketlink bearbeiten",
|
||||
"toogle_interest": "Fehler beim Umschalten des Interesses",
|
||||
"error_update": "Fehler beim Update",
|
||||
"count_interested": "Anzahl der Interessenten"
|
||||
}
|
||||
|
@@ -132,5 +132,14 @@
|
||||
"unknown_error": "Unknown error",
|
||||
"app_error": "Application error",
|
||||
"at": "at",
|
||||
"to_date": "to"
|
||||
"to_date": "to",
|
||||
"item_link": "Link : ",
|
||||
"item_ticket": "Ticket : ",
|
||||
"link": "Link",
|
||||
"edit_link": "Edit link name",
|
||||
"ticket": "Ticket",
|
||||
"edit_ticket": "Edit ticket link",
|
||||
"toogle_interest": "Error toggle interest",
|
||||
"error_update": "Error when updating",
|
||||
"count_interested": "Interested people number"
|
||||
}
|
@@ -132,6 +132,15 @@
|
||||
"unknown_error": "Erreur inconnue",
|
||||
"app_error": "Erreur d'application",
|
||||
"at": "à",
|
||||
"to_date": "jusqu'à"
|
||||
"to_date": "jusqu'à",
|
||||
"item_link": "Lien : ",
|
||||
"item_ticket": "Billet : ",
|
||||
"link": "Lien",
|
||||
"edit_link": "Editer le lien",
|
||||
"ticket": "Billet",
|
||||
"edit_ticket": "Editer le lien du billet",
|
||||
"toogle_interest": "Erreur de bouton de changement",
|
||||
"error_update": "Erreur lors de la mise à jour",
|
||||
"count_interested": "Nombre de personne interessé"
|
||||
|
||||
}
|
@@ -5,10 +5,12 @@ import 'package:provider/provider.dart';
|
||||
import 'pages/LoginDemo.dart';
|
||||
import 'locale_provider.dart'; // <-- à adapter selon ton arborescence
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'classes/notification_service.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await MobileAds.instance.initialize();
|
||||
await NotificationService.initialize();
|
||||
|
||||
runApp(
|
||||
ChangeNotifierProvider(
|
||||
|
@@ -66,6 +66,8 @@ class _EditEventState extends State<EditEvent>
|
||||
|
||||
TextEditingController inputName = TextEditingController();
|
||||
|
||||
TextEditingController inputTicket = TextEditingController();
|
||||
TextEditingController inputLink = TextEditingController();
|
||||
TextEditingController inputDate = TextEditingController();
|
||||
TextEditingController inputDesc = TextEditingController();
|
||||
|
||||
@@ -311,6 +313,8 @@ class _EditEventState extends State<EditEvent>
|
||||
'longitude': location['lng'],
|
||||
'description': inputDesc.text,
|
||||
"imgUrl": imgUrl,
|
||||
'link': inputLink.text,
|
||||
'ticket': inputTicket.text,
|
||||
"tags": List<String>.from(_stringTagController.getTags as List)
|
||||
}));
|
||||
|
||||
@@ -354,6 +358,8 @@ class _EditEventState extends State<EditEvent>
|
||||
});
|
||||
});
|
||||
inputName.text = widget.events!.name ?? "";
|
||||
inputTicket.text = widget.events!.ticket ?? "";
|
||||
inputLink.text = widget.events!.link ?? "";
|
||||
startDatepicker.text = DateFormat("dd/MM/yyyy")
|
||||
.format(DateTime.parse(
|
||||
widget.events!.startDate ?? DateTime.now().toString()))
|
||||
@@ -641,6 +647,35 @@ class _EditEventState extends State<EditEvent>
|
||||
onTap: () => onTapFunctionTimePicker(
|
||||
context: context, position: "end")),
|
||||
),
|
||||
Padding(
|
||||
//padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15.0, right: 15.0, top: 15, bottom: 0),
|
||||
child: TextFormField(
|
||||
controller: inputLink,
|
||||
validator: (value) => _validateField(value),
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: AppLocalizations.of(context)?.link ?? "Link",
|
||||
hintText: AppLocalizations.of(context)?.edit_link ??
|
||||
"Edit link event"),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
//padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0),
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15.0, right: 15.0, top: 15, bottom: 0),
|
||||
child: TextFormField(
|
||||
controller: inputTicket,
|
||||
validator: (value) => _validateField(value),
|
||||
decoration: InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText:
|
||||
AppLocalizations.of(context)?.ticket ?? "Ticket",
|
||||
hintText: AppLocalizations.of(context)?.edit_ticket ??
|
||||
"Edit ticket link"),
|
||||
),
|
||||
),
|
||||
TextFieldTags<String>(
|
||||
textfieldTagsController: _stringTagController,
|
||||
initialTags: initialTags,
|
||||
|
@@ -87,6 +87,8 @@ class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
|
||||
String eventName = "";
|
||||
String eventStartDate = "";
|
||||
String eventDescription = "";
|
||||
String eventTicket = "";
|
||||
String eventLink = "";
|
||||
String place = "";
|
||||
String imgUrl = "";
|
||||
List<String> tags = [];
|
||||
@@ -128,17 +130,17 @@ class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
|
||||
if (responseGet.statusCode == 200) {
|
||||
final responseBody = utf8.decode(responseGet.bodyBytes);
|
||||
|
||||
final event = Events.fromJson(jsonDecode(responseBody));
|
||||
events = Events.fromJson(jsonDecode(responseBody));
|
||||
final locale = Provider.of<LocaleProvider>(context, listen: false)
|
||||
.locale
|
||||
?.toString() ??
|
||||
'en_US';
|
||||
final startDate =
|
||||
DateTime.parse(event.startDate ?? DateTime.now().toString());
|
||||
DateTime.parse(events?.startDate ?? DateTime.now().toString());
|
||||
//final date = DateFormat.yMd().format(startDate);
|
||||
//final time = DateFormat.Hm().format(startDate);
|
||||
final endDate =
|
||||
DateTime.parse(event.endDate ?? DateTime.now().toString());
|
||||
DateTime.parse(events?.endDate ?? DateTime.now().toString());
|
||||
String separator = AppLocalizations.of(context)?.at ?? "at";
|
||||
final formattedStartDate =
|
||||
DateFormat("EEEE d MMMM y '${separator}' HH:mm", locale)
|
||||
@@ -151,14 +153,16 @@ class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
|
||||
String link = AppLocalizations.of(context)?.to_date ?? "to";
|
||||
|
||||
setState(() {
|
||||
eventName = event.name ?? "";
|
||||
eventName = events?.name ?? "";
|
||||
|
||||
eventStartDate = "$formattedStartDate ${link} $formattedEndDate";
|
||||
organizers = List<String>.from(event.organizers ?? []);
|
||||
place = event.place ?? "";
|
||||
imgUrl = event.imgUrl ?? "";
|
||||
eventDescription = event.description ?? "";
|
||||
tags = List<String>.from(event.tags ?? []);
|
||||
organizers = List<String>.from(events?.organizers ?? []);
|
||||
place = events?.place ?? "";
|
||||
imgUrl = events?.imgUrl ?? "";
|
||||
eventLink = events?.link ?? "";
|
||||
eventTicket = events?.ticket ?? "";
|
||||
eventDescription = events?.description ?? "";
|
||||
tags = List<String>.from(events?.tags ?? []);
|
||||
});
|
||||
} else {
|
||||
final messages = {
|
||||
@@ -276,6 +280,34 @@ class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis)))
|
||||
]),
|
||||
Row(children: [
|
||||
Icon(Icons.link),
|
||||
Text(
|
||||
AppLocalizations.of(context)?.item_link ?? "Link : ",
|
||||
style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold),
|
||||
)
|
||||
]),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child:
|
||||
Text("${eventLink}", style: TextStyle(fontSize: 15.0)))
|
||||
],
|
||||
),
|
||||
Row(children: [
|
||||
Icon(Icons.add_shopping_cart),
|
||||
Text(
|
||||
AppLocalizations.of(context)?.item_ticket ?? "Ticket : ",
|
||||
style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold),
|
||||
)
|
||||
]),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text("${eventTicket}",
|
||||
style: TextStyle(fontSize: 15.0)))
|
||||
],
|
||||
),
|
||||
Row(children: [
|
||||
Icon(Icons.group),
|
||||
Text(
|
||||
|
@@ -18,6 +18,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../locale_provider.dart'; //
|
||||
import '../classes/notification_service.dart';
|
||||
|
||||
// app starting point
|
||||
void main() async {
|
||||
@@ -94,6 +95,30 @@ class _MyHomePageState extends State<ListItemOrganizers> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> toggleInterested(String eventId) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
var accessToken = prefs.getString("access_token") ?? "";
|
||||
final url = Uri.parse("${globals.api}/events/${eventId}/interest");
|
||||
if (accessToken.isNotEmpty) {
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw (AppLocalizations.of(context)?.toogle_interest ??
|
||||
"Error toogle interest: ${response.statusCode}");
|
||||
}
|
||||
|
||||
var event = json.decode(response.body);
|
||||
return event;
|
||||
}
|
||||
return {"interested": false, "interested_count": 0};
|
||||
}
|
||||
|
||||
// variable to call and store future list of posts
|
||||
|
||||
// function to fetch data from api and return future list of posts
|
||||
@@ -190,10 +215,50 @@ class _MyHomePageState extends State<ListItemOrganizers> {
|
||||
|
||||
final dateLongue =
|
||||
DateFormat('EEEE d MMMM y', locale).format(startDate);
|
||||
final countInterestedString =
|
||||
AppLocalizations.of(context)?.count_interested ??
|
||||
"Interested people number";
|
||||
final countInterested =
|
||||
"${countInterestedString} : ${post.interestedCount}";
|
||||
|
||||
return ListTile(
|
||||
title: Text('${post.name!}'),
|
||||
subtitle: Text('${post.place!}\n${dateLongue}'),
|
||||
subtitle:
|
||||
Text('${post.place!}\n${dateLongue}\n${countInterested}'),
|
||||
trailing: IconButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final result = await toggleInterested(post.id!);
|
||||
setState(() {
|
||||
post.interested = result["interested"];
|
||||
post.interestedCount = result["interested_count"];
|
||||
});
|
||||
if (result["interested"] == true) {
|
||||
NotificationService.scheduleEventNotification(
|
||||
eventId: post.id!,
|
||||
title: "Rappel évènement",
|
||||
body:
|
||||
"Ton évènement '${post.name}' commence dans 1 heure !",
|
||||
eventDate: DateTime.parse(post.startDate!),
|
||||
);
|
||||
} else {
|
||||
NotificationService.cancel(post.id!);
|
||||
}
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
AppLocalizations.of(context)?.error_update ??
|
||||
"Error when updating")),
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
post.interested ?? false
|
||||
? Icons.favorite
|
||||
: Icons.favorite_border,
|
||||
color:
|
||||
post.interested ?? false ? Colors.red : Colors.grey)),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@@ -19,6 +19,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../locale_provider.dart'; //
|
||||
import '../classes/notification_service.dart';
|
||||
|
||||
// app starting point
|
||||
void main() async {
|
||||
@@ -121,6 +122,30 @@ class _MyHomePageState extends State<ListItemTags> {
|
||||
return body;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> toggleInterested(String eventId) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
var accessToken = prefs.getString("access_token") ?? "";
|
||||
final url = Uri.parse("${globals.api}/events/${eventId}/interest");
|
||||
if (accessToken.isNotEmpty) {
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw (AppLocalizations.of(context)?.toogle_interest ??
|
||||
"Error toogle interest: ${response.statusCode}");
|
||||
}
|
||||
|
||||
var event = json.decode(response.body);
|
||||
return event;
|
||||
}
|
||||
return {"interested": false, "interested_count": 0};
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -168,6 +193,7 @@ class _MyHomePageState extends State<ListItemTags> {
|
||||
Widget buildPosts(List<Events> posts) {
|
||||
// ListView Builder to show data in a list
|
||||
String tag = AppLocalizations.of(context)?.item_tags ?? "Tags : ";
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
@@ -191,9 +217,50 @@ class _MyHomePageState extends State<ListItemTags> {
|
||||
final dateLongue =
|
||||
DateFormat('EEEE d MMMM y', locale).format(startDate);
|
||||
|
||||
final countInterestedString =
|
||||
AppLocalizations.of(context)?.count_interested ??
|
||||
"Interested people number";
|
||||
final countInterested =
|
||||
"${countInterestedString} : ${post.interestedCount}";
|
||||
|
||||
return ListTile(
|
||||
title: Text('${post.name!}'),
|
||||
subtitle: Text('${post.place!}\n${dateLongue}'),
|
||||
subtitle:
|
||||
Text('${post.place!}\n${dateLongue}\n${countInterested}'),
|
||||
trailing: IconButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final result = await toggleInterested(post.id!);
|
||||
setState(() {
|
||||
post.interested = result["interested"];
|
||||
post.interestedCount = result["interested_count"];
|
||||
});
|
||||
if (result["interested"] == true) {
|
||||
NotificationService.scheduleEventNotification(
|
||||
eventId: post.id!,
|
||||
title: "Rappel évènement",
|
||||
body:
|
||||
"Ton évènement '${post.name}' commence dans 1 heure !",
|
||||
eventDate: DateTime.parse(post.startDate!),
|
||||
);
|
||||
} else {
|
||||
NotificationService.cancel(post.id!);
|
||||
}
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
AppLocalizations.of(context)?.error_update ??
|
||||
"Error when updating")),
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
post.interested ?? false
|
||||
? Icons.favorite
|
||||
: Icons.favorite_border,
|
||||
color:
|
||||
post.interested ?? false ? Colors.red : Colors.grey)),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@@ -23,6 +23,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../locale_provider.dart'; // Créé plus loin
|
||||
import '../classes/notification_service.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -423,7 +424,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
var url = await getUrlForEvents();
|
||||
final response = await http.get(url, headers: {
|
||||
"Content-Type": "application/json",
|
||||
HttpHeaders.cookieHeader: "acce0ss_token=$accessToken"
|
||||
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
||||
});
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
@@ -469,6 +470,30 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> toggleInterested(String eventId) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
var accessToken = prefs.getString("access_token") ?? "";
|
||||
final url = Uri.parse("${globals.api}/events/${eventId}/interest");
|
||||
if (accessToken.isNotEmpty) {
|
||||
final response = await http.post(
|
||||
url,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw (AppLocalizations.of(context)?.toogle_interest ??
|
||||
"Error toogle interest: ${response.statusCode}");
|
||||
}
|
||||
|
||||
var event = json.decode(response.body);
|
||||
return event;
|
||||
}
|
||||
return {"interested": false, "interested_count": 0};
|
||||
}
|
||||
|
||||
Future<void> fetchPostsByLocation() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
var accessToken = prefs.getString("access_token") ?? "";
|
||||
@@ -871,9 +896,49 @@ class _MyHomePageState extends State<ListItemMenu> {
|
||||
'en_US';
|
||||
final dateLongue =
|
||||
DateFormat('EEEE d MMMM y', locale).format(startDate);
|
||||
final countInterestedString =
|
||||
AppLocalizations.of(context)?.count_interested ??
|
||||
"Interested people number";
|
||||
final countInterested =
|
||||
"${countInterestedString} : ${post.interestedCount}";
|
||||
return ListTile(
|
||||
title: Text('${post.name!}'),
|
||||
subtitle: Text('${post.place!}\n${dateLongue}'),
|
||||
subtitle: Text('${post.place!}\n${dateLongue}\n${countInterested}'),
|
||||
trailing: IconButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final result = await toggleInterested(post.id!);
|
||||
setState(() {
|
||||
post.interested = result["interested"];
|
||||
post.interestedCount = result["interested_count"];
|
||||
});
|
||||
|
||||
if (result["interested"] == true) {
|
||||
NotificationService.scheduleEventNotification(
|
||||
eventId: post.id!,
|
||||
title: "Rappel évènement",
|
||||
body:
|
||||
"Ton évènement '${post.name}' commence dans 1 heure !",
|
||||
eventDate: DateTime.parse(post.startDate!),
|
||||
);
|
||||
} else {
|
||||
NotificationService.cancel(post.id!);
|
||||
}
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
AppLocalizations.of(context)?.error_update ??
|
||||
"Error when updating")),
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
post.interested ?? false
|
||||
? Icons.favorite
|
||||
: Icons.favorite_border,
|
||||
color:
|
||||
post.interested ?? false ? Colors.red : Colors.grey)),
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
|
@@ -6,6 +6,7 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import file_selector_macos
|
||||
import flutter_local_notifications
|
||||
import geolocator_apple
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
@@ -14,6 +15,7 @@ import webview_flutter_wkwebview
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
|
@@ -145,6 +145,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
dbus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.11"
|
||||
dio:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -270,6 +278,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
flutter_local_notifications:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "17.2.4"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_linux
|
||||
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.0"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -850,6 +882,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
timezone:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@@ -36,6 +36,8 @@ dependencies:
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
flutter_local_notifications: ^17.2.0
|
||||
timezone: ^0.9.4
|
||||
cupertino_icons: ^1.0.2
|
||||
http: ^1.2.1
|
||||
shared_preferences: ^2.2.3
|
||||
|
Reference in New Issue
Block a user