Add todos admin and 30s refresh
This commit is contained in:
@@ -13,6 +13,8 @@ import '../../services/family_service.dart';
|
||||
import '../../services/photo_service.dart';
|
||||
import '../../services/announcement_service.dart';
|
||||
import '../../services/schedule_service.dart';
|
||||
import '../../models/todo_item.dart';
|
||||
import '../../services/todo_service.dart';
|
||||
|
||||
class AdminScreen extends StatefulWidget {
|
||||
const AdminScreen({super.key});
|
||||
@@ -25,7 +27,7 @@ class _AdminScreenState extends State<AdminScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
length: 5,
|
||||
length: 6,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Admin Settings'),
|
||||
@@ -37,6 +39,7 @@ class _AdminScreenState extends State<AdminScreen> {
|
||||
Tab(text: 'Bible Verses'),
|
||||
Tab(text: 'Announcements'),
|
||||
Tab(text: 'Schedules'),
|
||||
Tab(text: 'Todos'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -47,6 +50,7 @@ class _AdminScreenState extends State<AdminScreen> {
|
||||
BibleVerseManagerTab(),
|
||||
AnnouncementManagerTab(),
|
||||
ScheduleManagerTab(),
|
||||
TodoManagerTab(),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -1239,3 +1243,226 @@ class _ScheduleManagerTabState extends State<ScheduleManagerTab> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TodoManagerTab extends StatefulWidget {
|
||||
const TodoManagerTab({super.key});
|
||||
|
||||
@override
|
||||
State<TodoManagerTab> createState() => _TodoManagerTabState();
|
||||
}
|
||||
|
||||
class _TodoManagerTabState extends State<TodoManagerTab> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => _showAddTodoDialog(context),
|
||||
child: const Icon(Icons.check_box),
|
||||
),
|
||||
body: FutureBuilder<List<TodoItem>>(
|
||||
future: Provider.of<TodoService>(context).fetchTodos(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
final todos = snapshot.data!;
|
||||
if (todos.isEmpty) {
|
||||
return const Center(
|
||||
child: Text(
|
||||
'No todos added yet',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
);
|
||||
}
|
||||
return ListView.builder(
|
||||
itemCount: todos.length,
|
||||
itemBuilder: (context, index) {
|
||||
final todo = todos[index];
|
||||
return ListTile(
|
||||
leading: Checkbox(
|
||||
value: todo.completed,
|
||||
onChanged: (val) async {
|
||||
await Provider.of<TodoService>(
|
||||
context,
|
||||
listen: false,
|
||||
).updateTodo(
|
||||
TodoItem(
|
||||
id: todo.id,
|
||||
familyMemberId: todo.familyMemberId,
|
||||
title: todo.title,
|
||||
completed: val ?? false,
|
||||
dueDate: todo.dueDate,
|
||||
),
|
||||
);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
todo.title,
|
||||
style: TextStyle(
|
||||
decoration:
|
||||
todo.completed ? TextDecoration.lineThrough : null,
|
||||
),
|
||||
),
|
||||
subtitle: todo.dueDate != null
|
||||
? Text(
|
||||
todo.dueDate!.toIso8601String().split('T')[0],
|
||||
style:
|
||||
const TextStyle(fontSize: 12, color: Colors.grey),
|
||||
)
|
||||
: null,
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.blue),
|
||||
onPressed: () => _showEditTodoDialog(context, todo),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete, color: Colors.red),
|
||||
onPressed: () async {
|
||||
await Provider.of<TodoService>(
|
||||
context,
|
||||
listen: false,
|
||||
).deleteTodo(todo.id);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showAddTodoDialog(BuildContext context) {
|
||||
_showTodoDialog(context, null);
|
||||
}
|
||||
|
||||
void _showEditTodoDialog(BuildContext context, TodoItem todo) {
|
||||
_showTodoDialog(context, todo);
|
||||
}
|
||||
|
||||
void _showTodoDialog(BuildContext context, TodoItem? todo) {
|
||||
final isEditing = todo != null;
|
||||
final titleController = TextEditingController(text: todo?.title ?? '');
|
||||
final dateController = TextEditingController(
|
||||
text: todo?.dueDate?.toIso8601String().split('T')[0] ?? '',
|
||||
);
|
||||
|
||||
String? selectedFamilyMemberId = todo?.familyMemberId;
|
||||
bool isCompleted = todo?.completed ?? false;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => StatefulBuilder(
|
||||
builder: (context, setDialogState) => AlertDialog(
|
||||
title: Text(isEditing ? 'Edit Todo' : 'Add Todo'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: titleController,
|
||||
decoration: const InputDecoration(labelText: 'Title'),
|
||||
),
|
||||
TextField(
|
||||
controller: dateController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Due Date (YYYY-MM-DD)',
|
||||
hintText: '2024-01-01',
|
||||
),
|
||||
),
|
||||
FutureBuilder<List<FamilyMember>>(
|
||||
future: Provider.of<FamilyService>(context, listen: false)
|
||||
.fetchFamilyMembers(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) return const SizedBox();
|
||||
final members = snapshot.data!;
|
||||
return DropdownButtonFormField<String>(
|
||||
value: selectedFamilyMemberId,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Family Member',
|
||||
),
|
||||
items: members.map((member) {
|
||||
return DropdownMenuItem(
|
||||
value: member.id,
|
||||
child: Text(member.name),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setDialogState(() {
|
||||
selectedFamilyMemberId = value;
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
if (isEditing)
|
||||
SwitchListTile(
|
||||
title: const Text('Completed'),
|
||||
value: isCompleted,
|
||||
onChanged: (value) {
|
||||
setDialogState(() {
|
||||
isCompleted = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
if (titleController.text.isNotEmpty &&
|
||||
selectedFamilyMemberId != null) {
|
||||
final date = dateController.text.isNotEmpty
|
||||
? DateTime.tryParse(dateController.text)
|
||||
: null;
|
||||
|
||||
final newItem = TodoItem(
|
||||
id: todo?.id ?? '',
|
||||
familyMemberId: selectedFamilyMemberId!,
|
||||
title: titleController.text,
|
||||
completed: isCompleted,
|
||||
dueDate: date,
|
||||
);
|
||||
|
||||
if (isEditing) {
|
||||
await Provider.of<TodoService>(
|
||||
context,
|
||||
listen: false,
|
||||
).updateTodo(newItem);
|
||||
} else {
|
||||
await Provider.of<TodoService>(
|
||||
context,
|
||||
listen: false,
|
||||
).createTodo(newItem);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
setState(() {});
|
||||
}
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Title and Family Member are required')),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(isEditing ? 'Save' : 'Add'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user