import 'package:diameter/utils/dialog_utils.dart'; import 'package:diameter/models/log_event.dart'; import 'package:diameter/models/settings.dart'; import 'package:diameter/screens/log/log_event_detail.dart'; import 'package:diameter/utils/date_time_utils.dart'; import 'package:flutter/material.dart'; import 'package:diameter/navigation.dart'; class LogEventListScreen extends StatefulWidget { static const String routeName = '/log-events'; const LogEventListScreen({Key? key}) : super(key: key); @override _LogEventListScreenState createState() => _LogEventListScreenState(); } class _LogEventListScreenState extends State { List _activeEvents = []; late List _logEvents; final ScrollController _scrollController = ScrollController(); final TextEditingController _dateController = TextEditingController(text: ''); late DateTime _date; bool _showActive = true; String? swipeDirection; @override void initState() { super.initState(); _date = DateTime.now(); _dateController.text = DateTimeUtils.displayDate(_date); reload(); } @override void dispose() { _scrollController.dispose(); _dateController.dispose(); super.dispose(); } void reload({String? message}) { setState(() { _activeEvents = LogEvent.getAllActiveForTime(DateTime.now()); _logEvents = LogEvent.getAllForDate(_date); }); setState(() { if (message != null) { var snackBar = SnackBar( content: Text(message), duration: const Duration(seconds: 2), ); ScaffoldMessenger.of(context) ..removeCurrentSnackBar() ..showSnackBar(snackBar); } }); } void handleAddNewEvent() async { Navigator.push( context, MaterialPageRoute( builder: (context) { return _date.isAtSameMomentAs(DateTimeUtils.today()) ? const LogEventDetailScreen() : LogEventDetailScreen( suggestedDate: _date, ); }, ), ).then((result) => reload(message: result?[0])); } void handleEditAction(LogEvent event) { Navigator.push( context, MaterialPageRoute( builder: (context) => LogEventDetailScreen( id: event.id, ), ), ).then((result) => reload(message: result?[0])); } void onDelete(LogEvent logEvent) { LogEvent.remove(logEvent.id); reload(message: 'Event deleted'); } void handleDeleteAction(LogEvent logEvent) async { if (Settings.get().showConfirmationDialogOnDelete) { DialogUtils.showConfirmationDialog( context: context, onConfirm: () => onDelete(logEvent), message: 'Are you sure you want to delete this Event?', ); } else { onDelete(logEvent); } } void onStop(LogEvent event) async { event.endTime = DateTime.now(); LogEvent.put(event); reload(message: 'Event ended'); } void handleStopAction(LogEvent event) async { if (Settings.get().showConfirmationDialogOnStopEvent) { DialogUtils.showConfirmationDialog( context: context, onConfirm: () => onStop(event), message: 'Are you sure you want to end this Event?', confirmationLabel: 'END EVENT', ); } else { onStop(event); } } void onChangeDate(DateTime? date) { if (date != null) { setState(() { _date = DateTime(date.year, date.month, date.day); _dateController.text = DateTimeUtils.displayDate(date); }); reload(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Log Events'), actions: [ IconButton( onPressed: () => onChangeDate(DateTime.now()), icon: const Icon(Icons.today)), IconButton(onPressed: reload, icon: const Icon(Icons.refresh)) ], ), drawer: const Navigation(currentLocation: LogEventListScreen.routeName), body: GestureDetector( onPanUpdate: (details) { swipeDirection = details.delta.dx < 0 ? 'left' : 'right'; }, onPanEnd: (details) { if (swipeDirection == null) { return; } if (swipeDirection == 'right' && !_date.isAtSameMomentAs(DateTime(2000, 1, 1))) { onChangeDate(_date.subtract(const Duration(days: 1))); } if (swipeDirection == 'left' && _date.add(const Duration(days: 1)).isBefore(DateTime.now())) { onChangeDate(_date.add(const Duration(days: 1))); } }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTap: () => setState(() { _showActive = !_showActive; }), child: Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisSize: MainAxisSize.max, children: [ Expanded( child: Text( 'ACTIVE EVENTS', style: Theme.of(context).textTheme.subtitle2, textAlign: TextAlign.center, ), ), Icon(_showActive ? Icons.expand_less : Icons.expand_more), ], ), ), ), !_showActive ? Container() : _activeEvents.isNotEmpty ? ListView.builder( shrinkWrap: true, padding: const EdgeInsets.all(10.0), itemCount: _activeEvents.length, itemBuilder: (context, index) { LogEvent event = _activeEvents[index]; return Card( child: ListTile( onTap: () { handleEditAction(event); }, title: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( DateTimeUtils.displayDateTime(event.time), ), const SizedBox(width: 24), Expanded( child: Text( (event.title ?? event.eventType.target?.value ?? '') .toUpperCase(), style: Theme.of(context).textTheme.subtitle2, ), ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ event.hasEndTime && event.endTime == null ? IconButton( icon: const Icon( Icons.stop, color: Colors.blue, ), onPressed: () => handleStopAction(event), ) : const SizedBox(width: 50), IconButton( icon: const Icon( Icons.edit, color: Colors.blue, ), onPressed: () => handleEditAction(event), ), IconButton( icon: const Icon( Icons.delete, color: Colors.blue, ), onPressed: () => handleDeleteAction(event), ), ], ), ), ); }, ) : const Center( child: Text('There are no Active Events!'), ), const Padding( padding: EdgeInsets.all(10.0), child: Divider(), ), Row( children: [ IconButton( onPressed: _date.isAtSameMomentAs(DateTime(2000, 1, 1)) ? null : () => onChangeDate(_date.subtract(const Duration(days: 1))), icon: const Icon(Icons.arrow_back), ), Expanded( child: GestureDetector( onTap: () async { final newTime = await showDatePicker( context: context, initialDate: _date, firstDate: DateTime(2000, 1, 1), lastDate: DateTime.now().add(const Duration(days: 365)), ); onChangeDate(newTime); }, child: Text( DateTimeUtils.displayDate(_date).toUpperCase(), style: Theme.of(context).textTheme.subtitle2, textAlign: TextAlign.center, ), ), ), IconButton( onPressed: _date .add(const Duration(days: 1)) .isBefore(DateTime.now()) ? () => onChangeDate(_date.add(const Duration(days: 1))) : null, icon: const Icon(Icons.arrow_forward), ), ], ), Expanded( child: _logEvents.isNotEmpty ? Scrollbar( controller: _scrollController, child: ListView.builder( controller: _scrollController, shrinkWrap: true, padding: const EdgeInsets.all(10.0), itemCount: _logEvents.length, itemBuilder: (context, index) { LogEvent event = _logEvents[index]; return Card( child: ListTile( onTap: () { handleEditAction(event); }, title: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( DateTimeUtils.displayTime(event.isEndEvent ? event.endTime : event.time), ), const SizedBox(width: 24), Expanded( child: Text( (event.title ?? event.eventType.target?.value ?? '') .toUpperCase(), style: Theme.of(context).textTheme.subtitle2, ), ), ], ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ event.hasEndTime && event.endTime == null ? IconButton( icon: const Icon( Icons.stop, color: Colors.blue, ), onPressed: () => handleStopAction(event), ) : const SizedBox(width: 50), IconButton( icon: const Icon( Icons.edit, color: Colors.blue, ), onPressed: () => handleEditAction(event), ), IconButton( icon: const Icon( Icons.delete, color: Colors.blue, ), onPressed: () => handleDeleteAction(event), ), ], ), ), ); }, )) : const Center( child: Text('There are no Events for that date!'), ), ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: handleAddNewEvent, child: const Icon(Icons.add), ), ); } }