summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2023-04-14 17:58:15 -0600
committerIván Ávalos <avalos@disroot.org>2023-04-14 17:58:15 -0600
commit80bad7a1b1c31fb7a28d74796adcf44ee319f586 (patch)
tree81ed35abb8637072fc8395e27775587bb007dd0c
parent1a796abe772e6d2de69b6c2d7f0944cd0c19289d (diff)
downloadpmsna1-80bad7a1b1c31fb7a28d74796adcf44ee319f586.tar.gz
pmsna1-80bad7a1b1c31fb7a28d74796adcf44ee319f586.tar.bz2
pmsna1-80bad7a1b1c31fb7a28d74796adcf44ee319f586.zip
Fully implemented events
-rw-r--r--lib/models/event.dart2
-rw-r--r--lib/providers/events_provider.dart10
-rw-r--r--lib/screens/events_screen.dart87
-rw-r--r--lib/screens/new_event_screen.dart24
-rw-r--r--lib/utils.dart5
-rw-r--r--lib/widgets/event_item.dart96
6 files changed, 186 insertions, 38 deletions
diff --git a/lib/models/event.dart b/lib/models/event.dart
index d9ef6f6..1c050ad 100644
--- a/lib/models/event.dart
+++ b/lib/models/event.dart
@@ -16,7 +16,7 @@ class Event {
id: map["id"],
description: map["description"],
date: DateTime.parse(map["date"]),
- completed: map["date"] == 1,
+ completed: map["completed"] == 1,
);
}
}
diff --git a/lib/providers/events_provider.dart b/lib/providers/events_provider.dart
index eee9853..01b6982 100644
--- a/lib/providers/events_provider.dart
+++ b/lib/providers/events_provider.dart
@@ -1,6 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:pmsna1/database/helper.dart';
import 'package:pmsna1/models/event.dart';
+import 'package:table_calendar/table_calendar.dart';
class EventsProvider with ChangeNotifier {
DatabaseHelper helper = DatabaseHelper();
@@ -25,4 +26,13 @@ class EventsProvider with ChangeNotifier {
events = e;
});
}
+
+ Future<void> deleteEvent(int id) async {
+ await helper.delete('events', 'id', id);
+ fetchDB();
+ }
+
+ List<Event> getEventsForDay(DateTime day) {
+ return events.where((e) => isSameDay(e.date, day)).toList();
+ }
}
diff --git a/lib/screens/events_screen.dart b/lib/screens/events_screen.dart
index 0b78fbe..9183e5e 100644
--- a/lib/screens/events_screen.dart
+++ b/lib/screens/events_screen.dart
@@ -1,6 +1,10 @@
import 'package:flutter/material.dart';
+import 'package:pmsna1/utils.dart';
+import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
+import '../models/event.dart';
+import '../providers/events_provider.dart';
import '../widgets/event_list.dart';
enum Vista { calendario, lista }
@@ -18,8 +22,32 @@ class _EventsScreenState extends State<EventsScreen> {
DateTime _focusedDay = DateTime.now();
CalendarFormat _calendarFormat = CalendarFormat.month;
+ Color? getEventColor(Event e) {
+ DateTime today = DateTime.now();
+ if (daysBetween(today, e.date) > 0 && daysBetween(today, e.date) <= 2) {
+ // 7. Cuando el evento esté a 2 días de realizarse, la
+ // celda del calendario deberá pintarse de color amarillo
+ return Colors.yellow;
+ } else if (isSameDay(e.date, today)) {
+ // 8. Cuando el evento sea el día en curso cambiará a un
+ // color verde
+ return Colors.green;
+ } else if (today.isAfter(e.date) && !e.completed) {
+ // 9. Cuando el evento ya haya pasado y no se haya
+ // completado, entonces se marcará en rojo
+ return Colors.red;
+ } else if (today.isAfter(e.date) && e.completed) {
+ // 10. Si el evento ya pasó y está como completado se
+ // dejará en verde
+ return Colors.green;
+ }
+ return null;
+ }
+
@override
Widget build(BuildContext context) {
+ EventsProvider provider = Provider.of<EventsProvider>(context);
+
return Scaffold(
appBar: AppBar(
title: const Text('Eventos'),
@@ -47,25 +75,46 @@ class _EventsScreenState extends State<EventsScreen> {
),
body: Container(
child: vista == Vista.calendario
- ? TableCalendar(
- firstDay: DateTime.fromMicrosecondsSinceEpoch(0),
- lastDay: DateTime.utc(9000, 12, 31),
- focusedDay: _focusedDay,
- selectedDayPredicate: (day) {
- return isSameDay(_selectedDay, day);
- },
- onDaySelected: (selectedDay, focusedDay) {
- setState(() {
- _selectedDay = selectedDay;
- _focusedDay = focusedDay;
- });
- },
- calendarFormat: _calendarFormat,
- onFormatChanged: (format) {
- setState(() {
- _calendarFormat = format;
- });
- },
+ ? SingleChildScrollView(
+ child: TableCalendar(
+ firstDay: DateTime.fromMicrosecondsSinceEpoch(0),
+ lastDay: DateTime.utc(9000, 12, 31),
+ focusedDay: _focusedDay,
+ selectedDayPredicate: (day) {
+ return isSameDay(_selectedDay, day);
+ },
+ onDaySelected: (selectedDay, focusedDay) {
+ setState(() {
+ _selectedDay = selectedDay;
+ _focusedDay = focusedDay;
+ });
+ },
+ calendarFormat: _calendarFormat,
+ onFormatChanged: (format) {
+ setState(() {
+ _calendarFormat = format;
+ });
+ },
+ eventLoader: (day) => provider.getEventsForDay(day),
+ // Source: https://stackoverflow.com/a/69036998
+ calendarBuilders: CalendarBuilders(
+ singleMarkerBuilder: (context, day, event) {
+ if (event == null) return null;
+ Event e = event as Event;
+ Color color = getEventColor(e) ??
+ Theme.of(context).colorScheme.onSurface;
+ return Container(
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: color,
+ ),
+ width: 5.0,
+ height: 5.0,
+ margin: const EdgeInsets.symmetric(horizontal: 1.5),
+ );
+ },
+ ),
+ ),
)
: const EventList()),
floatingActionButton: FloatingActionButton.extended(
diff --git a/lib/screens/new_event_screen.dart b/lib/screens/new_event_screen.dart
index 3c49ee6..2e8b52f 100644
--- a/lib/screens/new_event_screen.dart
+++ b/lib/screens/new_event_screen.dart
@@ -14,11 +14,13 @@ class NewEventScreen extends StatefulWidget {
class _NewEventScreenState extends State<NewEventScreen> {
Event? event;
+ bool isEventSet = false;
DateTime? selectedDate;
DatabaseHelper helper = DatabaseHelper();
final _descController = TextEditingController();
final _formKey = GlobalKey<FormState>();
+ bool completed = false;
final padding = 12.0;
Widget get spacer => SizedBox(height: padding, width: padding);
@@ -26,11 +28,13 @@ class _NewEventScreenState extends State<NewEventScreen> {
@override
Widget build(BuildContext context) {
event = ModalRoute.of(context)?.settings.arguments as Event?;
- if (event != null) {
+ if (event != null && !isEventSet) {
_descController.text = event!.description;
setState(() {
selectedDate = event!.date;
+ completed = event!.completed;
});
+ isEventSet = true;
}
EventsProvider provider = Provider.of<EventsProvider>(context);
@@ -54,7 +58,7 @@ class _NewEventScreenState extends State<NewEventScreen> {
helper.insert('events', {
'description': _descController.text,
'date': selectedDate!.toIso8601String(),
- 'completed': false, // TODO: implement checkbox
+ 'completed': completed == true ? 1 : 0,
}).then((value) {
SnackBar bar = SnackBar(
content: Text(
@@ -73,7 +77,7 @@ class _NewEventScreenState extends State<NewEventScreen> {
{
'description': _descController.text,
'date': selectedDate!.toIso8601String(),
- 'completed': false,
+ 'completed': completed == true ? 1 : 0,
},
'id',
event!.id,
@@ -115,14 +119,24 @@ class _NewEventScreenState extends State<NewEventScreen> {
},
),
spacer,
+ CheckboxListTile(
+ value: completed,
+ title: const Text('Completado'),
+ onChanged: (value) {
+ setState(() {
+ completed = value == true;
+ });
+ },
+ ),
+ spacer,
OutlinedButton(
child: Text(selectedDate != null
? selectedDate!.toIso8601String()
: 'Seleccionar fecha'),
onPressed: () {
showDatePicker(
- initialDate: DateTime.now(),
- firstDate: DateTime.now(),
+ initialDate: selectedDate ?? DateTime.now(),
+ firstDate: DateTime.fromMicrosecondsSinceEpoch(0),
lastDate: DateTime.utc(9000, 12, 31),
currentDate: DateTime.now(),
initialEntryMode: DatePickerEntryMode.calendar,
diff --git a/lib/utils.dart b/lib/utils.dart
new file mode 100644
index 0000000..79bee4e
--- /dev/null
+++ b/lib/utils.dart
@@ -0,0 +1,5 @@
+int daysBetween(DateTime from, DateTime to) {
+ from = DateTime(from.year, from.month, from.day);
+ to = DateTime(to.year, to.month, to.day);
+ return (to.difference(from).inHours / 24).round();
+}
diff --git a/lib/widgets/event_item.dart b/lib/widgets/event_item.dart
index e00d328..eb65566 100644
--- a/lib/widgets/event_item.dart
+++ b/lib/widgets/event_item.dart
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
import '../models/event.dart';
+import '../providers/events_provider.dart';
class EventItem extends StatelessWidget {
final Event event;
@@ -16,25 +18,93 @@ class EventItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final txtDate = Text(
- event.date.toIso8601String(),
- style: Theme.of(context).typography.englishLike.labelMedium,
+ event.date.toString().split(' ').first,
+ style: Theme.of(context).typography.englishLike.labelMedium?.copyWith(
+ color: Theme.of(context).colorScheme.onSurfaceVariant,
+ ),
);
final txtDesc = Text(
event.description,
- style: Theme.of(context).typography.englishLike.bodyLarge,
+ style: Theme.of(context).typography.englishLike.bodyLarge?.copyWith(
+ color: Theme.of(context).colorScheme.onSurfaceVariant,
+ decoration: event.completed == true
+ ? TextDecoration.lineThrough
+ : TextDecoration.none,
+ ),
);
+ EventsProvider provider = context.watch<EventsProvider>();
+
return Card(
- child: Padding(
- padding: EdgeInsets.all(padding),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- txtDesc,
- spacer,
- txtDate,
- ],
+ semanticContainer: true,
+ clipBehavior: Clip.antiAliasWithSaveLayer,
+ child: InkWell(
+ onTap: () {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: Text(event.description),
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ ListTile(
+ title: const Text('ID'),
+ subtitle: Text(event.id.toString()),
+ ),
+ ListTile(
+ title: const Text('Fecha'),
+ subtitle: Text(event.date.toIso8601String()),
+ ),
+ ListTile(
+ title: const Text('Completado'),
+ subtitle: Text(event.completed == true ? "Sí" : "No"),
+ ),
+ ],
+ ),
+ actions: [
+ TextButton(
+ child: const Text('OK'),
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ )
+ ],
+ ),
+ );
+ },
+ child: Padding(
+ padding: EdgeInsets.all(padding),
+ child: Row(
+ children: [
+ Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ txtDesc,
+ spacer,
+ txtDate,
+ ],
+ ),
+ const Expanded(child: SizedBox.shrink()),
+ ButtonBar(
+ children: [
+ IconButton(
+ icon: const Icon(Icons.edit),
+ onPressed: () {
+ Navigator.of(context)
+ .pushNamed('/newevent', arguments: event);
+ },
+ ),
+ IconButton(
+ icon: const Icon(Icons.delete),
+ onPressed: () {
+ provider.deleteEvent(event.id);
+ },
+ )
+ ],
+ ),
+ ],
+ ),
),
),
);