When I change the state of the contents of a tabbar, and navigate to another tabbar page, I have to manually reload the view by pulling down to refresh or navigating to another screen and returning to the tabbar in order for changes to be reflected.
The problem is that whenever I switch tabs, i expect the contents to be updated as well, which is not happening.
[import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../controllers/f10_task_list_controller.dart';
import '../models/f10_task_model.dart';
import 'f10_task_details_screen.dart';
import 'f10_task_creation_screen.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class TaskListScreen extends StatefulWidget {
final String role;
TaskListScreen({required this.role}) {
print('TaskListScreen initialized with role: $role');
}
@override
_TaskListScreenState createState() => _TaskListScreenState();
}
class _TaskListScreenState extends State<TaskListScreen> with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<TaskListController>(context, listen: false).fetchTasks();
});
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
print('Building TaskListScreen for role: ${widget.role}');
return ChangeNotifierProvider(
create: (context) => TaskListController(),
child: Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)?.taskList ?? 'Task List'),
bottom: TabBar(
controller: _tabController,
tabs: [
Tab(text: AppLocalizations.of(context)?.active ?? 'Active'),
Tab(text: AppLocalizations.of(context)?.completed ?? 'Completed'),
Tab(text: AppLocalizations.of(context)?.archived ?? 'Archived'),
],
labelColor: Colors.white,
unselectedLabelColor: Colors.white.withOpacity(0.6),
),
),
body: Consumer<TaskListController>(
builder: (context, controller, child) {
if (controller.isLoading) {
return Center(child: CircularProgressIndicator());
}
return RefreshIndicator(
onRefresh: controller.fetchTasks,
child: TabBarView(
controller: _tabController,
children: [
TaskListView(status: 'active'),
TaskListView(status: 'completed'),
TaskListView(status: 'archived'),
],
),
);
},
),
floatingActionButton: widget.role == 'admin'
? FloatingActionButton(
onPressed: () {
print('Navigating to TaskCreationScreen');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TaskCreationScreen(),
),
);
},
child: Icon(Icons.add),
backgroundColor: Theme.of(context).primaryColor,
)
: null,
),
);
}
}
class TaskListView extends StatelessWidget {
final String status;
TaskListView({required this.status});
@override
Widget build(BuildContext context) {
print('Building TaskListView for status: $status');
return Consumer<TaskListController>(
builder: (context, controller, child) {
List<Task> tasks;
if (status == 'active') {
tasks = controller.activeTasks;
} else if (status == 'completed') {
tasks = controller.completedTasks;
} else {
tasks = controller.archivedTasks;
}
print('Tasks for status $status: ${tasks.length} found');
if (tasks.isEmpty) {
return Center(child: Text('No tasks found'));
}
return ListView.builder(
key: PageStorageKey<String>(status),
itemCount: tasks.length,
itemBuilder: (context, index) {
final task = tasks[index];
print('Building TaskCard for task: ${task.title}');
return TaskCard(task: task, status: status);
},
);
},
);
}
}
class TaskCard extends StatelessWidget {
final Task task;
final String status;
TaskCard({required this.task, required this.status}) {
print('TaskCard initialized for task: ${task.title}');
}
@override
Widget build(BuildContext context) {
print('Building TaskCard for task: ${task.title}');
return GestureDetector(
onLongPress: () {
print('Long pressed on task: ${task.id}');
_showReassignDialog(context, task.id);
},
onTap: () {
print('Tapped on task: ${task.id}');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TaskDetailsScreen(taskId: task.id),
),
);
},
child: Dismissible(
key: UniqueKey(),
background: Container(
alignment: Alignment.centerLeft,
color: Colors.green,
child: Padding(
padding: const EdgeInsets.only(left: 16.0),
child: Icon(Icons.update),
),
),
secondaryBackground: Container(
alignment: Alignment.centerRight,
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(Icons.snooze),
),
),
onDismissed: (direction) {
final controller = Provider.of<TaskListController>(context, listen: false);
controller.removeTask(task.id, status);
if (direction == DismissDirection.endToStart) {
print('Snooze task: ${task.id}');
_showSnoozeDialog(context, task.id);
} else if (direction == DismissDirection.startToEnd) {
print('Update status for task: ${task.id}');
_showUpdateStatusDialog(context, task.id);
}
},
child: Card(
child: ListTile(
title: Text(task.title),
subtitle: Text(task.description),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(task.status),
if (task.snoozeUntil != null)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
'Snoozed',
style: TextStyle(color: Colors.red),
),
),
],
),
),
),
),
);
}
void _showReassignDialog(BuildContext context, String taskId) {
print('Showing reassign dialog for task: $taskId');
showDialog(
context: context,
builder: (context) {
String userId = '';
return AlertDialog(
title: Text('Reassign Task'),
content: TextField(
decoration: InputDecoration(hintText: 'Enter User ID'),
onChanged: (value) {
userId = value;
},
),
actions: [
TextButton(
onPressed: () {
print('Cancelled reassigning task: $taskId');
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
TextButton(
onPressed: () {
if (userId.isNotEmpty) {
print('Reassigning task: $taskId to user: $userId');
Provider.of<TaskListController>(context, listen: false)
.reassignTask(taskId, userId)
.then((_) {
Navigator.of(context).pop();
Provider.of<TaskListController>(context, listen: false)
.fetchTasks();
});
} else {
print('Invalid User ID: $userId');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Invalid User ID')),
);
}
},
child: Text('Reassign'),
),
],
);
},
);
}
void _showSnoozeDialog(BuildContext context, String taskId) {
print('Showing snooze dialog for task: $taskId');
TextEditingController durationController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Snooze Task',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
TextField(
controller: durationController,
decoration: InputDecoration(hintText: 'Enter duration (e.g., 1h, 30m, 2d)'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
String duration = durationController.text;
if (duration.isNotEmpty) {
print('Snooze button pressed with duration: $duration');
Provider.of<TaskListController>(context, listen: false)
.snoozeTask(taskId, duration)
.then((_) {
print('Task snoozed successfully.');
Navigator.of(context).pop();
Provider.of<TaskListController>(context, listen: false)
.fetchTasks();
}).catchError((error) {
print('Error snoozing task: $error');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to snooze task')),
);
});
} else {
print('Invalid duration entered.');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Invalid duration')),
);
}
},
child: Text('Snooze'),
),
],
),
);
},
);
}
void _showUpdateStatusDialog(BuildContext context, String taskId) {
print('Showing update status dialog for task: $taskId');
showDialog(
context: context,
builder: (context) {
String status = 'In Progress';
return AlertDialog(
title: Text('Update Task Status'),
content: DropdownButtonFormField<String>(
value: status,
items: ['In Progress', 'Completed']
.map((label) => DropdownMenuItem(
child: Text(label),
value: label,
))
.toList(),
onChanged: (value) {
status = value!;
},
),
actions: [
TextButton(
onPressed: () {
print('Cancelled updating status for task: $taskId');
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
TextButton(
onPressed: () {
print('Updating status for task: $taskId to $status');
Provider.of<TaskListController>(context, listen: false)
.updateTaskStatus(taskId, status)
.then((_) {
Navigator.of(context).pop();
Provider.of<TaskListController>(context, listen: false)
.fetchTasks();
});
},
child: Text('Update'),
),
],
);
},
);
}
}][1]