Compare commits

...

3 Commits

Author SHA1 Message Date
510e366216 add pagination 2025-03-24 22:47:49 +01:00
52580c6568 fetchCount to 0 2025-03-24 22:10:49 +01:00
4f7c8f60d0 add increment and decrement to pagination 2025-03-19 23:40:38 +01:00
4 changed files with 200 additions and 10 deletions

View File

@ -42,17 +42,62 @@ 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 _decrementFetchCount() {
setState(() {
if (_fetchCount > 0) {
_fetchCount--;
}
});
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_incrementFetchCount();
} else if (_scrollController.position.pixels ==
_scrollController.position.minScrollExtent) {
_decrementFetchCount();
}
_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) async {
static Future<List<Events>> getPosts(organizer, {count = 0}) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? "";
final List<Events> body = [];
if (accessToken.isNotEmpty) {
var url = Uri.parse("${globals.api}/events?organizers=${organizer}");
var url = Uri.parse(
"${globals.api}/events?organizers=${organizer}&skip=${count}");
final response = await http.get(url, headers: {
"Content-Type": "application/json",
HttpHeaders.cookieHeader: "access_token=${accessToken}"
@ -67,6 +112,14 @@ class _MyHomePageState extends State<ListItemOrganizers> {
void initState() {
super.initState();
_authService.checkTokenStatus(context);
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// build function
@ -109,7 +162,10 @@ class _MyHomePageState extends State<ListItemOrganizers> {
foregroundColor: Colors.white,
),
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) {
final post = posts[index];
final startDate = DateTime.parse(post.startDate!);

View File

@ -44,15 +44,59 @@ 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 _decrementFetchCount() {
setState(() {
if (_fetchCount > 0) {
_fetchCount--;
}
});
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_incrementFetchCount();
} else if (_scrollController.position.pixels ==
_scrollController.position.minScrollExtent) {
_decrementFetchCount();
}
_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) async {
static Future<List<Events>> getPosts(tags, {count = 0}) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var accessToken = prefs.getString("access_token") ?? "";
final List<Events> body = [];
if (accessToken.isNotEmpty) {
var url = Uri.parse("${globals.api}/events?tags=${tags}");
var url = Uri.parse("${globals.api}/events?tags=${tags}&skip=${count}");
final response = await http.get(url, headers: {
"Content-Type": "application/json",
HttpHeaders.cookieHeader: "access_token=${accessToken}"
@ -67,6 +111,15 @@ class _MyHomePageState extends State<ListItemTags> {
void initState() {
super.initState();
_authService.checkTokenStatus(context);
_authService.checkTokenStatus(context);
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// build function
@ -108,7 +161,10 @@ class _MyHomePageState extends State<ListItemTags> {
foregroundColor: Colors.white,
),
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) {
final post = posts[index];
final startDate = DateTime.parse(post.startDate!);

View File

@ -48,6 +48,9 @@ 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 = [];
@ -144,6 +147,46 @@ class _MyHomePageState extends State<ListItemMenu> {
return "${year}-${month}-${day}";
}
void _incrementFetchCount() {
setState(() {
_fetchCount++;
});
}
void _decrementFetchCount() {
setState(() {
if (_fetchCount > 0 && filteredPosts.isNotEmpty) {
_fetchCount--;
}
});
}
void _scrollListener() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_incrementFetchCount();
} else if (_scrollController.position.pixels ==
_scrollController.position.minScrollExtent) {
_decrementFetchCount();
}
_fetchData();
}
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();
@ -153,10 +196,19 @@ class _MyHomePageState extends State<ListItemMenu> {
_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;
@ -347,7 +399,8 @@ class _MyHomePageState extends State<ListItemMenu> {
queryParameters = dateParameter;
}
return Uri.parse("${globals.api}/$endpoint?$queryParameters");
return Uri.parse(
"${globals.api}/$endpoint?$queryParameters&skip=${_fetchCount}");
}
Future<void> searchSuggestionsByItem(String input) async {
@ -570,6 +623,7 @@ class _MyHomePageState extends State<ListItemMenu> {
controller: inputItem,
labelText: 'Search by item',
onChanged: (value) {
_fetchCount = 0;
if (value.isNotEmpty) {
setState(() {
itemName = value;
@ -587,6 +641,7 @@ class _MyHomePageState extends State<ListItemMenu> {
}
},
onClear: () {
_fetchCount = 0;
setState(() {
inputItem.clear();
itemName = '';
@ -598,6 +653,8 @@ class _MyHomePageState extends State<ListItemMenu> {
},
suggestions: suggestionsItem,
onSuggestionTap: (suggestion) async {
_fetchCount = 0;
setState(() {
itemName = suggestion['name'];
inputItem.text = itemName;
@ -613,6 +670,8 @@ class _MyHomePageState extends State<ListItemMenu> {
controller: inputTags,
labelText: 'Search by tags',
onChanged: (value) {
_fetchCount = 0;
if (value.isNotEmpty) {
setState(() {
itemTags = value;
@ -630,6 +689,7 @@ class _MyHomePageState extends State<ListItemMenu> {
}
},
onClear: () {
_fetchCount = 0;
setState(() {
inputTags.clear();
});
@ -637,6 +697,8 @@ class _MyHomePageState extends State<ListItemMenu> {
},
suggestions: suggestionsTags,
onSuggestionTap: (suggestion) async {
_fetchCount = 0;
setState(() {
itemTags = suggestion['name'];
inputTags.text = itemTags;
@ -660,6 +722,8 @@ class _MyHomePageState extends State<ListItemMenu> {
controller: inputGeo,
labelText: 'Search by geographical zone',
onChanged: (value) async {
_fetchCount = 0;
if (value.isNotEmpty) {
setState(() {
geographicalZone = value;
@ -681,6 +745,8 @@ class _MyHomePageState extends State<ListItemMenu> {
}
},
onClear: () async {
_fetchCount = 0;
final prefs = await SharedPreferences.getInstance();
prefs.remove("city_lat");
prefs.remove("city_long");
@ -696,6 +762,8 @@ 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(() {
@ -770,12 +838,22 @@ class _MyHomePageState extends State<ListItemMenu> {
}
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) {
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);
return ListTile(
title: Text('${post.name!}'),
subtitle: Text('${post.place!}\n${date} ${time}'),

View File

@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: args
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.6.0"
version: "2.7.0"
asn1lib:
dependency: transitive
description: