Compare commits
16 Commits
feature/ch
...
main
Author | SHA1 | Date | |
---|---|---|---|
452faf05d8 | |||
3a64f1ae36 | |||
afae3293c4 | |||
600bf8d2f4 | |||
ec7a286074 | |||
6c1c650fa1 | |||
7468c5f24c | |||
1bcc8372c6 | |||
510e366216 | |||
52580c6568 | |||
4f7c8f60d0 | |||
ce2a061bf0 | |||
04f4b7ce8e | |||
78ea5f0c10 | |||
395d3390cf | |||
daef20db66 |
@ -10,6 +10,8 @@ import 'alert.dart';
|
|||||||
import '../variable/globals.dart' as globals;
|
import '../variable/globals.dart' as globals;
|
||||||
|
|
||||||
import '../pages/LoginDemo.dart';
|
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 {
|
class MyDrawer extends StatelessWidget with ShowAlertDialog {
|
||||||
Future<void> logout(BuildContext context) async {
|
Future<void> logout(BuildContext context) async {
|
||||||
@ -28,7 +30,20 @@ class MyDrawer extends StatelessWidget with ShowAlertDialog {
|
|||||||
print("Status code logout ${response.statusCode}");
|
print("Status code logout ${response.statusCode}");
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
await prefs.remove("access_token"); // Correctly remove the token
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Navigator.pushAndRemoveUntil(
|
Navigator.pushAndRemoveUntil(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (_) => LoginDemo()),
|
MaterialPageRoute(builder: (_) => LoginDemo()),
|
||||||
|
@ -4,11 +4,14 @@ import 'package:http/http.dart' as http;
|
|||||||
import '../variable/globals.dart' as globals;
|
import '../variable/globals.dart' as globals;
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:encrypt_shared_preferences/provider.dart';
|
||||||
import '../pages/LoginDemo.dart';
|
import '../pages/LoginDemo.dart';
|
||||||
|
import 'package:flutter_dotenv/flutter_dotenv.dart'; // Import dotenv
|
||||||
|
|
||||||
class AuthService {
|
class AuthService {
|
||||||
// Login with username and password
|
// Login with username and password
|
||||||
Future<bool> login(String username, String password) async {
|
Future<bool> login(String username, String password,
|
||||||
|
{bool rememberMe = false}) async {
|
||||||
final url = Uri.parse("${globals.api}/token");
|
final url = Uri.parse("${globals.api}/token");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -18,14 +21,22 @@ class AuthService {
|
|||||||
'accept': 'application/json',
|
'accept': 'application/json',
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
},
|
},
|
||||||
body: {
|
body: {"username": username, "password": password},
|
||||||
"username": username,
|
|
||||||
"password": password,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
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(";") ?? [];
|
final cookies = response.headers["set-cookie"]?.split(";") ?? [];
|
||||||
|
|
||||||
for (final cookie in cookies) {
|
for (final cookie in cookies) {
|
||||||
@ -79,8 +90,25 @@ class AuthService {
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
print("Token is invalid. Status code: ${response.statusCode}");
|
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
|
await prefs.remove("access_token"); // Clear invalid token
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
return login(username, password);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error while checking token: $e");
|
print("Error while checking token: $e");
|
||||||
|
@ -42,17 +42,53 @@ class ListItemOrganizers extends StatefulWidget {
|
|||||||
|
|
||||||
// homepage state
|
// homepage state
|
||||||
class _MyHomePageState extends State<ListItemOrganizers> {
|
class _MyHomePageState extends State<ListItemOrganizers> {
|
||||||
|
int _fetchCount = 0;
|
||||||
|
bool _isLoading = false;
|
||||||
|
late ScrollController _scrollController;
|
||||||
|
|
||||||
final AuthService _authService = AuthService();
|
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
|
// variable to call and store future list of posts
|
||||||
|
|
||||||
// function to fetch data from api and return future list of posts
|
// function to fetch data from api and return future list of posts
|
||||||
static Future<List<Events>> getPosts(organizer) async {
|
static Future<List<Events>> getPosts(organizer, {count = 0}) async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
var accessToken = prefs.getString("access_token") ?? "";
|
var accessToken = prefs.getString("access_token") ?? "";
|
||||||
final List<Events> body = [];
|
final List<Events> body = [];
|
||||||
if (accessToken.isNotEmpty) {
|
if (accessToken.isNotEmpty) {
|
||||||
var url = Uri.parse("${globals.api}/events?organizers=${organizer}");
|
DateTime currentDatetime = DateTime.now();
|
||||||
|
num limit = 20 * (count + 1);
|
||||||
|
var url = Uri.parse(
|
||||||
|
"${globals.api}/events?organizers=${organizer}&limit=${limit}¤t_datetime=${currentDatetime.toString()}");
|
||||||
final response = await http.get(url, headers: {
|
final response = await http.get(url, headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
HttpHeaders.cookieHeader: "access_token=${accessToken}"
|
HttpHeaders.cookieHeader: "access_token=${accessToken}"
|
||||||
@ -67,6 +103,14 @@ class _MyHomePageState extends State<ListItemOrganizers> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_authService.checkTokenStatus(context);
|
_authService.checkTokenStatus(context);
|
||||||
|
_scrollController = ScrollController();
|
||||||
|
_scrollController.addListener(_scrollListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// build function
|
// build function
|
||||||
@ -109,7 +153,10 @@ class _MyHomePageState extends State<ListItemOrganizers> {
|
|||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
body: ListView.separated(
|
body: ListView.separated(
|
||||||
itemCount: posts.length,
|
controller: _scrollController,
|
||||||
|
itemCount: posts.isNotEmpty
|
||||||
|
? posts.length + (_isLoading ? 1 : 0) // Add 1 only if loading
|
||||||
|
: 0,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final post = posts[index];
|
final post = posts[index];
|
||||||
final startDate = DateTime.parse(post.startDate!);
|
final startDate = DateTime.parse(post.startDate!);
|
||||||
|
@ -44,15 +44,53 @@ class ListItemTags extends StatefulWidget {
|
|||||||
class _MyHomePageState extends State<ListItemTags> {
|
class _MyHomePageState extends State<ListItemTags> {
|
||||||
// variable to call and store future list of posts
|
// variable to call and store future list of posts
|
||||||
|
|
||||||
|
int _fetchCount = 0;
|
||||||
|
bool _isLoading = false;
|
||||||
|
late ScrollController _scrollController;
|
||||||
|
|
||||||
final AuthService _authService = AuthService();
|
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
|
// function to fetch data from api and return future list of posts
|
||||||
static Future<List<Events>> getPosts(tags) async {
|
static Future<List<Events>> getPosts(tags, {count = 0}) async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
var accessToken = prefs.getString("access_token") ?? "";
|
var accessToken = prefs.getString("access_token") ?? "";
|
||||||
final List<Events> body = [];
|
final List<Events> body = [];
|
||||||
if (accessToken.isNotEmpty) {
|
if (accessToken.isNotEmpty) {
|
||||||
var url = Uri.parse("${globals.api}/events?tags=${tags}");
|
DateTime currentDatetime = DateTime.now();
|
||||||
|
num limit = 20 * (count + 1);
|
||||||
|
|
||||||
|
var url = Uri.parse(
|
||||||
|
"${globals.api}/events?tags=${tags}&limit=${limit}¤t_datetime=${currentDatetime.toString()}");
|
||||||
final response = await http.get(url, headers: {
|
final response = await http.get(url, headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
HttpHeaders.cookieHeader: "access_token=${accessToken}"
|
HttpHeaders.cookieHeader: "access_token=${accessToken}"
|
||||||
@ -67,6 +105,15 @@ class _MyHomePageState extends State<ListItemTags> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_authService.checkTokenStatus(context);
|
_authService.checkTokenStatus(context);
|
||||||
|
_authService.checkTokenStatus(context);
|
||||||
|
_scrollController = ScrollController();
|
||||||
|
_scrollController.addListener(_scrollListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// build function
|
// build function
|
||||||
@ -108,7 +155,10 @@ class _MyHomePageState extends State<ListItemTags> {
|
|||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
body: ListView.separated(
|
body: ListView.separated(
|
||||||
itemCount: posts.length,
|
controller: _scrollController,
|
||||||
|
itemCount: posts.isNotEmpty
|
||||||
|
? posts.length + (_isLoading ? 1 : 0) // Add 1 only if loading
|
||||||
|
: 0,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final post = posts[index];
|
final post = posts[index];
|
||||||
final startDate = DateTime.parse(post.startDate!);
|
final startDate = DateTime.parse(post.startDate!);
|
||||||
|
@ -48,6 +48,9 @@ class ListItemMenu extends StatefulWidget {
|
|||||||
class _MyHomePageState extends State<ListItemMenu> {
|
class _MyHomePageState extends State<ListItemMenu> {
|
||||||
BannerAd? _bannerAd;
|
BannerAd? _bannerAd;
|
||||||
final AuthService _authService = AuthService();
|
final AuthService _authService = AuthService();
|
||||||
|
late ScrollController _scrollController;
|
||||||
|
int _fetchCount = 0;
|
||||||
|
bool _isLoading = false;
|
||||||
|
|
||||||
Future<List<Events>> postsFuture = getPosts();
|
Future<List<Events>> postsFuture = getPosts();
|
||||||
List<Events> filteredPosts = [];
|
List<Events> filteredPosts = [];
|
||||||
@ -144,6 +147,37 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
return "${year}-${month}-${day}";
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -153,10 +187,19 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
_bannerAd = ad;
|
_bannerAd = ad;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
_scrollController = ScrollController();
|
||||||
|
_scrollController.addListener(_scrollListener);
|
||||||
|
|
||||||
// Initialize data fetch when the page loads
|
// Initialize data fetch when the page loads
|
||||||
_getCurrentLocation();
|
_getCurrentLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
// Get the device's current location
|
// Get the device's current location
|
||||||
Future<void> _getCurrentLocation() async {
|
Future<void> _getCurrentLocation() async {
|
||||||
PermissionStatus status = await Permission.location.status;
|
PermissionStatus status = await Permission.location.status;
|
||||||
@ -346,8 +389,10 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
} else {
|
} else {
|
||||||
queryParameters = dateParameter;
|
queryParameters = dateParameter;
|
||||||
}
|
}
|
||||||
|
int limit = 20 * (_fetchCount + 1);
|
||||||
|
|
||||||
return Uri.parse("${globals.api}/$endpoint?$queryParameters");
|
return Uri.parse(
|
||||||
|
"${globals.api}/$endpoint?$queryParameters&limit=${limit}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> searchSuggestionsByItem(String input) async {
|
Future<void> searchSuggestionsByItem(String input) async {
|
||||||
@ -358,7 +403,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
var url = await getUrlForEvents();
|
var url = await getUrlForEvents();
|
||||||
final response = await http.get(url, headers: {
|
final response = await http.get(url, headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
HttpHeaders.cookieHeader: "access_token=$accessToken"
|
HttpHeaders.cookieHeader: "acce0ss_token=$accessToken"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
@ -422,16 +467,17 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final List<dynamic> body = json.decode(utf8.decode(response.bodyBytes));
|
final List<dynamic> body = json.decode(utf8.decode(response.bodyBytes));
|
||||||
print("results fetch : ${body}");
|
print("results fetch : ${body}");
|
||||||
|
print("fetch count : ${_fetchCount}");
|
||||||
// Update state after getting the response
|
// Update state after getting the response
|
||||||
|
if (body.isEmpty) {
|
||||||
|
_fetchCount--;
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
if (body.isNotEmpty) {
|
if (body.isNotEmpty) {
|
||||||
// If we have results, map them to Events
|
// If we have results, map them to Events
|
||||||
filteredPosts = body
|
filteredPosts = body
|
||||||
.map((e) => Events.fromJson(e as Map<String, dynamic>))
|
.map((e) => Events.fromJson(e as Map<String, dynamic>))
|
||||||
.toList();
|
.toList();
|
||||||
} else {
|
|
||||||
// If no results, clear filteredPosts
|
|
||||||
filteredPosts.clear();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -570,6 +616,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
controller: inputItem,
|
controller: inputItem,
|
||||||
labelText: 'Search by item',
|
labelText: 'Search by item',
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
_fetchCount = 0;
|
||||||
if (value.isNotEmpty) {
|
if (value.isNotEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
itemName = value;
|
itemName = value;
|
||||||
@ -587,6 +634,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClear: () {
|
onClear: () {
|
||||||
|
_fetchCount = 0;
|
||||||
setState(() {
|
setState(() {
|
||||||
inputItem.clear();
|
inputItem.clear();
|
||||||
itemName = '';
|
itemName = '';
|
||||||
@ -598,6 +646,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
},
|
},
|
||||||
suggestions: suggestionsItem,
|
suggestions: suggestionsItem,
|
||||||
onSuggestionTap: (suggestion) async {
|
onSuggestionTap: (suggestion) async {
|
||||||
|
_fetchCount = 0;
|
||||||
setState(() {
|
setState(() {
|
||||||
itemName = suggestion['name'];
|
itemName = suggestion['name'];
|
||||||
inputItem.text = itemName;
|
inputItem.text = itemName;
|
||||||
@ -613,6 +662,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
controller: inputTags,
|
controller: inputTags,
|
||||||
labelText: 'Search by tags',
|
labelText: 'Search by tags',
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
_fetchCount = 0;
|
||||||
if (value.isNotEmpty) {
|
if (value.isNotEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
itemTags = value;
|
itemTags = value;
|
||||||
@ -630,6 +680,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClear: () {
|
onClear: () {
|
||||||
|
_fetchCount = 0;
|
||||||
setState(() {
|
setState(() {
|
||||||
inputTags.clear();
|
inputTags.clear();
|
||||||
});
|
});
|
||||||
@ -637,6 +688,8 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
},
|
},
|
||||||
suggestions: suggestionsTags,
|
suggestions: suggestionsTags,
|
||||||
onSuggestionTap: (suggestion) async {
|
onSuggestionTap: (suggestion) async {
|
||||||
|
_fetchCount = 0;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
itemTags = suggestion['name'];
|
itemTags = suggestion['name'];
|
||||||
inputTags.text = itemTags;
|
inputTags.text = itemTags;
|
||||||
@ -660,6 +713,8 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
controller: inputGeo,
|
controller: inputGeo,
|
||||||
labelText: 'Search by geographical zone',
|
labelText: 'Search by geographical zone',
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
|
_fetchCount = 0;
|
||||||
|
|
||||||
if (value.isNotEmpty) {
|
if (value.isNotEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
geographicalZone = value;
|
geographicalZone = value;
|
||||||
@ -681,6 +736,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClear: () async {
|
onClear: () async {
|
||||||
|
_fetchCount = 0;
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
prefs.remove("city_lat");
|
prefs.remove("city_lat");
|
||||||
prefs.remove("city_long");
|
prefs.remove("city_long");
|
||||||
@ -696,6 +752,7 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
},
|
},
|
||||||
suggestions: suggestionsGeo,
|
suggestions: suggestionsGeo,
|
||||||
onSuggestionTap: (suggestion) async {
|
onSuggestionTap: (suggestion) async {
|
||||||
|
_fetchCount = 0;
|
||||||
final latitude = suggestion['geometry']['coordinates'][1];
|
final latitude = suggestion['geometry']['coordinates'][1];
|
||||||
final longitude = suggestion['geometry']['coordinates'][0];
|
final longitude = suggestion['geometry']['coordinates'][0];
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -770,12 +827,22 @@ class _MyHomePageState extends State<ListItemMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ListView.separated(
|
return ListView.separated(
|
||||||
itemCount: displayedPosts.length,
|
controller: _scrollController,
|
||||||
|
itemCount: displayedPosts.isNotEmpty
|
||||||
|
? displayedPosts.length +
|
||||||
|
(_isLoading ? 1 : 0) // Add 1 only if loading
|
||||||
|
: 0,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
|
if (index >= displayedPosts.length) {
|
||||||
|
return _isLoading
|
||||||
|
? Center(child: CircularProgressIndicator())
|
||||||
|
: SizedBox.shrink();
|
||||||
|
}
|
||||||
final post = displayedPosts[index];
|
final post = displayedPosts[index];
|
||||||
final startDate = DateTime.parse(post.startDate!);
|
final startDate = DateTime.parse(post.startDate!);
|
||||||
final date = DateFormat.yMd().format(startDate);
|
final date = DateFormat.yMd().format(startDate);
|
||||||
final time = DateFormat.Hm().format(startDate);
|
final time = DateFormat.Hm().format(startDate);
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text('${post.name!}'),
|
title: Text('${post.name!}'),
|
||||||
subtitle: Text('${post.place!}\n${date} ${time}'),
|
subtitle: Text('${post.place!}\n${date} ${time}'),
|
||||||
|
@ -18,6 +18,7 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
|
|||||||
TextEditingController inputPseudo = TextEditingController();
|
TextEditingController inputPseudo = TextEditingController();
|
||||||
TextEditingController inputPassword = TextEditingController();
|
TextEditingController inputPassword = TextEditingController();
|
||||||
final AuthService _authService = AuthService();
|
final AuthService _authService = AuthService();
|
||||||
|
bool _rememberMe = false;
|
||||||
|
|
||||||
Future<void> _login(BuildContext context) async {
|
Future<void> _login(BuildContext context) async {
|
||||||
final pseudo = inputPseudo.text;
|
final pseudo = inputPseudo.text;
|
||||||
@ -28,7 +29,8 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = await _authService.login(pseudo, password);
|
bool success =
|
||||||
|
await _authService.login(pseudo, password, rememberMe: _rememberMe);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
@ -53,7 +55,6 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
|
|||||||
|
|
||||||
Future<void> _checkLoginStatus() async {
|
Future<void> _checkLoginStatus() async {
|
||||||
bool loggedIn = await _authService.isLoggedIn();
|
bool loggedIn = await _authService.isLoggedIn();
|
||||||
print("logged status : ${loggedIn}");
|
|
||||||
if (loggedIn) {
|
if (loggedIn) {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context, MaterialPageRoute(builder: (_) => ListItemMenu()));
|
context, MaterialPageRoute(builder: (_) => ListItemMenu()));
|
||||||
@ -109,6 +110,15 @@ class _LoginDemoState extends State<LoginDemo> with ShowAlertDialog {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
CheckboxListTile(
|
||||||
|
title: Text("Se souvenir de moi"),
|
||||||
|
value: _rememberMe,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
_rememberMe = newValue ?? false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(context,
|
Navigator.push(context,
|
||||||
|
@ -9,6 +9,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.1"
|
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:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -89,6 +105,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.18.0"
|
version: "1.18.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
cross_file:
|
cross_file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -137,6 +161,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
encrypt:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: encrypt
|
||||||
|
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
|
||||||
|
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"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -648,6 +688,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
version: "2.1.8"
|
||||||
|
pointycastle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pointycastle
|
||||||
|
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.9.1"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -51,6 +51,7 @@ dependencies:
|
|||||||
url_launcher: ^6.3.1
|
url_launcher: ^6.3.1
|
||||||
mapbox_gl: ^0.16.0
|
mapbox_gl: ^0.16.0
|
||||||
google_mobile_ads: ^5.3.1
|
google_mobile_ads: ^5.3.1
|
||||||
|
encrypt_shared_preferences: ^0.8.8
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user