Compare commits

..

No commits in common. "main" and "feature/oauth" have entirely different histories.

23 changed files with 205 additions and 487 deletions

View File

@ -10,8 +10,6 @@ import 'alert.dart';
import '../variable/globals.dart' as globals;
import '../pages/LoginDemo.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import dotenv
import 'package:encrypt_shared_preferences/provider.dart';
class MyDrawer extends StatelessWidget with ShowAlertDialog {
Future<void> logout(BuildContext context) async {
@ -30,20 +28,7 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog {
print("Status code logout ${response.statusCode}");
if (response.statusCode == 200) {
await prefs.remove("access_token");
await dotenv.load(fileName: ".env"); // Load .env file
final keyEncrypt = dotenv.env['KEY_ENCRYPT'] ?? '';
if (keyEncrypt.isNotEmpty) {
await EncryptedSharedPreferences.initialize(keyEncrypt);
var sharedPref = EncryptedSharedPreferences.getInstance();
String username = sharedPref.getString("username") ?? "";
String password = sharedPref.getString("password") ?? "";
if ((username.isEmpty) || (password.isEmpty)) {
sharedPref.remove("username");
sharedPref.remove("password");
}
}
await prefs.remove("access_token"); // Correctly remove the token
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => LoginDemo()),

View File

@ -3,15 +3,10 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import '../variable/globals.dart' as globals;
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:encrypt_shared_preferences/provider.dart';
import '../pages/LoginDemo.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import dotenv
class AuthService {
// Login with username and password
Future<bool> login(String username, String password,
{bool rememberMe = false}) async {
Future<bool> login(String username, String password) async {
final url = Uri.parse("${globals.api}/token");
try {
@ -21,22 +16,14 @@ class AuthService {
'accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {"username": username, "password": password},
body: {
"username": username,
"password": password,
},
);
if (response.statusCode == 200 || response.statusCode == 201) {
final prefs = await SharedPreferences.getInstance();
if (rememberMe) {
await dotenv.load(fileName: ".env"); // Load .env file
final keyEncrypt = dotenv.env['KEY_ENCRYPT'] ?? '';
if (keyEncrypt.isNotEmpty) {
await EncryptedSharedPreferences.initialize(keyEncrypt);
var sharedPref = EncryptedSharedPreferences.getInstance();
sharedPref.setString("username", username);
sharedPref.setString("password", password);
}
}
final cookies = response.headers["set-cookie"]?.split(";") ?? [];
for (final cookie in cookies) {
@ -90,25 +77,8 @@ class AuthService {
return true;
} else {
print("Token is invalid. Status code: ${response.statusCode}");
await dotenv.load(fileName: ".env"); // Load .env file
final keyEncrypt = dotenv.env['KEY_ENCRYPT'] ?? '';
if (keyEncrypt.isNotEmpty) {
await EncryptedSharedPreferences.initialize(keyEncrypt);
var sharedPref = EncryptedSharedPreferences.getInstance();
String username = sharedPref.getString("username") ?? "";
String password = sharedPref.getString("password") ?? "";
if ((username.isEmpty) || (password.isEmpty)) {
sharedPref.remove("username");
sharedPref.remove("password");
await prefs.remove("access_token"); // Clear invalid token
return false;
} else {
return login(username, password);
}
} else {
return false;
}
await prefs.remove("access_token"); // Clear invalid token
return false;
}
} catch (e) {
print("Error while checking token: $e");
@ -116,21 +86,6 @@ class AuthService {
}
}
Future<void> checkTokenStatus(context) async {
bool loggedIn = await isLoggedIn();
SharedPreferences prefs = await SharedPreferences.getInstance();
if (!loggedIn) {
await prefs.remove("access_token"); // Correctly remove the token
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => LoginDemo()),
(route) => false, // Remove all previous routes
);
}
}
// Get stored access token
Future<String?> getAccessToken() async {
final prefs = await SharedPreferences.getInstance();

View File

@ -140,7 +140,6 @@ class _AddProfileState extends State<AddProfile> with ShowAlertDialog {
@override
void initState() {
super.initState();
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import '../classes/MyDrawer.dart';
@ -6,7 +7,6 @@ import '../classes/MyDrawer.dart';
import 'DisplayPictureScreen.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import '../classes/auth_service.dart';
Future<void> main() async {
// Ensure that plugin services are initialized so that `availableCameras()`
@ -46,14 +46,12 @@ class Camera extends StatefulWidget {
class CameraState extends State<Camera> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
final AuthService _authService = AuthService();
@override
void initState() {
super.initState();
// To display the current output from the Camera,
// create a CameraController.
_authService.checkTokenStatus(context);
_controller = CameraController(
// Get a specific camera from the list of available cameras.
@ -97,6 +95,7 @@ class CameraState extends State<Camera> {
// camera preview. Use a FutureBuilder to display a loading spinner until the
// controller has finished initializing.
drawer: MyDrawer(),
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {

View File

@ -7,7 +7,6 @@ import 'package:image_picker/image_picker.dart';
import 'EditEvent.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import '../classes/auth_service.dart';
Future<void> main() async {
// Ensure that plugin services are initialized so that `availableCameras()`
@ -46,13 +45,10 @@ class CameraEdit extends StatefulWidget {
class CameraEditState extends State<CameraEdit> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
final AuthService _authService = AuthService();
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
// To display the current output from the Camera,
// create a CameraController.
@ -99,6 +95,7 @@ class CameraEditState extends State<CameraEdit> {
// camera preview. Use a FutureBuilder to display a loading spinner until the
// controller has finished initializing.
drawer: MyDrawer(),
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {

View File

@ -16,7 +16,6 @@ import '../classes/MyDrawer.dart';
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -63,14 +62,11 @@ class DisplayPictureScreen extends StatefulWidget {
class DisplayPictureScreenState extends State<DisplayPictureScreen>
with ShowDescImageAdd, ShowAlertDialog, TickerProviderStateMixin {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
late AnimationController controller;
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;
@ -102,41 +98,6 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
"L'IA de Google n'a pas su analyser l'image. Recommecer avec une autre");
}
void _showErrorDialog(BuildContext context, String title, String message) {
showAlertDialog(context, title, message);
}
Future<Map<String, dynamic>?> _fetchGeolocation(String place) async {
final apiKey = dotenv.env['PLACE_API_KEY'] ?? '';
final response = await http.get(Uri.parse(
'https://maps.googleapis.com/maps/api/place/textsearch/json?query=${place}}&key=$apiKey'));
if (response.statusCode == 200) {
final data = json.decode(response.body);
if (data['results'].isNotEmpty) {
return data['results'][0]['geometry']['location'];
}
}
return null;
}
Future<bool> _isDuplicateEvent(String accessToken,
Map<String, dynamic> jsonData, Map<String, dynamic> location) async {
final url = Uri.parse(
"${globals.api}/events/search?item=${jsonData["name"]}&date_event=${jsonData["start_date"]}"
"&min_lat=${location['lat']}&max_lat=${location['lat']}"
"&min_lon=${location['lng']}&max_lon=${location['lng']}");
final response = await http.get(url,
headers: {HttpHeaders.cookieHeader: 'access_token=$accessToken'});
if (response.statusCode == 200) {
final events = jsonDecode(utf8.decode(response.bodyBytes));
return events.isNotEmpty;
}
return false;
}
Future<void> searchEvents(String json, String imagePath) async {
print(json.replaceAll("'''json", '').replaceAll("'''", ""));
SharedPreferences prefs = await SharedPreferences.getInstance();
@ -151,22 +112,13 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
var accessToken = prefs.getString("access_token") ?? "";
if (accessToken.isNotEmpty) {
final location = await _fetchGeolocation(place);
if (location == null) {
_showErrorDialog(
context, "Erreur serveur", "Aucune donnée geographique");
return;
}
var urlGet = Uri.parse(
"${globals.api}/events/search?item=${name}&date_event=${date}");
final url = Uri.parse(
"${globals.api}/events/search?item=${name}&date_event=${date}"
"&min_lat=${location['lat']}&max_lat=${location['lat']}"
"&min_lon=${location['lng']}&max_lon=${location['lng']}");
final response = await http.get(url,
headers: {HttpHeaders.cookieHeader: 'access_token=$accessToken'});
if (response.statusCode == 200) {
var events = jsonDecode(utf8.decode(response.bodyBytes));
var responseGet = await http.get(urlGet,
headers: {HttpHeaders.cookieHeader: 'access_token=${accessToken}'});
if (responseGet.statusCode == 200) {
var events = jsonDecode(utf8.decode(responseGet.bodyBytes));
print("reponse http : ${events.length}");
if (events.length == 0) {
Navigator.push(
@ -182,7 +134,7 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
}
} else {
showAlertDialog(context, 'Erreur de reponse',
"response status code update : ${response.statusCode}");
"response status code update : ${responseGet.statusCode}");
}
} else {
showAlertDialog(context, "Erreur de reponse", "Erreur de token");
@ -206,7 +158,7 @@ class DisplayPictureScreenState extends State<DisplayPictureScreen>
gemini
.textAndImage(
text:
"Peux-tu donner le nom, la date (si l'année n'est pas précisé, mettez l'année actuelle ou future) et le lieu de l'évènement sous format JSON (sans le caratère json au début de la chaine de caractère) avec les valeurs suivantes : name, place, description, tags (tableau sans espace), organizers (tableau), start_date et end_date (si le end_date est vide, alors donnez une valeur de six de plus par rapport à start_date) sous le format en YYYY-MM-DD HH:mm:ssZ",
"Peux-tu donner le nom, la date avec l'année actuelle ou d'une année future proche et le lieu de l'évènement sous format JSON (sans le caratère json au début de la chaine de caractère) avec les valeurs suivantes : name, place, description, tags (tableau sans espace), organizers (tableau), start_date et end_date (si le end_date est vide, alors donnez une valeur de six de plus par rapport à start_date) sous le format en YYYY-MM-DD HH:mm:ssZ",
images: [file.readAsBytesSync()],
modelName: "models/gemini-1.5-pro-latest")
.then((value) => searchEvents(

View File

@ -9,9 +9,12 @@ import 'package:textfield_tags/textfield_tags.dart';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import '../classes/events.dart';
import '../classes/MyDrawer.dart';
import 'ItemMenu.dart';
import 'CameraEdit.dart';
import 'package:camera/camera.dart';
import '../classes/alert.dart';
@ -21,7 +24,6 @@ import '../variable/globals.dart' as globals;
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -58,8 +60,6 @@ class EditEvent extends StatefulWidget {
class _EditEventState extends State<EditEvent>
with ShowAlertDialog, ShowEventDialog {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
TextEditingController inputName = TextEditingController();
TextEditingController inputDate = TextEditingController();
@ -315,8 +315,6 @@ class _EditEventState extends State<EditEvent>
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;

View File

@ -17,7 +17,6 @@ import '../variable/globals.dart' as globals;
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -45,8 +44,6 @@ class EditProfile extends StatefulWidget {
class _EditProfileState extends State<EditProfile>
with ShowAlertDialog, ShowEventDialog {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
TextEditingController inputUserName = TextEditingController();
TextEditingController inputName = TextEditingController();
@ -201,8 +198,6 @@ class _EditProfileState extends State<EditProfile>
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;

View File

@ -12,7 +12,6 @@ import '../classes/eventAdded.dart';
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -40,8 +39,6 @@ class EditSettings extends StatefulWidget {
class _EditProfileState extends State<EditSettings>
with ShowAlertDialog, ShowEventDialog {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
TextEditingController inputUserName = TextEditingController();
int? kilometer;
@ -63,8 +60,6 @@ class _EditProfileState extends State<EditSettings>
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;

View File

@ -23,7 +23,6 @@ import 'EditEvent.dart';
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -76,7 +75,6 @@ class ItemMenu extends StatefulWidget {
class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
String listUser = "";
String eventName = "";
@ -93,8 +91,6 @@ class _ItemMenuState extends State<ItemMenu> with ShowAlertDialog {
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;

View File

@ -11,16 +11,10 @@ import 'package:intl/date_symbol_data_local.dart';
import '../variable/globals.dart' as globals;
import '../classes/MyDrawer.dart';
import '../classes/auth_service.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
// app starting point
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeDateFormatting("fr_FR", null);
runApp(const MyApp());
void main() {
initializeDateFormatting("fr_FR", null).then((_) => (const MyApp()));
}
class MyApp extends StatelessWidget {
@ -29,14 +23,6 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('fr', 'FR'),
],
home: const ListItemOrganizers(organizer: "default"),
debugShowCheckedModeBanner: false,
);
@ -55,55 +41,15 @@ class ListItemOrganizers extends StatefulWidget {
// homepage state
class _MyHomePageState extends State<ListItemOrganizers> {
int _fetchCount = 0;
bool _isLoading = false;
late ScrollController _scrollController;
final AuthService _authService = AuthService();
void _incrementFetchCount() {
setState(() {
_fetchCount++;
});
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_incrementFetchCount();
_fetchData();
}
}
Future<void> _fetchData() async {
print("Counter : ${_fetchCount}");
if (_isLoading) return;
setState(() {
_isLoading = true;
});
await Future.delayed(Duration(seconds: 2));
getPosts(widget.organizer, count: _fetchCount);
setState(() {
_isLoading = false;
});
}
// variable to call and store future list of posts
// function to fetch data from api and return future list of posts
static Future<List<Events>> getPosts(organizer, {count = 0}) async {
await initializeDateFormatting("fr_FR", null);
static Future<List<Events>> getPosts(organizer) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? "";
final List<Events> body = [];
if (accessToken.isNotEmpty) {
DateTime currentDatetime = DateTime.now();
num limit = 20 * (count + 1);
var url = Uri.parse(
"${globals.api}/events?organizers=${organizer}&limit=${limit}&current_datetime=${currentDatetime.toString()}");
var url = Uri.parse("${globals.api}/events?organizers=${organizer}");
final response = await http.get(url, headers: {
"Content-Type": "application/json",
HttpHeaders.cookieHeader: "access_token=${accessToken}"
@ -114,20 +60,6 @@ class _MyHomePageState extends State<ListItemOrganizers> {
return body;
}
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// build function
@override
Widget build(BuildContext context) {
@ -168,20 +100,16 @@ class _MyHomePageState extends State<ListItemOrganizers> {
foregroundColor: Colors.white,
),
body: ListView.separated(
controller: _scrollController,
itemCount: posts.isNotEmpty
? posts.length + (_isLoading ? 1 : 0) // Add 1 only if loading
: 0,
itemCount: posts.length,
itemBuilder: (context, index) {
final post = posts[index];
final startDate = DateTime.parse(post.startDate!);
final dateLongue =
DateFormat('EEEE d MMMM y', 'fr_FR').format(startDate);
final date = DateFormat.yMd().format(startDate);
final time = DateFormat.Hm().format(startDate);
return ListTile(
title: Text('${post.name!}'),
subtitle: Text('${post.place!}\n${dateLongue}'),
subtitle: Text('${post.place!}\n${date} ${time}'),
onTap: () {
Navigator.push(
context,

View File

@ -12,16 +12,10 @@ import 'package:intl/date_symbol_data_local.dart';
import '../variable/globals.dart' as globals;
import '../classes/MyDrawer.dart';
import '../classes/auth_service.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
// app starting point
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeDateFormatting("fr_FR", null);
runApp(const MyApp());
void main() {
initializeDateFormatting("fr_FR", null).then((_) => (const MyApp()));
}
class MyApp extends StatelessWidget {
@ -30,14 +24,6 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('fr', 'FR'),
],
home: const ListItemTags(tags: "default"),
debugShowCheckedModeBanner: false,
);
@ -57,55 +43,13 @@ class ListItemTags extends StatefulWidget {
class _MyHomePageState extends State<ListItemTags> {
// variable to call and store future list of posts
int _fetchCount = 0;
bool _isLoading = false;
late ScrollController _scrollController;
final AuthService _authService = AuthService();
void _incrementFetchCount() {
setState(() {
_fetchCount++;
});
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_incrementFetchCount();
_fetchData();
}
}
Future<void> _fetchData() async {
print("Counter : ${_fetchCount}");
if (_isLoading) return;
setState(() {
_isLoading = true;
});
await Future.delayed(Duration(seconds: 2));
getPosts(widget.tags, count: _fetchCount);
setState(() {
_isLoading = false;
});
}
// function to fetch data from api and return future list of posts
static Future<List<Events>> getPosts(tags, {count = 0}) async {
await initializeDateFormatting("fr_FR", null);
static Future<List<Events>> getPosts(tags) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? "";
final List<Events> body = [];
if (accessToken.isNotEmpty) {
DateTime currentDatetime = DateTime.now();
num limit = 20 * (count + 1);
var url = Uri.parse(
"${globals.api}/events?tags=${tags}&limit=${limit}&current_datetime=${currentDatetime.toString()}");
var url = Uri.parse("${globals.api}/events?tags=${tags}");
final response = await http.get(url, headers: {
"Content-Type": "application/json",
HttpHeaders.cookieHeader: "access_token=${accessToken}"
@ -116,21 +60,6 @@ class _MyHomePageState extends State<ListItemTags> {
return body;
}
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
_authService.checkTokenStatus(context);
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// build function
@override
Widget build(BuildContext context) {
@ -170,19 +99,16 @@ class _MyHomePageState extends State<ListItemTags> {
foregroundColor: Colors.white,
),
body: ListView.separated(
controller: _scrollController,
itemCount: posts.isNotEmpty
? posts.length + (_isLoading ? 1 : 0) // Add 1 only if loading
: 0,
itemCount: posts.length,
itemBuilder: (context, index) {
final post = posts[index];
final startDate = DateTime.parse(post.startDate!);
final dateLongue =
DateFormat('EEEE d MMMM y', 'fr_FR').format(startDate);
final date = DateFormat.yMd().format(startDate);
final time = DateFormat.Hm().format(startDate);
return ListTile(
title: Text('${post.name!}'),
subtitle: Text('${post.place!}\n${dateLongue}'),
subtitle: Text('${post.place!}\n${date} ${time}'),
onTap: () {
Navigator.push(
context,

View File

@ -18,16 +18,11 @@ import 'package:camera/camera.dart';
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await MobileAds.instance.initialize();
await initializeDateFormatting("fr_FR", null);
runApp(const MyApp());
initializeDateFormatting("fr_FR", null).then((_) => runApp(const MyApp()));
}
class MyApp extends StatelessWidget {
@ -36,14 +31,6 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('fr', 'FR'),
],
home: const ListItemMenu(),
debugShowCheckedModeBanner: false,
);
@ -59,10 +46,6 @@ class ListItemMenu extends StatefulWidget {
class _MyHomePageState extends State<ListItemMenu> {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
late ScrollController _scrollController;
int _fetchCount = 0;
bool _isLoading = false;
Future<List<Events>> postsFuture = getPosts();
List<Events> filteredPosts = [];
@ -86,7 +69,6 @@ class _MyHomePageState extends State<ListItemMenu> {
bool showInputTag = true;
// Fetching events from API
static Future<List<Events>> getPosts() async {
await initializeDateFormatting("fr_FR");
PermissionStatus status = await Permission.location.status;
final List<Events> body = [];
var url = Uri.parse("${globals.api}/events");
@ -160,59 +142,18 @@ class _MyHomePageState extends State<ListItemMenu> {
return "${year}-${month}-${day}";
}
void _incrementFetchCount() {
setState(() {
_fetchCount++;
});
_fetchData();
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_incrementFetchCount();
}
// Scroll to top
}
Future<void> _fetchData() async {
print("Counter : ${_fetchCount}");
if (_isLoading) return;
setState(() {
_isLoading = true;
});
await Future.delayed(Duration(seconds: 2));
fetchPostsByLocation();
setState(() {
_isLoading = false;
});
}
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;
});
});
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
// Initialize data fetch when the page loads
_getCurrentLocation();
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// Get the device's current location
Future<void> _getCurrentLocation() async {
PermissionStatus status = await Permission.location.status;
@ -402,10 +343,8 @@ class _MyHomePageState extends State<ListItemMenu> {
} else {
queryParameters = dateParameter;
}
int limit = 20 * (_fetchCount + 1);
return Uri.parse(
"${globals.api}/$endpoint?$queryParameters&limit=${limit}");
return Uri.parse("${globals.api}/$endpoint?$queryParameters");
}
Future<void> searchSuggestionsByItem(String input) async {
@ -416,7 +355,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) {
@ -480,17 +419,16 @@ class _MyHomePageState extends State<ListItemMenu> {
if (response.statusCode == 200) {
final List<dynamic> body = json.decode(utf8.decode(response.bodyBytes));
print("results fetch : ${body}");
print("fetch count : ${_fetchCount}");
// Update state after getting the response
setState(() {
int counter = filteredPosts.length;
// If we have results, map them to Events
filteredPosts = body
.map((e) => Events.fromJson(e as Map<String, dynamic>))
.toList();
if (counter == filteredPosts.length) {
_fetchCount--;
if (body.isNotEmpty) {
// If we have results, map them to Events
filteredPosts = body
.map((e) => Events.fromJson(e as Map<String, dynamic>))
.toList();
} else {
// If no results, clear filteredPosts
filteredPosts.clear();
}
});
} else {
@ -629,7 +567,6 @@ class _MyHomePageState extends State<ListItemMenu> {
controller: inputItem,
labelText: 'Search by item',
onChanged: (value) {
_fetchCount = 0;
if (value.isNotEmpty) {
setState(() {
itemName = value;
@ -647,7 +584,6 @@ class _MyHomePageState extends State<ListItemMenu> {
}
},
onClear: () {
_fetchCount = 0;
setState(() {
inputItem.clear();
itemName = '';
@ -659,7 +595,6 @@ class _MyHomePageState extends State<ListItemMenu> {
},
suggestions: suggestionsItem,
onSuggestionTap: (suggestion) async {
_fetchCount = 0;
setState(() {
itemName = suggestion['name'];
inputItem.text = itemName;
@ -675,7 +610,6 @@ class _MyHomePageState extends State<ListItemMenu> {
controller: inputTags,
labelText: 'Search by tags',
onChanged: (value) {
_fetchCount = 0;
if (value.isNotEmpty) {
setState(() {
itemTags = value;
@ -693,7 +627,6 @@ class _MyHomePageState extends State<ListItemMenu> {
}
},
onClear: () {
_fetchCount = 0;
setState(() {
inputTags.clear();
});
@ -701,8 +634,6 @@ class _MyHomePageState extends State<ListItemMenu> {
},
suggestions: suggestionsTags,
onSuggestionTap: (suggestion) async {
_fetchCount = 0;
setState(() {
itemTags = suggestion['name'];
inputTags.text = itemTags;
@ -726,8 +657,6 @@ class _MyHomePageState extends State<ListItemMenu> {
controller: inputGeo,
labelText: 'Search by geographical zone',
onChanged: (value) async {
_fetchCount = 0;
if (value.isNotEmpty) {
setState(() {
geographicalZone = value;
@ -749,7 +678,6 @@ class _MyHomePageState extends State<ListItemMenu> {
}
},
onClear: () async {
_fetchCount = 0;
final prefs = await SharedPreferences.getInstance();
prefs.remove("city_lat");
prefs.remove("city_long");
@ -765,7 +693,6 @@ class _MyHomePageState extends State<ListItemMenu> {
},
suggestions: suggestionsGeo,
onSuggestionTap: (suggestion) async {
_fetchCount = 0;
final latitude = suggestion['geometry']['coordinates'][1];
final longitude = suggestion['geometry']['coordinates'][0];
setState(() {
@ -840,26 +767,15 @@ class _MyHomePageState extends State<ListItemMenu> {
}
return ListView.separated(
controller: _scrollController,
itemCount: displayedPosts.isNotEmpty
? displayedPosts.length +
(_isLoading ? 1 : 0) // Add 1 only if loading
: 0,
itemCount: displayedPosts.length,
itemBuilder: (context, index) {
if (index >= displayedPosts.length) {
return _isLoading
? Center(child: CircularProgressIndicator())
: SizedBox.shrink();
}
final post = displayedPosts[index];
final startDate = DateTime.parse(post.startDate!);
//final date = DateFormat.yMd().format(startDate);
//final time = DateFormat.Hm().format(startDate);
final dateLongue =
DateFormat('EEEE d MMMM y', 'fr_FR').format(startDate);
final date = DateFormat.yMd().format(startDate);
final time = DateFormat.Hm().format(startDate);
return ListTile(
title: Text('${post.name!}'),
subtitle: Text('${post.place!}\n${dateLongue}'),
subtitle: Text('${post.place!}\n${date} ${time}'),
onTap: () {
Navigator.push(
context,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:permission_handler/permission_handler.dart';
import '../classes/auth_service.dart';
import '../pages/ListItemMenu.dart';
@ -18,7 +19,6 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
TextEditingController inputPseudo = TextEditingController();
TextEditingController inputPassword = TextEditingController();
final AuthService _authService = AuthService();
bool _rememberMe = false;
Future<void> _login(BuildContext context) async {
final pseudo = inputPseudo.text;
@ -29,8 +29,7 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
return;
}
bool success =
await _authService.login(pseudo, password, rememberMe: _rememberMe);
bool success = await _authService.login(pseudo, password);
if (success) {
Navigator.push(
@ -55,6 +54,7 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
Future<void> _checkLoginStatus() async {
bool loggedIn = await _authService.isLoggedIn();
print("logged status : ${loggedIn}");
if (loggedIn) {
Navigator.push(
context, MaterialPageRoute(builder: (_) => ListItemMenu()));
@ -110,15 +110,6 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
),
),
),
CheckboxListTile(
title: Text("Se souvenir de moi"),
value: _rememberMe,
onChanged: (newValue) {
setState(() {
_rememberMe = newValue ?? false;
});
},
),
TextButton(
onPressed: () {
Navigator.push(context,

View File

@ -11,7 +11,6 @@ import 'package:geolocator/geolocator.dart'; // For getting the user's location
import '../classes/alert.dart'; // Assuming this contains your error dialog code.
import '../variable/globals.dart' as globals;
import '../classes/MyDrawer.dart';
import '../classes/auth_service.dart';
void main() async {
await dotenv.load(fileName: ".env"); // Load .env file
@ -45,8 +44,6 @@ class MapboxPages extends StatefulWidget {
}
class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
final AuthService _authService = AuthService();
late MapboxMapController mapController;
late String mapboxAccessToken;
List<LatLng> routeCoordinates = [];
@ -61,8 +58,6 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
_getUserLocation();
}

View File

@ -18,7 +18,6 @@ import '../variable/globals.dart' as globals;
import '../classes/ad_helper.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import '../classes/auth_service.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@ -52,7 +51,6 @@ class UpdateeventImage extends StatefulWidget {
class _UpdateeventImageState extends State<UpdateeventImage>
with ShowAlertDialog, ShowEventDialog {
BannerAd? _bannerAd;
final AuthService _authService = AuthService();
TextEditingController inputName = TextEditingController();
@ -318,8 +316,6 @@ class _UpdateeventImageState extends State<UpdateeventImage>
@override
void initState() {
super.initState();
_authService.checkTokenStatus(context);
AdHelper.createBannerAd(() => setState(() {})).then((ad) {
setState(() {
_bannerAd = ad;

View File

@ -7,12 +7,16 @@
#include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
flutter_secure_storage_linux
url_launcher_linux
)

View File

@ -5,16 +5,22 @@
import FlutterMacOS
import Foundation
import facebook_auth_desktop
import file_selector_macos
import flutter_secure_storage_macos
import geolocator_apple
import google_sign_in_ios
import path_provider_foundation
import shared_preferences_foundation
import url_launcher_macos
import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FacebookAuthDesktopPlugin.register(with: registry.registrar(forPlugin: "FacebookAuthDesktopPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))

View File

@ -9,22 +9,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.6.1"
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
url: "https://pub.dev"
source: hosted
version: "1.5.8"
async:
dependency: transitive
description:
@ -105,14 +89,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
cross_file:
dependency: transitive
description:
@ -161,22 +137,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
encrypt:
facebook_auth_desktop:
dependency: transitive
description:
name: encrypt
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
name: facebook_auth_desktop
sha256: "219d559a33891e937c1913430505eae01fb946cb35729167bbdc747e3ebbd9ff"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
encrypt_shared_preferences:
dependency: "direct main"
description:
name: encrypt_shared_preferences
sha256: "35cd218e5e9d12fe4a63a545f46f2144d861909e4c4f2c4606fc75ffb53d9a46"
url: "https://pub.dev"
source: hosted
version: "0.8.8"
version: "2.1.1"
fake_async:
dependency: transitive
description:
@ -254,6 +222,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.2.1"
flutter_facebook_auth:
dependency: "direct main"
description:
name: flutter_facebook_auth
sha256: d542743aee9571fad59aa4cfb645640dbb49f23b039d07c34b5e21bc3d5857e9
url: "https://pub.dev"
source: hosted
version: "7.1.1"
flutter_facebook_auth_platform_interface:
dependency: transitive
description:
name: flutter_facebook_auth_platform_interface
sha256: e04b8dbfa77702bea45a79993163ad5d20b2c0084109bec591fdc2b9ee505779
url: "https://pub.dev"
source: hosted
version: "6.1.2"
flutter_facebook_auth_web:
dependency: transitive
description:
name: flutter_facebook_auth_web
sha256: f682400d61cf8d52dd8b6458b5ee106ed57e95309a117dc32875d3da129ce47c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
flutter_gemini:
dependency: "direct main"
description:
@ -270,11 +262,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@ -283,6 +270,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.23"
flutter_secure_storage:
dependency: transitive
description:
name: flutter_secure_storage
sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
url: "https://pub.dev"
source: hosted
version: "9.2.4"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: bf7404619d7ab5c0a1151d7c4e802edad8f33535abfbeff2f9e1fe1274e2d705
url: "https://pub.dev"
source: hosted
version: "1.2.2"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
url: "https://pub.dev"
source: hosted
version: "1.1.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
url: "https://pub.dev"
source: hosted
version: "1.2.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
url: "https://pub.dev"
source: hosted
version: "3.1.2"
flutter_test:
dependency: "direct dev"
description: flutter
@ -349,6 +384,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.3"
google_identity_services_web:
dependency: transitive
description:
name: google_identity_services_web
sha256: "55580f436822d64c8ff9a77e37d61f5fb1e6c7ec9d632a43ee324e2a05c3c6c9"
url: "https://pub.dev"
source: hosted
version: "0.3.3"
google_mobile_ads:
dependency: "direct main"
description:
@ -357,6 +400,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.3.1"
google_sign_in:
dependency: "direct main"
description:
name: google_sign_in
sha256: fad6ddc80c427b0bba705f2116204ce1173e09cf299f85e053d57a55e5b2dd56
url: "https://pub.dev"
source: hosted
version: "6.2.2"
google_sign_in_android:
dependency: transitive
description:
name: google_sign_in_android
sha256: "7af72e5502c313865c729223b60e8ae7bce0a1011b250c24edcf30d3d7032748"
url: "https://pub.dev"
source: hosted
version: "6.1.35"
google_sign_in_ios:
dependency: transitive
description:
name: google_sign_in_ios
sha256: "8468465516a6fdc283ffbbb06ec03a860ee34e9ff84b0454074978705b42379b"
url: "https://pub.dev"
source: hosted
version: "5.8.0"
google_sign_in_platform_interface:
dependency: transitive
description:
name: google_sign_in_platform_interface
sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971"
url: "https://pub.dev"
source: hosted
version: "2.4.5"
google_sign_in_web:
dependency: transitive
description:
name: google_sign_in_web
sha256: ada595df6c30cead48e66b1f3a050edf0c5cf2ba60c185d69690e08adcc6281b
url: "https://pub.dev"
source: hosted
version: "0.12.4+3"
http:
dependency: "direct main"
description:
@ -693,14 +776,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
shared_preferences:
dependency: "direct main"
description:
@ -970,6 +1045,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.18.3"
win32:
dependency: transitive
description:
name: win32
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
url: "https://pub.dev"
source: hosted
version: "5.10.1"
xdg_directories:
dependency: transitive
description:

View File

@ -29,9 +29,6 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
@ -54,7 +51,8 @@ dependencies:
url_launcher: ^6.3.1
mapbox_gl: ^0.16.0
google_mobile_ads: ^5.3.1
encrypt_shared_preferences: ^0.8.8
google_sign_in: ^6.2.2
flutter_facebook_auth: ^7.1.1
dev_dependencies:
flutter_test:
@ -72,7 +70,6 @@ dev_dependencies:
# The following section is specific to Flutter packages.
flutter:
generate: true
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in

View File

@ -7,6 +7,7 @@
#include "generated_plugin_registrant.h"
#include <file_selector_windows/file_selector_windows.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <geolocator_windows/geolocator_windows.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
@ -14,6 +15,8 @@
void RegisterPlugins(flutter::PluginRegistry* registry) {
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_windows
flutter_secure_storage_windows
geolocator_windows
permission_handler_windows
url_launcher_windows