387 lines
14 KiB
Dart
387 lines
14 KiB
Dart
|
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<LogEventListScreen> {
|
||
|
List<LogEvent> _activeEvents = [];
|
||
|
late List<LogEvent> _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: <Widget>[
|
||
|
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),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|